"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.extrasPattern = exports.packagePattern = void 0;
exports.extractPackageFile = extractPackageFile;
const tslib_1 = require("tslib");
const pep440_1 = require("@renovatebot/pep440");
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
const logger_1 = require("../../../logger");
const fs_1 = require("../../../util/fs");
const regex_1 = require("../../../util/regex");
const toml_1 = require("../../../util/toml");
const pypi_1 = require("../../datasource/pypi");
const common_1 = require("../../datasource/pypi/common");
// based on https://www.python.org/dev/peps/pep-0508/#names
exports.packagePattern = '[A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9]';
exports.extrasPattern = '(?:\\s*\\[[^\\]]+\\])*';
const packageRegex = (0, regex_1.regEx)(`^(${exports.packagePattern})(${exports.extrasPattern})$`, 'i');
const rangePattern = pep440_1.RANGE_PATTERN;
const specifierPartPattern = `\\s*${rangePattern.replace((0, regex_1.regEx)(/\?<\w+>/g), '?:')}\\s*`;
const specifierPattern = `${specifierPartPattern}(?:,${specifierPartPattern})*`;
const specifierRegex = (0, regex_1.regEx)(`^${specifierPattern}$`);
function extractFromSection(sectionName, pipfileSection, sources) {
    const deps = Object.entries(pipfileSection)
        .map((x) => {
        const [packageNameString, requirements] = x;
        let depName = packageNameString;
        let currentValue;
        let nestedVersion = false;
        let skipReason;
        if (is_1.default.object(requirements)) {
            if (requirements.git) {
                skipReason = 'git-dependency';
            }
            else if (requirements.file) {
                skipReason = 'file-dependency';
            }
            else if (requirements.path) {
                skipReason = 'local-dependency';
            }
            else if (requirements.version) {
                currentValue = requirements.version;
                nestedVersion = true;
            }
            else {
                skipReason = 'unspecified-version';
            }
        }
        else {
            currentValue = requirements;
        }
        if (currentValue === '*') {
            skipReason = 'unspecified-version';
        }
        if (!skipReason) {
            const packageMatches = packageRegex.exec(packageNameString);
            if (packageMatches) {
                depName = packageMatches[1];
            }
            else {
                logger_1.logger.debug(`Skipping dependency with malformed package name "${packageNameString}".`);
                skipReason = 'invalid-name';
            }
            // validated above
            const specifierMatches = specifierRegex.exec(currentValue);
            if (!specifierMatches) {
                logger_1.logger.debug(`Skipping dependency with malformed version specifier "${currentValue}".`);
                skipReason = 'invalid-version';
            }
        }
        const dep = {
            depType: sectionName,
            depName,
            packageName: (0, common_1.normalizePythonDepName)(depName),
            managerData: {},
        };
        if (currentValue) {
            dep.currentValue = currentValue;
        }
        if (skipReason) {
            dep.skipReason = skipReason;
        }
        else {
            dep.datasource = pypi_1.PypiDatasource.id;
        }
        if (!skipReason && currentValue?.startsWith('==')) {
            dep.currentVersion = currentValue.replace((0, regex_1.regEx)(/^==\s*/), '');
        }
        if (nestedVersion) {
            // TODO #22198
            dep.managerData.nestedVersion = nestedVersion;
        }
        if (sources && is_1.default.object(requirements) && requirements.index) {
            const source = sources.find((item) => item.name === requirements.index);
            if (source) {
                dep.registryUrls = [source.url];
            }
        }
        return dep;
    })
        .filter(Boolean);
    return deps;
}
function isPipRequirements(section) {
    return (!is_1.default.array(section) &&
        is_1.default.object(section) &&
        !Object.values(section).some((dep) => !is_1.default.object(dep) && !is_1.default.string(dep)));
}
async function extractPackageFile(content, packageFile) {
    logger_1.logger.trace(`pipenv.extractPackageFile(${packageFile})`);
    let pipfile;
    try {
        // TODO: fix type (#9610)
        pipfile = (0, toml_1.parse)(content);
    }
    catch (err) {
        logger_1.logger.debug({ err, packageFile }, 'Error parsing Pipfile');
        return null;
    }
    const res = { deps: [] };
    const sources = pipfile?.source;
    if (sources) {
        res.registryUrls = sources.map((source) => source.url);
    }
    let pipenv_constraint;
    res.deps = Object.entries(pipfile)
        .map(([category, section]) => {
        if (category === 'source' ||
            category === 'requires' ||
            !isPipRequirements(section)) {
            return [];
        }
        if (section.pipenv && !pipenv_constraint) {
            pipenv_constraint = section.pipenv;
        }
        return extractFromSection(category, section, sources);
    })
        .flat();
    if (!res.deps.length) {
        return null;
    }
    const extractedConstraints = {};
    if (is_1.default.nonEmptyString(pipfile.requires?.python_version)) {
        extractedConstraints.python = `== ${pipfile.requires.python_version}.*`;
    }
    else if (is_1.default.nonEmptyString(pipfile.requires?.python_full_version)) {
        extractedConstraints.python = `== ${pipfile.requires.python_full_version}`;
    }
    if (pipenv_constraint) {
        extractedConstraints.pipenv = pipenv_constraint;
    }
    const lockFileName = `${packageFile}.lock`;
    if (await (0, fs_1.localPathExists)(lockFileName)) {
        res.lockFiles = [lockFileName];
    }
    res.extractedConstraints = extractedConstraints;
    return res;
}
//# sourceMappingURL=extract.js.map