"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RegistryResponseError = exports.NoMatchingVersionError = void 0;
const error_1 = __importDefault(require("@pnpm/error"));
const resolve_workspace_range_1 = __importDefault(require("@pnpm/resolve-workspace-range"));
const createNpmPkgId_1 = __importDefault(require("./createNpmPkgId"));
const fetch_1 = __importStar(require("./fetch"));
Object.defineProperty(exports, "RegistryResponseError", { enumerable: true, get: function () { return fetch_1.RegistryResponseError; } });
const parsePref_1 = __importDefault(require("./parsePref"));
const pickPackage_1 = __importDefault(require("./pickPackage"));
const path = require("path");
const LRU = require("lru-cache");
const normalize = require("normalize-path");
const pMemoize = require("p-memoize");
const semver = require("semver");
const ssri = require("ssri");
class NoMatchingVersionError extends error_1.default {
    constructor(opts) {
        var _a;
        const dep = opts.wantedDependency.alias
            ? `${opts.wantedDependency.alias}@${(_a = opts.wantedDependency.pref) !== null && _a !== void 0 ? _a : ''}`
            : opts.wantedDependency.pref;
        super('NO_MATCHING_VERSION', `No matching version found for ${dep}`);
        this.packageMeta = opts.packageMeta;
    }
}
exports.NoMatchingVersionError = NoMatchingVersionError;
// This file contains meta information
// about all the packages published by the same name, not just the manifest
// of one package/version
const META_DIR = 'metadata';
const FULL_META_DIR = 'metadata-full';
function createResolver(fetchFromRegistry, getCredentials, opts) {
    var _a;
    if (typeof opts.storeDir !== 'string') { // eslint-disable-line
        throw new TypeError('`opts.storeDir` is required and needs to be a string');
    }
    const fetch = pMemoize(fetch_1.default.bind(null, fetchFromRegistry, (_a = opts.retry) !== null && _a !== void 0 ? _a : {}), {
        cacheKey: (...args) => JSON.stringify(args),
        maxAge: 1000 * 20,
    });
    const getAuthHeaderValueByURI = (registry) => getCredentials(registry).authHeaderValue;
    const metaCache = new LRU({
        max: 10000,
        maxAge: 120 * 1000,
    }); // eslint-disable-line @typescript-eslint/no-explicit-any
    return resolveNpm.bind(null, {
        getAuthHeaderValueByURI,
        pickPackage: pickPackage_1.default.bind(null, {
            fetch,
            metaCache,
            metaDir: opts.fullMetadata ? FULL_META_DIR : META_DIR,
            offline: opts.offline,
            preferOffline: opts.preferOffline,
            storeDir: opts.storeDir,
        }),
    });
}
exports.default = createResolver;
async function resolveNpm(ctx, wantedDependency, opts) {
    var _a, _b, _c;
    const defaultTag = (_a = opts.defaultTag) !== null && _a !== void 0 ? _a : 'latest';
    if ((_b = wantedDependency.pref) === null || _b === void 0 ? void 0 : _b.startsWith('workspace:')) {
        if (wantedDependency.pref.startsWith('workspace:.'))
            return null;
        const resolvedFromWorkspace = tryResolveFromWorkspace(wantedDependency, {
            defaultTag,
            projectDir: opts.projectDir,
            registry: opts.registry,
            workspacePackages: opts.workspacePackages,
        });
        if (resolvedFromWorkspace) {
            return resolvedFromWorkspace;
        }
    }
    const workspacePackages = opts.alwaysTryWorkspacePackages !== false ? opts.workspacePackages : undefined;
    const spec = wantedDependency.pref
        ? parsePref_1.default(wantedDependency.pref, wantedDependency.alias, defaultTag, opts.registry)
        : defaultTagForAlias(wantedDependency.alias, defaultTag);
    if (!spec)
        return null;
    const authHeaderValue = ctx.getAuthHeaderValueByURI(opts.registry);
    let pickResult;
    try {
        pickResult = await ctx.pickPackage(spec, {
            authHeaderValue,
            dryRun: opts.dryRun === true,
            preferredVersionSelectors: (_c = opts.preferredVersions) === null || _c === void 0 ? void 0 : _c[spec.name],
            registry: opts.registry,
        });
    }
    catch (err) {
        if (workspacePackages && opts.projectDir) {
            const resolvedFromLocal = tryResolveFromWorkspacePackages(workspacePackages, spec, opts.projectDir);
            if (resolvedFromLocal)
                return resolvedFromLocal;
        }
        throw err;
    }
    const pickedPackage = pickResult.pickedPackage;
    const meta = pickResult.meta;
    if (!pickedPackage) {
        if (workspacePackages && opts.projectDir) {
            const resolvedFromLocal = tryResolveFromWorkspacePackages(workspacePackages, spec, opts.projectDir);
            if (resolvedFromLocal)
                return resolvedFromLocal;
        }
        throw new NoMatchingVersionError({ wantedDependency, packageMeta: meta });
    }
    if ((workspacePackages === null || workspacePackages === void 0 ? void 0 : workspacePackages[pickedPackage.name]) && opts.projectDir) {
        if (workspacePackages[pickedPackage.name][pickedPackage.version]) {
            return {
                ...resolveFromLocalPackage(workspacePackages[pickedPackage.name][pickedPackage.version], spec.normalizedPref, opts.projectDir),
                latest: meta['dist-tags'].latest,
            };
        }
        const localVersion = pickMatchingLocalVersionOrNull(workspacePackages[pickedPackage.name], spec);
        if (localVersion && (semver.gt(localVersion, pickedPackage.version) || opts.preferWorkspacePackages)) {
            return {
                ...resolveFromLocalPackage(workspacePackages[pickedPackage.name][localVersion], spec.normalizedPref, opts.projectDir),
                latest: meta['dist-tags'].latest,
            };
        }
    }
    const id = createNpmPkgId_1.default(pickedPackage.dist.tarball, pickedPackage.name, pickedPackage.version);
    const resolution = {
        integrity: getIntegrity(pickedPackage.dist),
        registry: opts.registry,
        tarball: pickedPackage.dist.tarball,
    };
    return {
        id,
        latest: meta['dist-tags'].latest,
        manifest: pickedPackage,
        normalizedPref: spec.normalizedPref,
        resolution,
        resolvedVia: 'npm-registry',
    };
}
function tryResolveFromWorkspace(wantedDependency, opts) {
    var _a, _b;
    if (!((_a = wantedDependency.pref) === null || _a === void 0 ? void 0 : _a.startsWith('workspace:'))) {
        return null;
    }
    let pref = wantedDependency.pref.substr(10);
    if (pref.includes('@', 1)) {
        pref = `npm:${pref}`;
    }
    const spec = parsePref_1.default(pref, wantedDependency.alias, opts.defaultTag, opts.registry);
    if (!spec)
        throw new Error(`Invalid workspace: spec (${wantedDependency.pref})`);
    if (!opts.workspacePackages) {
        throw new Error('Cannot resolve package from workspace because opts.workspacePackages is not defined');
    }
    if (!opts.projectDir) {
        throw new Error('Cannot resolve package from workspace because opts.projectDir is not defined');
    }
    const resolvedFromLocal = tryResolveFromWorkspacePackages(opts.workspacePackages, spec, opts.projectDir);
    if (!resolvedFromLocal) {
        throw new error_1.default('NO_MATCHING_VERSION_INSIDE_WORKSPACE', `In ${path.relative(process.cwd(), opts.projectDir)}: No matching version found for ${(_b = wantedDependency.alias) !== null && _b !== void 0 ? _b : ''}@${pref} inside the workspace`);
    }
    return resolvedFromLocal;
}
function tryResolveFromWorkspacePackages(workspacePackages, spec, projectDir) {
    if (!workspacePackages[spec.name])
        return null;
    const localVersion = pickMatchingLocalVersionOrNull(workspacePackages[spec.name], spec);
    if (!localVersion)
        return null;
    return resolveFromLocalPackage(workspacePackages[spec.name][localVersion], spec.normalizedPref, projectDir);
}
function pickMatchingLocalVersionOrNull(versions, spec) {
    const localVersions = Object.keys(versions);
    switch (spec.type) {
        case 'tag':
            return semver.maxSatisfying(localVersions, '*');
        case 'version':
            return versions[spec.fetchSpec] ? spec.fetchSpec : null;
        case 'range':
            return resolve_workspace_range_1.default(spec.fetchSpec, localVersions);
        default:
            return null;
    }
}
function resolveFromLocalPackage(localPackage, normalizedPref, projectDir) {
    return {
        id: `link:${normalize(path.relative(projectDir, localPackage.dir))}`,
        manifest: localPackage.manifest,
        normalizedPref,
        resolution: {
            directory: localPackage.dir,
            type: 'directory',
        },
        resolvedVia: 'local-filesystem',
    };
}
function defaultTagForAlias(alias, defaultTag) {
    return {
        fetchSpec: defaultTag,
        name: alias,
        type: 'tag',
    };
}
function getIntegrity(dist) {
    if (dist.integrity) {
        return dist.integrity;
    }
    return ssri.fromHex(dist.shasum, 'sha1').toString();
}
//# sourceMappingURL=index.js.map