"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InternalRubyGemsDatasource = void 0;
const tslib_1 = require("tslib");
const marshal_1 = require("@qnighy/marshal");
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
const zod_1 = require("zod");
const logger_1 = require("../../../logger");
const http_1 = require("../../../util/http");
const schema_utils_1 = require("../../../util/schema-utils");
const url_1 = require("../../../util/url");
const datasource_1 = require("../datasource");
const MarshalledVersionInfo = (0, schema_utils_1.LooseArray)(zod_1.z
    .object({
    number: zod_1.z.string(),
})
    .transform(({ number: version }) => ({ version })))
    .transform((releases) => (releases.length === 0 ? null : { releases }))
    .nullable()
    .catch(null);
const GemsInfo = zod_1.z
    .object({
    name: zod_1.z.string().transform((x) => x.toLowerCase()),
    version: zod_1.z.string().nullish().catch(null),
    changelog_uri: zod_1.z.string().nullish().catch(null),
    homepage_uri: zod_1.z.string().nullish().catch(null),
    source_code_uri: zod_1.z.string().nullish().catch(null),
})
    .transform(({ name: packageName, version, changelog_uri: changelogUrl, homepage_uri: homepage, source_code_uri: sourceUrl, }) => ({
    packageName,
    version,
    changelogUrl,
    homepage,
    sourceUrl,
}));
const GemVersions = (0, schema_utils_1.LooseArray)(zod_1.z
    .object({
    number: zod_1.z.string(),
    created_at: zod_1.z.string(),
    platform: zod_1.z.string().nullable().catch(null),
    ruby_version: zod_1.z.string().nullable().catch(null),
    rubygems_version: zod_1.z.string().nullable().catch(null),
})
    .transform(({ number: version, created_at: releaseTimestamp, platform, ruby_version: rubyVersion, rubygems_version: rubygemsVersion, }) => {
    const result = { version, releaseTimestamp };
    const constraints = {};
    if (platform) {
        constraints.platform = [platform];
    }
    if (rubyVersion) {
        constraints.ruby = [rubyVersion];
    }
    if (rubygemsVersion) {
        constraints.rubygems = [rubygemsVersion];
    }
    if (!is_1.default.emptyObject(constraints)) {
        result.constraints = constraints;
    }
    return result;
}));
class InternalRubyGemsDatasource extends datasource_1.Datasource {
    id;
    constructor(id) {
        super(id);
        this.id = id;
    }
    async getReleases(config) {
        const registryUrl = config.registryUrl;
        // istanbul ignore if
        if (!registryUrl) {
            return null;
        }
        const packageName = config.packageName.toLowerCase();
        const hostname = (0, url_1.parseUrl)(registryUrl)?.hostname;
        return hostname === 'rubygems.pkg.github.com' || hostname === 'gitlab.com'
            ? await this.getDependencyFallback(registryUrl, packageName)
            : await this.getDependency(registryUrl, packageName);
    }
    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 MarshalledVersionInfo.parse(data);
    }
    async fetchGemsInfo(registryUrl, packageName) {
        try {
            const { body } = await this.http.getJson((0, url_1.joinUrlParts)(registryUrl, '/api/v1/gems', `${packageName}.json`), 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`), 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.InternalRubyGemsDatasource = InternalRubyGemsDatasource;
//# sourceMappingURL=get.js.map