UNPKG

npm-check-updates

Version:

Find newer versions of dependencies than what your package.json allows

688 lines 31.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (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.semver = exports.patch = exports.minor = exports.newest = exports.latest = exports.distTag = exports.list = exports.getPeerDependencies = exports.greatest = exports.defaultPrefix = exports.viewOne = exports.viewManyMemoized = exports.mockViewMany = exports.packageAuthorChanged = exports.normalizeNpmConfig = void 0; const fast_memoize_1 = __importDefault(require("fast-memoize")); const fs_1 = __importDefault(require("fs")); const ini_1 = __importDefault(require("ini")); const camelCase_1 = __importDefault(require("lodash/camelCase")); const filter_1 = __importDefault(require("lodash/filter")); const get_1 = __importDefault(require("lodash/get")); const isEqual_1 = __importDefault(require("lodash/isEqual")); const last_1 = __importDefault(require("lodash/last")); const omit_1 = __importDefault(require("lodash/omit")); const sortBy_1 = __importDefault(require("lodash/sortBy")); const pacote_1 = __importDefault(require("pacote")); const path_1 = __importDefault(require("path")); const semver_1 = __importDefault(require("semver")); const semver_utils_1 = require("semver-utils"); const spawn_please_1 = __importDefault(require("spawn-please")); const untildify_1 = __importDefault(require("untildify")); const filterObject_1 = __importDefault(require("../lib/filterObject")); const keyValueBy_1 = require("../lib/keyValueBy"); const libnpmconfig_1 = __importDefault(require("../lib/libnpmconfig")); const logging_1 = require("../lib/logging"); const versionUtil = __importStar(require("../lib/version-util")); const filters_1 = require("./filters"); const EXPLICIT_RANGE_OPS = new Set(['-', '||', '&&', '<', '<=', '>', '>=']); /** Returns true if the spec is an explicit version range (not ~ or ^). */ const isExplicitRange = (spec) => { const range = (0, semver_utils_1.parseRange)(spec); return range.some(parsed => EXPLICIT_RANGE_OPS.has(parsed.operator || '')); }; /** Returns true if the version is sa valid, exact version. */ const isExactVersion = (version) => version && (!semver_1.default.validRange(version) || versionUtil.isWildCard(version)); /** Normalizes the keys of an npm config for pacote. */ const normalizeNpmConfig = (npmConfig, // config path used to determine relative cafile paths configPath) => { const npmConfigToPacoteMap = { cafile: (capath) => { // load-cafile, based on github.com/npm/cli/blob/40c1b0f/lib/config/load-cafile.js if (!capath) return; // synchronous since it is loaded once on startup, and to avoid complexity in libnpmconfig.read // https://github.com/raineorshine/npm-check-updates/issues/636?notification_referrer_id=MDE4Ok5vdGlmaWNhdGlvblRocmVhZDc0Njk2NjAzMjo3NTAyNzY%3D const cadata = fs_1.default.readFileSync(path_1.default.resolve(configPath || '', (0, untildify_1.default)(capath)), 'utf8'); const delim = '-----END CERTIFICATE-----'; const output = cadata .split(delim) .filter(xs => !!xs.trim()) .map(xs => `${xs.trimStart()}${delim}`); return { ca: output }; }, maxsockets: 'maxSockets', 'strict-ssl': 'strictSSL', }; // all config variables are read in as strings, so we need to type coerce non-strings // lowercased and hyphens removed for comparison purposes const keyTypes = { all: 'boolean', allowsameversion: 'boolean', audit: 'boolean', binlinks: 'boolean', color: 'boolean', commithooks: 'boolean', description: 'boolean', dev: 'boolean', diffignoreallspace: 'boolean', diffnameonly: 'boolean', diffnoprefix: 'boolean', difftext: 'boolean', dryrun: 'boolean', enginestrict: 'boolean', force: 'boolean', foregroundscripts: 'boolean', formatpackagelock: 'boolean', fund: 'boolean', gittagversion: 'boolean', global: 'boolean', globalstyle: 'boolean', ifpresent: 'boolean', ignorescripts: 'boolean', includestaged: 'boolean', includeworkspaceroot: 'boolean', installlinks: 'boolean', json: 'boolean', legacybundling: 'boolean', legacypeerdeps: 'boolean', link: 'boolean', long: 'boolean', offline: 'boolean', omitlockfileregistryresolved: 'boolean', packagelock: 'boolean', packagelockonly: 'boolean', parseable: 'boolean', preferoffline: 'boolean', preferonline: 'boolean', progress: 'boolean', readonly: 'boolean', rebuildbundle: 'boolean', save: 'boolean', savebundle: 'boolean', savedev: 'boolean', saveexact: 'boolean', saveoptional: 'boolean', savepeer: 'boolean', saveprod: 'boolean', shrinkwrap: 'boolean', signgitcommit: 'boolean', signgittag: 'boolean', strictpeerdeps: 'boolean', strictssl: 'boolean', timing: 'boolean', unicode: 'boolean', updatenotifier: 'boolean', usage: 'boolean', version: 'boolean', versions: 'boolean', workspacesupdate: 'boolean', diffunified: 'number', fetchretries: 'number', fetchretryfactor: 'number', fetchretrymaxtimeout: 'number', fetchretrymintimeout: 'number', fetchtimeout: 'number', logsmax: 'number', maxsockets: 'number', searchlimit: 'number', searchstaleness: 'number', ssopollfrequency: 'number', timeout: 'number', }; /** Parses a string to a boolean. */ const stringToBoolean = (s) => !!s && s !== 'false' && s !== '0'; /** Parses a string to a number. */ const stringToNumber = (s) => parseInt(s) || 0; // needed until pacote supports full npm config compatibility // See: https://github.com/zkat/pacote/issues/156 const config = (0, keyValueBy_1.keyValueBy)(npmConfig, (key, value) => { // replace env ${VARS} in strings with the process.env value const normalizedValue = typeof value !== 'string' ? value : // parse stringified booleans keyTypes[key.replace(/-/g, '').toLowerCase()] === 'boolean' ? stringToBoolean(value) : keyTypes[key.replace(/-/g, '').toLowerCase()] === 'number' ? stringToNumber(value) : value.replace(/\${([^}]+)}/, (_, envVar) => process.env[envVar]); // normalize the key for pacote const { [key]: pacoteKey } = npmConfigToPacoteMap; return typeof pacoteKey === 'string' ? // key is mapped to a string { [pacoteKey]: normalizedValue } : // key is mapped to a function typeof pacoteKey === 'function' ? { ...pacoteKey(normalizedValue.toString()) } : // otherwise assign the camel-cased key { [key.match(/^[a-z]/i) ? (0, camelCase_1.default)(key) : key]: normalizedValue }; }); return config; }; exports.normalizeNpmConfig = normalizeNpmConfig; /** Finds and parses the npm config at the given path. If the path does not exist, returns null. If no path is provided, finds and merges the global and user npm configs using libnpmconfig and sets cache: false. */ const findNpmConfig = (0, fast_memoize_1.default)((configPath) => { let config; if (configPath) { try { config = ini_1.default.parse(fs_1.default.readFileSync(configPath, 'utf-8')); } catch (err) { if (err.code === 'ENOENT') { return null; } else { throw err; } } } else { // libnpmconfig incorrectly (?) ignores NPM_CONFIG_USERCONFIG because it is always overridden by the default builtin.userconfig // set userconfig manually so that it is prioritized const opts = libnpmconfig_1.default.read(null, { userconfig: process.env.npm_config_userconfig || process.env.NPM_CONFIG_USERCONFIG, }); config = { ...opts.toJSON(), cache: false, }; } return (0, exports.normalizeNpmConfig)(config, configPath); }); // get the base config that is used for all npm queries // this may be partially overwritten by .npmrc config files when using --deep const npmConfig = findNpmConfig(); /** A promise that returns true if --global is deprecated on the system npm. Spawns "npm --version". */ const isGlobalDeprecated = (0, fast_memoize_1.default)(async () => { const cmd = process.platform === 'win32' ? 'npm.cmd' : 'npm'; const output = await (0, spawn_please_1.default)(cmd, ['--version']); const npmVersion = output.trim(); // --global was deprecated in npm v8.11.0. return semver_1.default.valid(npmVersion) && semver_1.default.gte(npmVersion, '8.11.0'); }); /** * @typedef {object} CommandAndPackageName * @property {string} command * @property {string} packageName */ /** * Parse JSON and throw an informative error on failure. * * @param result Data to be parsed * @param data * @returns */ function parseJson(result, data) { let json; try { json = JSON.parse(result); } catch (err) { throw new Error(`Expected JSON from "${data.command}".${data.packageName ? ` There could be problems with the ${data.packageName} package.` : ''} ${result ? 'Instead received: ' + result : 'Received empty response.'}`); } return json; } /** * Check if package author changed between current and upgraded version. * * @param packageName Name of the package * @param currentVersion Current version declaration (may be range) * @param upgradedVersion Upgraded version declaration (may be range) * @param npmConfigLocal Additional npm config variables that are merged into the system npm config * @returns A promise that fulfills with boolean value. */ async function packageAuthorChanged(packageName, currentVersion, upgradedVersion, options = {}, npmConfigLocal) { var _a, _b; const result = await pacote_1.default.packument(packageName, { ...npmConfigLocal, ...npmConfig, fullMetadata: true, ...(options.registry ? { registry: options.registry, silent: true } : null), }); if (result.versions) { const pkgVersions = Object.keys(result.versions); const current = semver_1.default.minSatisfying(pkgVersions, currentVersion); const upgraded = semver_1.default.maxSatisfying(pkgVersions, upgradedVersion); if (current && upgraded && result.versions[current]._npmUser && result.versions[upgraded]._npmUser) { const currentAuthor = (_a = result.versions[current]._npmUser) === null || _a === void 0 ? void 0 : _a.name; const latestAuthor = (_b = result.versions[upgraded]._npmUser) === null || _b === void 0 ? void 0 : _b.name; return !(0, isEqual_1.default)(currentAuthor, latestAuthor); } } return false; } exports.packageAuthorChanged = packageAuthorChanged; /** Returns true if an object is a Packument. */ const isPackument = (o) => o && (o.name || o.engines || o.version || o.versions); /** Creates a function with the same signature as viewMany that always returns the given versions. */ const mockViewMany = (mockReturnedVersions) => (name, fields, currentVersion, options) => { var _a, _b; // a partial Packument const partialPackument = typeof mockReturnedVersions === 'function' ? (_a = mockReturnedVersions(options)) === null || _a === void 0 ? void 0 : _a[name] : typeof mockReturnedVersions === 'string' || isPackument(mockReturnedVersions) ? mockReturnedVersions : mockReturnedVersions[name]; const version = isPackument(partialPackument) ? partialPackument.version : partialPackument; // if there is no version, hard exit // otherwise getPackageProtected will swallow the error if (!version) { console.error(`No mock version supplied for ${name}`); process.exit(1); } const time = (isPackument(partialPackument) && ((_b = partialPackument.time) === null || _b === void 0 ? void 0 : _b[version])) || new Date().toISOString(); const packument = { name, engines: { node: '' }, time: { [version]: time, }, version, // overwritten below versions: [], ...(isPackument(partialPackument) ? partialPackument : null), }; return Promise.resolve((0, keyValueBy_1.keyValueBy)(fields, field => ({ [field]: field === 'versions' ? { [version]: packument, } : field === 'time' ? { [version]: time, } : { ...packument, versions: [packument], }, }))); }; exports.mockViewMany = mockViewMany; /** Merges the workspace, global, user, local, project, and cwd npm configs (in that order). */ // Note that this is memoized on configs and options, but not on package name. This avoids duplicate messages when log level is verbose. findNpmConfig is memoized on config path, so it is not expensive to call multiple times. const mergeNpmConfigs = (0, fast_memoize_1.default)(({ npmConfigLocal, npmConfigUser, npmConfigWorkspaceProject, }, options) => { // merge project npm config with base config const npmConfigProjectPath = options.packageFile ? path_1.default.join(options.packageFile, '../.npmrc') : null; const npmConfigProject = options.packageFile ? findNpmConfig(npmConfigProjectPath || undefined) : null; const npmConfigCWDPath = options.cwd ? path_1.default.join(options.cwd, '.npmrc') : null; const npmConfigCWD = options.cwd ? findNpmConfig(npmConfigCWDPath) : null; if (npmConfigWorkspaceProject && Object.keys(npmConfigWorkspaceProject).length > 0) { (0, logging_1.print)(options, `\nnpm config (workspace project):`, 'verbose'); (0, logging_1.printSorted)(options, (0, omit_1.default)(npmConfigWorkspaceProject, 'cache'), 'verbose'); } if (npmConfigUser && Object.keys(npmConfigUser).length > 0) { (0, logging_1.print)(options, `\nnpm config (user):`, 'verbose'); (0, logging_1.printSorted)(options, (0, omit_1.default)(npmConfigUser, 'cache'), 'verbose'); } if (npmConfigLocal && Object.keys(npmConfigLocal).length > 0) { (0, logging_1.print)(options, `\nnpm config (local override):`, 'verbose'); (0, logging_1.printSorted)(options, (0, omit_1.default)(npmConfigLocal, 'cache'), 'verbose'); } if (npmConfigProject && Object.keys(npmConfigProject).length > 0) { (0, logging_1.print)(options, `\nnpm config (project: ${npmConfigProjectPath}):`, 'verbose'); (0, logging_1.printSorted)(options, (0, omit_1.default)(npmConfigProject, 'cache'), 'verbose'); } if (npmConfigCWD && Object.keys(npmConfigCWD).length > 0) { (0, logging_1.print)(options, `\nnpm config (cwd: ${npmConfigCWDPath}):`, 'verbose'); // omit cache since it is added to every config (0, logging_1.printSorted)(options, (0, omit_1.default)(npmConfigCWD, 'cache'), 'verbose'); } const npmConfigMerged = { ...npmConfigWorkspaceProject, ...npmConfigUser, ...npmConfigLocal, ...npmConfigProject, ...npmConfigCWD, ...(options.registry ? { registry: options.registry, silent: true } : null), ...(options.timeout ? { timeout: options.timeout } : null), }; const isMerged = npmConfigWorkspaceProject || npmConfigLocal || npmConfigProject || npmConfigCWD; if (isMerged) { (0, logging_1.print)(options, `\nmerged npm config:`, 'verbose'); // omit cache since it is added to every config (0, logging_1.printSorted)(options, (0, omit_1.default)(npmConfigMerged, 'cache'), 'verbose'); } return npmConfigMerged; }); /** * Returns an object of specified values retrieved by npm view. * * @param packageName Name of the package * @param fields Array of fields like versions, time, version * @param currentVersion * @returns dist-tags field return Index<Packument>, time field returns Index<Index<string>>>, versions field returns Index<Index<Packument>> */ async function viewMany(packageName, fields, currentVersion, options, retried = 0, npmConfigLocal, npmConfigWorkspaceProject) { var _a; // See: /test/helpers/stubNpmView if (process.env.STUB_NPM_VIEW) { const mockReturnedVersions = JSON.parse(process.env.STUB_NPM_VIEW); return (0, exports.mockViewMany)(mockReturnedVersions)(packageName, fields, currentVersion, options); } if (isExactVersion(currentVersion)) { return Promise.resolve({}); } // fields may already include time const fieldsExtended = ((_a = options.format) === null || _a === void 0 ? void 0 : _a.includes('time')) ? [...fields, 'time'] : fields; const fullMetadata = fieldsExtended.includes('time'); const npmConfigMerged = mergeNpmConfigs({ npmConfigUser: { ...npmConfig, fullMetadata }, npmConfigLocal, npmConfigWorkspaceProject, }, options); let result; try { result = await pacote_1.default.packument(packageName, npmConfigMerged); } catch (err) { if (options.retry && ++retried <= options.retry) { return viewMany(packageName, fieldsExtended, currentVersion, options, retried, npmConfigLocal); } throw err; } // select each field from the result object const resultNormalized = (0, keyValueBy_1.keyValueBy)(fields, field => { let value = result[field]; // index into the result object to get the dist-tag if (field.startsWith('dist-tags.') && result.versions) { const packument = result.versions[(0, get_1.default)(result, field)]; // since viewOne only keeps a single field, we need to add time onto the dist-tag field value = fullMetadata ? { ...packument, time: result.time } : packument; } return { [field]: value, }; }); return resultNormalized; } /** Memoize viewMany for --deep and --workspaces performance. */ exports.viewManyMemoized = (0, fast_memoize_1.default)(viewMany, { // serializer args are incorrectly typed as any[] instead of being generic, so we need to cast it serializer: (([packageName, fields, currentVersion, options, retried, npmConfigLocal, npmConfigWorkspaceProject,]) => JSON.stringify([ packageName, fields, // currentVersion does not change the behavior of viewMany unless it is an invalid/inexact version which causes it to short circuit isExactVersion(currentVersion), // packageFile varies by cwd in workspaces/deep mode, so we do not want to memoize on that (0, omit_1.default)(options, 'packageFile'), // make sure retries do not get memoized retried, npmConfigLocal, npmConfigWorkspaceProject, ])), }); /** * Returns the value of one of the properties retrieved by npm view. * * @param packageName Name of the package * @param field Field such as "versions" or "dist-tags.latest" are parsed from the pacote result (https://www.npmjs.com/package/pacote#packument) * @param currentVersion * @returns Promised result */ async function viewOne(packageName, field, currentVersion, options, npmConfigLocal, npmConfigProject) { const result = await (0, exports.viewManyMemoized)(packageName, [field], currentVersion, options, 0, npmConfigLocal, npmConfigProject); return result[field]; } exports.viewOne = viewOne; /** * Spawns npm with --json. Handles different commands for Window and Linux/OSX, and automatically converts --location=global to --global on npm < 8.11.0. * * @param args * @param [npmOptions={}] * @param [spawnOptions={}] * @returns */ async function spawnNpm(args, npmOptions = {}, spawnOptions = {}) { const cmd = process.platform === 'win32' ? 'npm.cmd' : 'npm'; const fullArgs = [ ...(npmOptions.location ? (await isGlobalDeprecated()) ? [`--location=${npmOptions.location}`] : npmOptions.location === 'global' ? ['--global'] : [] : []), ...(npmOptions.prefix ? [`--prefix=${npmOptions.prefix}`] : []), '--json', ...(Array.isArray(args) ? args : [args]), ]; return (0, spawn_please_1.default)(cmd, fullArgs, spawnOptions); } /** * Get platform-specific default prefix to pass on to npm. * * @param options * @param [options.global] * @param [options.prefix] * @returns */ async function defaultPrefix(options) { if (options.prefix) { return Promise.resolve(options.prefix); } const cmd = process.platform === 'win32' ? 'npm.cmd' : 'npm'; let prefix; // catch spawn error which can occur on Windows // https://github.com/raineorshine/npm-check-updates/issues/703 try { prefix = await (0, spawn_please_1.default)(cmd, ['config', 'get', 'prefix']); } catch (e) { const message = (e.message || e || '').toString(); (0, logging_1.print)(options, 'Error executing `npm config get prefix`. Caught and ignored. Unsolved: https://github.com/raineorshine/npm-check-updates/issues/703. ERROR: ' + message, 'verbose', 'error'); } // FIX: for ncu -g doesn't work on homebrew or windows #146 // https://github.com/raineorshine/npm-check-updates/issues/146 return options.global && (prefix === null || prefix === void 0 ? void 0 : prefix.match('Cellar')) ? '/usr/local' : // Workaround: get prefix on windows for global packages // Only needed when using npm api directly process.platform === 'win32' && options.global && !process.env.prefix ? prefix ? prefix.trim() : `${process.env.AppData}\\npm` : undefined; } exports.defaultPrefix = defaultPrefix; /** * Fetches the highest version number, regardless of tag or publish time. * * @param packageName * @param currentVersion * @param options * @returns */ const greatest = async (packageName, currentVersion, options = {}, npmConfig, npmConfigProject) => { // known type based on 'versions' const versions = (await viewOne(packageName, 'versions', currentVersion, options, npmConfig, npmConfigProject)); return { version: (0, last_1.default)( // eslint-disable-next-line fp/no-mutating-methods (0, filter_1.default)(versions, (0, filters_1.filterPredicate)(options)) .map(o => o.version) .sort(versionUtil.compareVersions)) || null, }; }; exports.greatest = greatest; /** * Fetches the list of peer dependencies for a specific package version. * * @param packageName * @param version * @returns Promised {packageName: version} collection */ const getPeerDependencies = async (packageName, version) => { const args = ['view', `${packageName}@${version}`, 'peerDependencies']; const result = await spawnNpm(args, {}, { rejectOnError: false }); return result ? parseJson(result, { command: [...args, '--json'].join(' ') }) : {}; }; exports.getPeerDependencies = getPeerDependencies; /** * Fetches the list of all installed packages. * * @param [options] * @param [options.cwd] * @param [options.global] * @param [options.prefix] * @returns */ const list = async (options = {}) => { const result = await spawnNpm(['ls', '--depth=0'], { // spawnNpm takes the modern --location option and converts it to --global on older versions of npm ...(options.global ? { location: 'global' } : null), ...(options.prefix ? { prefix: options.prefix } : null), }, { ...(options.cwd ? { cwd: options.cwd } : null), rejectOnError: false, }); const dependencies = parseJson(result, { command: `npm${process.platform === 'win32' ? '.cmd' : ''} ls --json${options.global ? ' --location=global' : ''}${options.prefix ? ' --prefix ' + options.prefix : ''}`, }).dependencies; return (0, keyValueBy_1.keyValueBy)(dependencies, (name, info) => { var _a; return ({ // unmet peer dependencies have a different structure [name]: info.version || ((_a = info.required) === null || _a === void 0 ? void 0 : _a.version), }); }); }; exports.list = list; /** * Fetches the version of a package published to options.distTag. * * @param packageName * @param currentVersion * @param options * @returns */ const distTag = async (packageName, currentVersion, options = {}, npmConfig, npmConfigProject) => { var _a; const packument = (await viewOne(packageName, `dist-tags.${options.distTag}`, currentVersion, options, npmConfig, npmConfigProject)); // known type based on dist-tags.latest // latest should not be deprecated // if latest exists and latest is not a prerelease version, return it // if latest exists and latest is a prerelease version and --pre is specified, return it // if latest exists and latest not satisfies min version of engines.node if (packument && (0, filters_1.filterPredicate)(options)(packument)) { return { version: packument.version, ...(((_a = packument.time) === null || _a === void 0 ? void 0 : _a[packument.version]) ? { time: packument.time[packument.version] } : null), }; } // If we use a custom dist-tag, we do not want to get other 'pre' versions, just the ones from this dist-tag if (options.distTag && options.distTag !== 'latest') return {}; // if latest is a prerelease version and --pre is not specified // or latest is deprecated // find the next valid version // known type based on dist-tags.latest return (0, exports.greatest)(packageName, currentVersion, options, npmConfig, npmConfigProject); }; exports.distTag = distTag; /** * Fetches the version published to the latest tag. * * @param packageName * @param currentVersion * @param options * @returns */ const latest = async (packageName, currentVersion, options = {}, npmConfig, npmConfigProject) => (0, exports.distTag)(packageName, currentVersion, { ...options, distTag: 'latest' }, npmConfig, npmConfigProject); exports.latest = latest; /** * Fetches the most recently published version, regardless of version number. * * @param packageName * @param currentVersion * @param options * @returns */ const newest = async (packageName, currentVersion, options = {}, npmConfig, npmConfigProject) => { const result = await (0, exports.viewManyMemoized)(packageName, ['time', 'versions'], currentVersion, options, 0, npmConfig, npmConfigProject); // Generate a map of versions that satisfy the node engine. // result.versions is an object but is parsed as an array, so manually convert it to an object. // Otherwise keyValueBy will pass the predicate arguments in the wrong order. const versionsSatisfyingNodeEngine = (0, keyValueBy_1.keyValueBy)(Object.values(result.versions || {}), (packument) => (0, filters_1.satisfiesNodeEngine)(packument, options.nodeEngineVersion) ? { [packument.version]: true } : null); // filter out times that do not satisfy the node engine // filter out prereleases if pre:false (same as allowPreOrIsNotPre) const timesSatisfyingNodeEngine = (0, filterObject_1.default)((result.time || {}), version => versionsSatisfyingNodeEngine[version] && (options.pre !== false || !versionUtil.isPre(version))); // sort by timestamp (entry[1]) and map versions const versionsSortedByTime = (0, sortBy_1.default)(Object.entries(timesSatisfyingNodeEngine), 1).map(([version]) => version); return { version: (0, last_1.default)(versionsSortedByTime) }; }; exports.newest = newest; /** * Fetches the highest version with the same major version as currentVersion. * * @param packageName * @param currentVersion * @param options * @returns */ const minor = async (packageName, currentVersion, options = {}, npmConfig, npmConfigProject) => { const versions = (await viewOne(packageName, 'versions', currentVersion, options, npmConfig, npmConfigProject)); const version = versionUtil.findGreatestByLevel((0, filter_1.default)(versions, (0, filters_1.filterPredicate)(options)).map(o => o.version), currentVersion, 'minor'); return { version }; }; exports.minor = minor; /** * Fetches the highest version with the same minor and major version as currentVersion. * * @param packageName * @param currentVersion * @param options * @returns */ const patch = async (packageName, currentVersion, options = {}, npmConfig, npmConfigProject) => { const versions = (await viewOne(packageName, 'versions', currentVersion, options, npmConfig, npmConfigProject)); const version = versionUtil.findGreatestByLevel((0, filter_1.default)(versions, (0, filters_1.filterPredicate)(options)).map(o => o.version), currentVersion, 'patch'); return { version }; }; exports.patch = patch; /** * Fetches the highest version that satisfies the semver range specified in the package.json. * * @param packageName * @param currentVersion * @param options * @returns */ const semver = async (packageName, currentVersion, options = {}, npmConfig, npmConfigProject) => { const versions = (await viewOne(packageName, 'versions', currentVersion, options, npmConfig, npmConfigProject)); // ignore explicit version ranges if (isExplicitRange(currentVersion)) return { version: null }; const versionsFiltered = (0, filter_1.default)(versions, (0, filters_1.filterPredicate)(options)).map(o => o.version); // TODO: Upgrading within a prerelease does not seem to work. // { includePrerelease: true } does not help. const version = semver_1.default.maxSatisfying(versionsFiltered, currentVersion); return { version }; }; exports.semver = semver; exports.default = spawnNpm; //# sourceMappingURL=npm.js.map