"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 http_2 = require("./http");
const metadata_cache_1 = require("./metadata-cache");
const schema_1 = require("./schema");
const versions_endpoint_cache_1 = require("./versions-endpoint-cache");
class RubyGemsDatasource extends datasource_1.Datasource {
    static id = 'rubygems';
    metadataCache;
    constructor() {
        super(RubyGemsDatasource.id);
        this.http = new http_2.RubygemsHttp(RubyGemsDatasource.id);
        this.versionsEndpointCache = new versions_endpoint_cache_1.VersionsEndpointCache(this.http);
        this.metadataCache = new metadata_cache_1.MetadataCache(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;
                const result = await this.metadataCache.getRelease(registryUrl, packageName, versions);
                return result;
            }
            const registryHostname = (0, url_1.parseUrl)(registryUrl)?.hostname;
            if (cachedVersions.type === 'not-supported' &&
                registryHostname !== 'rubygems.org') {
                if (registryHostname === 'rubygems.pkg.github.com' ||
                    registryHostname === 'gitlab.com') {
                    return await this.getReleasesViaFallbackAPI(registryUrl, packageName);
                }
                const gemMetadata = await this.fetchGemMetadata(registryUrl, packageName);
                if (!gemMetadata) {
                    return await this.getReleasesViaFallbackAPI(registryUrl, packageName);
                }
                return await this.getReleasesViaAPI(registryUrl, packageName, gemMetadata);
            }
            return null;
        }
        catch (error) {
            this.handleGenericErrors(error);
        }
    }
    async fetchGemMetadata(registryUrl, packageName) {
        try {
            const { body } = await this.http.getJson((0, url_1.joinUrlParts)(registryUrl, '/api/v1/gems', `${packageName}.json`), schema_1.GemMetadata);
            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 getReleasesViaAPI(registryUrl, packageName, gemMetadata) {
        const gemVersions = await this.fetchGemVersions(registryUrl, packageName);
        let releases = null;
        if (gemVersions?.length) {
            releases = gemVersions;
        }
        else if (gemMetadata.latestVersion) {
            releases = [{ version: gemMetadata.latestVersion }];
        }
        else {
            return null;
        }
        const result = { releases };
        if (gemMetadata.changelogUrl) {
            result.changelogUrl = gemMetadata.changelogUrl;
        }
        if (gemMetadata.homepage) {
            result.homepage = gemMetadata.homepage;
        }
        if (gemMetadata.sourceUrl) {
            result.sourceUrl = gemMetadata.sourceUrl;
        }
        return result;
    }
    async getReleasesViaFallbackAPI(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);
    }
}
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 */
        `metadata:${registryUrl}/${packageName}`,
    })
], RubyGemsDatasource.prototype, "fetchGemMetadata", null);
tslib_1.__decorate([
    (0, decorator_1.cache)({
        namespace: `datasource-${RubyGemsDatasource.id}`,
        key: ({ registryUrl, packageName }) => 
        // TODO: types (#7154)
        /* eslint-disable @typescript-eslint/restrict-template-expressions */
        `versions:${registryUrl}/${packageName}`,
    })
], RubyGemsDatasource.prototype, "fetchGemVersions", null);
tslib_1.__decorate([
    (0, decorator_1.cache)({
        namespace: `datasource-${RubyGemsDatasource.id}`,
        key: ({ registryUrl, packageName }) => 
        // TODO: types (#7154)
        /* eslint-disable @typescript-eslint/restrict-template-expressions */
        `dependencies:${registryUrl}/${packageName}`,
    })
], RubyGemsDatasource.prototype, "getReleasesViaFallbackAPI", null);
//# sourceMappingURL=index.js.map