"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RegistryMeta = exports.PackagistFile = exports.PackagesResponse = exports.RegistryFile = exports.HashSpec = exports.parsePackagesResponses = exports.extractDepReleases = exports.extractReleaseResult = exports.parsePackagesResponse = exports.ComposerPackagesResponse = exports.ComposerReleases = exports.ComposerRelease = exports.MinifiedArray = void 0;
const tslib_1 = require("tslib");
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
const zod_1 = require("zod");
const logger_1 = require("../../../logger");
const schema_1 = require("../../../util/schema");
exports.MinifiedArray = zod_1.z.array(zod_1.z.record(zod_1.z.unknown())).transform((xs) => {
    // Ported from: https://github.com/composer/metadata-minifier/blob/main/src/MetadataMinifier.php#L17
    if (xs.length === 0) {
        return xs;
    }
    const prevVals = {};
    for (const x of xs) {
        for (const key of Object.keys(x)) {
            prevVals[key] ?? (prevVals[key] = undefined);
        }
        for (const key of Object.keys(prevVals)) {
            const val = x[key];
            if (val === '__unset') {
                delete x[key];
                prevVals[key] = undefined;
                continue;
            }
            if (!is_1.default.undefined(val)) {
                prevVals[key] = val;
                continue;
            }
            if (!is_1.default.undefined(prevVals[key])) {
                x[key] = prevVals[key];
                continue;
            }
        }
    }
    return xs;
});
exports.ComposerRelease = zod_1.z
    .object({
    version: zod_1.z.string(),
})
    .merge((0, schema_1.looseObject)({
    homepage: zod_1.z.string(),
    source: zod_1.z.object({ url: zod_1.z.string() }),
    time: zod_1.z.string(),
    require: zod_1.z.object({ php: zod_1.z.string() }),
}));
const ComposerReleasesLooseArray = (0, schema_1.looseArray)(exports.ComposerRelease);
exports.ComposerReleases = zod_1.z
    .union([
    exports.MinifiedArray.transform((xs) => ComposerReleasesLooseArray.parse(xs)),
    (0, schema_1.looseRecord)(exports.ComposerRelease).transform((map) => Object.values(map)),
])
    .catch([]);
exports.ComposerPackagesResponse = zod_1.z
    .object({
    packageName: zod_1.z.string(),
    packagesResponse: zod_1.z.object({
        packages: zod_1.z.record(zod_1.z.unknown()),
    }),
})
    .transform(({ packageName, packagesResponse }) => packagesResponse.packages[packageName])
    .transform((xs) => exports.ComposerReleases.parse(xs));
function parsePackagesResponse(packageName, packagesResponse) {
    try {
        return exports.ComposerPackagesResponse.parse({ packageName, packagesResponse });
    }
    catch (err) {
        logger_1.logger.debug({ packageName, err }, `Error parsing packagist response for ${packageName}`);
        return [];
    }
}
exports.parsePackagesResponse = parsePackagesResponse;
function extractReleaseResult(...composerReleasesArrays) {
    const releases = [];
    let homepage;
    let sourceUrl;
    for (const composerReleasesArray of composerReleasesArrays) {
        for (const composerRelease of composerReleasesArray) {
            const version = composerRelease.version.replace(/^v/, '');
            const gitRef = composerRelease.version;
            const dep = { version, gitRef };
            if (composerRelease.time) {
                dep.releaseTimestamp = composerRelease.time;
            }
            if (composerRelease.require?.php) {
                dep.constraints = { php: [composerRelease.require.php] };
            }
            releases.push(dep);
            if (!homepage && composerRelease.homepage) {
                homepage = composerRelease.homepage;
            }
            if (!sourceUrl && composerRelease.source?.url) {
                sourceUrl = composerRelease.source.url;
            }
        }
    }
    if (releases.length === 0) {
        return null;
    }
    const result = { releases };
    if (homepage) {
        result.homepage = homepage;
    }
    if (sourceUrl) {
        result.sourceUrl = sourceUrl;
    }
    return result;
}
exports.extractReleaseResult = extractReleaseResult;
function extractDepReleases(composerReleases) {
    const parsedReleases = exports.ComposerReleases.parse(composerReleases);
    return extractReleaseResult(parsedReleases);
}
exports.extractDepReleases = extractDepReleases;
function parsePackagesResponses(packageName, packagesResponses) {
    const releaseArrays = packagesResponses.map((pkgResp) => parsePackagesResponse(packageName, pkgResp));
    return extractReleaseResult(...releaseArrays);
}
exports.parsePackagesResponses = parsePackagesResponses;
exports.HashSpec = zod_1.z.union([
    zod_1.z
        .object({ sha256: zod_1.z.string().nullable() })
        .transform(({ sha256 }) => ({ hash: sha256 })),
    zod_1.z
        .object({ sha1: zod_1.z.string().nullable() })
        .transform(({ sha1 }) => ({ hash: sha1 })),
]);
exports.RegistryFile = zod_1.z.intersection(exports.HashSpec, zod_1.z.object({ key: zod_1.z.string() }));
exports.PackagesResponse = zod_1.z.object({
    packages: (0, schema_1.looseRecord)(exports.ComposerReleases),
});
exports.PackagistFile = exports.PackagesResponse.merge(zod_1.z.object({
    providers: (0, schema_1.looseRecord)(exports.HashSpec).transform((x) => Object.fromEntries(Object.entries(x).map(([key, { hash }]) => [key, hash]))),
}));
exports.RegistryMeta = zod_1.z
    .preprocess((x) => (is_1.default.plainObject(x) ? x : {}), exports.PackagistFile.merge(zod_1.z.object({
    ['includes']: (0, schema_1.looseRecord)(exports.HashSpec).transform((x) => Object.entries(x).map(([name, { hash }]) => ({ key: name, hash }))),
    ['provider-includes']: (0, schema_1.looseRecord)(exports.HashSpec).transform((x) => Object.entries(x).map(([key, { hash }]) => ({ key, hash }))),
    ['providers-lazy-url']: (0, schema_1.looseValue)(zod_1.z.string()),
    ['providers-url']: (0, schema_1.looseValue)(zod_1.z.string()),
    ['metadata-url']: (0, schema_1.looseValue)(zod_1.z.string()),
})))
    .transform(({ ['includes']: includesFiles, ['packages']: packages, ['provider-includes']: files, ['providers']: providerPackages, ['providers-lazy-url']: providersLazyUrl, ['providers-url']: providersUrl, ['metadata-url']: metadataUrl, }) => ({
    packages,
    includesFiles,
    providerPackages,
    files,
    providersUrl,
    providersLazyUrl,
    metadataUrl,
    includesPackages: {},
}));
//# sourceMappingURL=schema.js.map