"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Lockfile = exports.PoetrySchemaToml = exports.PoetrySchema = exports.PoetrySectionSchema = exports.PoetrySources = exports.PoetrySource = exports.PoetryGroupDependencies = exports.PoetryDependencies = void 0;
const tslib_1 = require("tslib");
const zod_1 = require("zod");
const logger_1 = require("../../../logger");
const url_1 = require("../../../util/git/url");
const regex_1 = require("../../../util/regex");
const schema_utils_1 = require("../../../util/schema-utils");
const uniq_1 = require("../../../util/uniq");
const git_refs_1 = require("../../datasource/git-refs");
const git_tags_1 = require("../../datasource/git-tags");
const github_tags_1 = require("../../datasource/github-tags");
const gitlab_tags_1 = require("../../datasource/gitlab-tags");
const pypi_1 = require("../../datasource/pypi");
const gitVersioning = tslib_1.__importStar(require("../../versioning/git"));
const pep440Versioning = tslib_1.__importStar(require("../../versioning/pep440"));
const poetryVersioning = tslib_1.__importStar(require("../../versioning/poetry"));
const extract_1 = require("../pip_requirements/extract");
const PoetryPathDependency = zod_1.z
    .object({
    path: zod_1.z.string(),
    version: zod_1.z.string().optional().catch(undefined),
})
    .transform(({ version }) => {
    const dep = {
        datasource: pypi_1.PypiDatasource.id,
        skipReason: 'path-dependency',
    };
    if (version) {
        dep.currentValue = version;
    }
    return dep;
});
const PoetryGitDependency = zod_1.z
    .object({
    git: zod_1.z.string(),
    tag: zod_1.z.string().optional().catch(undefined),
    version: zod_1.z.string().optional().catch(undefined),
    branch: zod_1.z.string().optional().catch(undefined),
    rev: zod_1.z.string().optional().catch(undefined),
})
    .transform(({ git, tag, version, branch, rev }) => {
    if (tag) {
        const { source, owner, name } = (0, url_1.parseGitUrl)(git);
        const repo = `${owner}/${name}`;
        if (source === 'github.com') {
            return {
                datasource: github_tags_1.GithubTagsDatasource.id,
                currentValue: tag,
                packageName: repo,
            };
        }
        else if (source === 'gitlab.com') {
            return {
                datasource: gitlab_tags_1.GitlabTagsDatasource.id,
                currentValue: tag,
                packageName: repo,
            };
        }
        else {
            return {
                datasource: git_tags_1.GitTagsDatasource.id,
                currentValue: tag,
                packageName: git,
            };
        }
    }
    if (rev) {
        return {
            datasource: git_refs_1.GitRefsDatasource.id,
            currentValue: branch,
            currentDigest: rev,
            replaceString: rev,
            packageName: git,
        };
    }
    return {
        datasource: git_refs_1.GitRefsDatasource.id,
        currentValue: version,
        packageName: git,
        skipReason: 'git-dependency',
    };
});
const PoetryPypiDependency = zod_1.z.union([
    zod_1.z
        .object({ version: zod_1.z.string().optional(), source: zod_1.z.string().optional() })
        .transform(({ version: currentValue, source }) => {
        if (!currentValue) {
            return { datasource: pypi_1.PypiDatasource.id };
        }
        return {
            datasource: pypi_1.PypiDatasource.id,
            managerData: { nestedVersion: true, sourceName: source?.toLowerCase() },
            currentValue,
        };
    }),
    zod_1.z.string().transform((version) => ({
        datasource: pypi_1.PypiDatasource.id,
        currentValue: version,
        managerData: { nestedVersion: false },
    })),
]);
const PoetryArrayDependency = zod_1.z.array(zod_1.z.unknown()).transform(() => ({
    datasource: pypi_1.PypiDatasource.id,
    skipReason: 'multiple-constraint-dep',
}));
const PoetryDependency = zod_1.z.union([
    PoetryPathDependency,
    PoetryGitDependency,
    PoetryPypiDependency,
    PoetryArrayDependency,
]);
exports.PoetryDependencies = (0, schema_utils_1.LooseRecord)(zod_1.z.string(), PoetryDependency.transform((dep) => {
    if (dep.skipReason) {
        return dep;
    }
    if (dep.datasource === git_refs_1.GitRefsDatasource.id && dep.currentDigest) {
        dep.versioning = gitVersioning.id;
        return dep;
    }
    // istanbul ignore if: normaly should not happen
    if (!dep.currentValue) {
        dep.skipReason = 'unspecified-version';
        return dep;
    }
    if (pep440Versioning.isValid(dep.currentValue)) {
        dep.versioning = pep440Versioning.id;
        return dep;
    }
    if (poetryVersioning.isValid(dep.currentValue)) {
        dep.versioning = poetryVersioning.id;
        return dep;
    }
    dep.skipReason = 'invalid-version';
    return dep;
})).transform((record) => {
    const deps = [];
    for (const [depName, dep] of Object.entries(record)) {
        dep.depName = depName;
        if (!dep.packageName) {
            const pep503NormalizeRegex = (0, regex_1.regEx)(/[-_.]+/g);
            const packageName = depName
                .toLowerCase()
                .replace(pep503NormalizeRegex, '-');
            if (depName !== packageName) {
                dep.packageName = packageName;
            }
        }
        deps.push(dep);
    }
    return deps;
});
function withDepType(schema, depType) {
    return schema.transform((deps) => {
        for (const dep of deps) {
            dep.depType = depType;
        }
        return deps;
    });
}
exports.PoetryGroupDependencies = (0, schema_utils_1.LooseRecord)(zod_1.z.string(), zod_1.z
    .object({ dependencies: exports.PoetryDependencies })
    .transform(({ dependencies }) => dependencies)).transform((record) => {
    const deps = [];
    for (const [groupName, group] of Object.entries(record)) {
        for (const dep of Object.values(group)) {
            dep.depType = groupName;
            deps.push(dep);
        }
    }
    return deps;
});
const PoetrySourceOrder = [
    'default',
    'primary',
    'secondary',
    'supplemental',
    'explicit',
];
exports.PoetrySource = zod_1.z.object({
    name: zod_1.z.string().toLowerCase(),
    url: zod_1.z.string().optional(),
    priority: zod_1.z.enum(PoetrySourceOrder).default('primary'),
});
exports.PoetrySources = (0, schema_utils_1.LooseArray)(exports.PoetrySource, {
    onError: ({ error: err }) => {
        logger_1.logger.debug({ err }, 'Poetry: error parsing sources array');
    },
})
    .transform((sources) => {
    const pypiUrl = process.env.PIP_INDEX_URL ?? 'https://pypi.org/pypi/';
    const result = [];
    let overridesPyPi = false;
    let hasDefaultSource = false;
    let hasPrimarySource = false;
    for (const source of sources) {
        if (source.name === 'pypi') {
            source.url = pypiUrl;
            overridesPyPi = true;
        }
        if (!source.url) {
            continue;
        }
        if (source.priority === 'default') {
            hasDefaultSource = true;
        }
        else if (source.priority === 'primary') {
            hasPrimarySource = true;
        }
        result.push(source);
    }
    if (sources.length && !hasDefaultSource && !overridesPyPi) {
        result.push({
            name: 'pypi',
            priority: hasPrimarySource ? 'secondary' : 'default',
            url: pypiUrl,
        });
    }
    result.sort((a, b) => PoetrySourceOrder.indexOf(a.priority) -
        PoetrySourceOrder.indexOf(b.priority));
    return result;
})
    .catch([]);
exports.PoetrySectionSchema = zod_1.z
    .object({
    version: zod_1.z.string().optional().catch(undefined),
    dependencies: withDepType(exports.PoetryDependencies, 'dependencies').optional(),
    'dev-dependencies': withDepType(exports.PoetryDependencies, 'dev-dependencies').optional(),
    extras: withDepType(exports.PoetryDependencies, 'extras').optional(),
    group: exports.PoetryGroupDependencies.optional(),
    source: exports.PoetrySources,
})
    .transform(({ version, dependencies = [], 'dev-dependencies': devDependencies = [], extras: extraDependencies = [], group: groupDependencies = [], source: sourceUrls, }) => {
    const deps = [
        ...dependencies,
        ...devDependencies,
        ...extraDependencies,
        ...groupDependencies,
    ];
    const res = { deps, packageFileVersion: version };
    if (sourceUrls.length) {
        for (const dep of res.deps) {
            if (dep.managerData?.sourceName) {
                const sourceUrl = sourceUrls.find(({ name }) => name === dep.managerData?.sourceName);
                if (sourceUrl?.url) {
                    dep.registryUrls = [sourceUrl.url];
                }
            }
        }
        const sourceUrlsFiltered = sourceUrls.filter(({ priority }) => priority !== 'explicit');
        res.registryUrls = (0, uniq_1.uniq)(sourceUrlsFiltered.map(({ url }) => url));
    }
    return res;
});
const BuildSystemRequireVal = zod_1.z
    .string()
    .nonempty()
    .transform((val) => (0, regex_1.regEx)(`^${extract_1.dependencyPattern}$`).exec(val))
    .transform((match, ctx) => {
    if (!match) {
        ctx.addIssue({
            code: zod_1.z.ZodIssueCode.custom,
            message: 'invalid requirement',
        });
        return zod_1.z.NEVER;
    }
    const [, depName, , poetryRequirement] = match;
    return { depName, poetryRequirement };
});
exports.PoetrySchema = zod_1.z
    .object({
    tool: zod_1.z
        .object({ poetry: exports.PoetrySectionSchema })
        .transform(({ poetry }) => poetry),
    'build-system': zod_1.z
        .object({
        'build-backend': zod_1.z.string().refine(
        // https://python-poetry.org/docs/pyproject/#poetry-and-pep-517
        (buildBackend) => buildBackend === 'poetry.masonry.api' ||
            buildBackend === 'poetry.core.masonry.api'),
        requires: (0, schema_utils_1.LooseArray)(BuildSystemRequireVal).transform((vals) => {
            const req = vals.find(({ depName }) => depName === 'poetry' || depName === 'poetry_core');
            return req?.poetryRequirement;
        }),
    })
        .transform(({ requires: poetryRequirement }) => poetryRequirement)
        .optional()
        .catch(undefined),
})
    .transform(({ tool: packageFileContent, 'build-system': poetryRequirement }) => ({
    packageFileContent,
    poetryRequirement,
}));
exports.PoetrySchemaToml = schema_utils_1.Toml.pipe(exports.PoetrySchema);
const poetryConstraint = {
    '1.0': '<1.1.0',
    '1.1': '<1.3.0',
    '2.0': '>=1.3.0',
};
exports.Lockfile = schema_utils_1.Toml.pipe(zod_1.z.object({
    package: (0, schema_utils_1.LooseArray)(zod_1.z
        .object({
        name: zod_1.z.string(),
        version: zod_1.z.string(),
    })
        .transform(({ name, version }) => [name, version]))
        .transform((entries) => Object.fromEntries(entries))
        .catch({}),
    metadata: zod_1.z
        .object({
        'lock-version': zod_1.z
            .string()
            .transform((lockVersion) => poetryConstraint[lockVersion])
            .optional()
            .catch(undefined),
        'python-versions': zod_1.z.string().optional().catch(undefined),
    })
        .transform(({ 'lock-version': poetryConstraint, 'python-versions': pythonVersions, }) => ({
        poetryConstraint,
        pythonVersions,
    }))
        .catch({
        poetryConstraint: undefined,
        pythonVersions: undefined,
    }),
})).transform(({ package: lock, metadata: { poetryConstraint, pythonVersions } }) => ({
    lock,
    poetryConstraint,
    pythonVersions,
}));
//# sourceMappingURL=schema.js.map