"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RubyGemsDatasource = void 0;
const tslib_1 = require("tslib");
const marshal_1 = require("@qnighy/marshal");
const logger_1 = require("../../../logger");
const decorator_1 = require("../../../util/cache/package/decorator");
const http_1 = require("../../../util/http");
const url_1 = require("../../../util/url");
const rubyVersioning = tslib_1.__importStar(require("../../versioning/ruby"));
const datasource_1 = require("../datasource");
const schema_1 = require("./schema");
const versions_endpoint_cache_1 = require("./versions-endpoint-cache");
class RubyGemsDatasource extends datasource_1.Datasource {
    static id = 'rubygems';
    constructor() {
        super(RubyGemsDatasource.id);
        this.versionsEndpointCache = new versions_endpoint_cache_1.VersionsEndpointCache(this.http);
    }
    defaultRegistryUrls = ['https://rubygems.org'];
    defaultVersioning = rubyVersioning.id;
    registryStrategy = 'hunt';
    versionsEndpointCache;
    async getReleases({ packageName, registryUrl, }) {
        // istanbul ignore if
        if (!registryUrl) {
            return null;
        }
        try {
            const cachedVersions = await this.versionsEndpointCache.getVersions(registryUrl, packageName);
            if (cachedVersions.type === 'success') {
                const { versions } = cachedVersions;
                return { releases: versions.map((version) => ({ version })) };
            }
            const registryHostname = (0, url_1.parseUrl)(registryUrl)?.hostname;
            if (cachedVersions.type === 'not-supported' &&
                registryHostname !== 'rubygems.org') {
                const hostname = registryHostname;
                return hostname === 'rubygems.pkg.github.com' ||
                    hostname === 'gitlab.com'
                    ? await this.getDependencyFallback(registryUrl, packageName)
                    : await this.getDependency(registryUrl, packageName);
            }
        }
        catch (error) {
            this.handleGenericErrors(error);
        }
        return null;
    }
    async getDependencyFallback(registryUrl, packageName) {
        const path = (0, url_1.joinUrlParts)(registryUrl, `/api/v1/dependencies`);
        const query = (0, url_1.getQueryString)({ gems: packageName });
        const url = `${path}?${query}`;
        const { body: buffer } = await this.http.getBuffer(url);
        const data = marshal_1.Marshal.parse(buffer);
        return schema_1.MarshalledVersionInfo.parse(data);
    }
    async fetchGemsInfo(registryUrl, packageName) {
        try {
            const { body } = await this.http.getJson((0, url_1.joinUrlParts)(registryUrl, '/api/v1/gems', `${packageName}.json`), schema_1.GemsInfo);
            return body;
        }
        catch (err) {
            // fallback to deps api on 404
            if (err instanceof http_1.HttpError && err.response?.statusCode === 404) {
                return null;
            }
            throw err;
        }
    }
    async fetchGemVersions(registryUrl, packageName) {
        try {
            const { body } = await this.http.getJson((0, url_1.joinUrlParts)(registryUrl, '/api/v1/versions', `${packageName}.json`), schema_1.GemVersions);
            return body;
        }
        catch (err) {
            if (err.statusCode === 400 || err.statusCode === 404) {
                logger_1.logger.debug({ registry: registryUrl }, 'versions endpoint returns error - falling back to info endpoint');
                return null;
            }
            else {
                throw err;
            }
        }
    }
    async getDependency(registryUrl, packageName) {
        const info = await this.fetchGemsInfo(registryUrl, packageName);
        if (!info) {
            return await this.getDependencyFallback(registryUrl, packageName);
        }
        if (info.packageName !== packageName) {
            logger_1.logger.warn({ lookup: packageName, returned: info.packageName }, 'Lookup name does not match the returned name.');
            return null;
        }
        let releases = null;
        const gemVersions = await this.fetchGemVersions(registryUrl, packageName);
        if (gemVersions?.length) {
            releases = gemVersions;
        }
        else if (info.version) {
            releases = [{ version: info.version }];
        }
        if (!releases) {
            return null;
        }
        const result = { releases };
        if (info.changelogUrl) {
            result.changelogUrl = info.changelogUrl;
        }
        if (info.homepage) {
            result.homepage = info.homepage;
        }
        if (info.sourceUrl) {
            result.sourceUrl = info.sourceUrl;
        }
        return result;
    }
}
exports.RubyGemsDatasource = RubyGemsDatasource;
tslib_1.__decorate([
    (0, decorator_1.cache)({
        namespace: `datasource-${RubyGemsDatasource.id}`,
        key: ({ registryUrl, packageName }) => 
        // TODO: types (#7154)
        /* eslint-disable @typescript-eslint/restrict-template-expressions */
        `${registryUrl}/${packageName}`,
    })
], RubyGemsDatasource.prototype, "getReleases", null);
//# sourceMappingURL=index.js.map