UNPKG

npm-check-updates

Version:

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

248 lines 11.9 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.newest = exports.minor = exports.latest = exports.greatest = exports.distTag = exports.list = exports.defaultPrefix = exports.getPathToLookForYarnrc = exports.npmAuthTokenKeyValue = void 0; const fast_memoize_1 = __importDefault(require("fast-memoize")); const promises_1 = __importDefault(require("fs/promises")); const js_yaml_1 = __importDefault(require("js-yaml")); const jsonlines_1 = __importDefault(require("jsonlines")); const curry_1 = __importDefault(require("lodash/curry")); const os_1 = __importDefault(require("os")); const path_1 = __importDefault(require("path")); const spawn_please_1 = __importDefault(require("spawn-please")); const exists_1 = __importDefault(require("../lib/exists")); const findLockfile_1 = __importDefault(require("../lib/findLockfile")); const keyValueBy_1 = require("../lib/keyValueBy"); const logging_1 = require("../lib/logging"); const npm = __importStar(require("./npm")); /** Safely interpolates a string as a template string. */ const interpolate = (s, data) => s.replace(/\$\{([^:-]+)(?:(:)?-([^}]*))?\}/g, (match, key, name, fallbackOnEmpty, fallback) => data[key] || (fallbackOnEmpty ? fallback : '')); /** Reads an auth token from a yarn config, interpolates it, and returns it as an npm config key-value pair. */ exports.npmAuthTokenKeyValue = (0, curry_1.default)((npmConfig, dep, scopedConfig) => { if (scopedConfig.npmAuthToken) { // get registry server from this config or a previous config (assumes setNpmRegistry has already been called on all npm scopes) const registryServer = scopedConfig.npmRegistryServer || npmConfig[`@${dep}:registry`]; // interpolate environment variable fallback // https://yarnpkg.com/configuration/yarnrc if (registryServer) { let trimmedRegistryServer = registryServer.replace(/^https?:/, ''); if (trimmedRegistryServer.endsWith('/')) { trimmedRegistryServer = trimmedRegistryServer.slice(0, -1); } return { [`${trimmedRegistryServer}/:_authToken`]: interpolate(scopedConfig.npmAuthToken, process.env), }; } } return null; }); /** Reads a registry from a yarn config. interpolates it, and returns it as an npm config key-value pair. */ const npmRegistryKeyValue = (dep, scopedConfig) => scopedConfig.npmRegistryServer ? { [`@${dep}:registry`]: interpolate(scopedConfig.npmRegistryServer, process.env) } : null; /** * Returns the path to the local .yarnrc.yml, or undefined. This doesn't * actually check that the .yarnrc.yml file exists. * * Exported for test purposes only. * * @param readdirSync This is only a parameter so that it can be used in tests. */ async function getPathToLookForYarnrc(options, readdir = promises_1.default.readdir) { var _a; if (options.global) return undefined; const directoryPath = (_a = (await (0, findLockfile_1.default)(options, readdir))) === null || _a === void 0 ? void 0 : _a.directoryPath; if (!directoryPath) return undefined; return path_1.default.join(directoryPath, '.yarnrc.yml'); } exports.getPathToLookForYarnrc = getPathToLookForYarnrc; // If private registry auth is specified in npmScopes in .yarnrc.yml, read them in and convert them to npm config variables. // Define as a memoized function to efficiently call existsSync and readFileSync only once, and only if yarn is being used. // https://github.com/raineorshine/npm-check-updates/issues/1036 const npmConfigFromYarn = (0, fast_memoize_1.default)(async (options) => { const yarnrcLocalPath = await getPathToLookForYarnrc(options); const yarnrcUserPath = path_1.default.join(os_1.default.homedir(), '.yarnrc.yml'); const yarnrcLocalExists = typeof yarnrcLocalPath === 'string' && (await (0, exists_1.default)(yarnrcLocalPath)); const yarnrcUserExists = await (0, exists_1.default)(yarnrcUserPath); const yarnrcLocal = yarnrcLocalExists ? await promises_1.default.readFile(yarnrcLocalPath, 'utf-8') : ''; const yarnrcUser = yarnrcUserExists ? await promises_1.default.readFile(yarnrcUserPath, 'utf-8') : ''; const yarnConfigLocal = js_yaml_1.default.load(yarnrcLocal); const yarnConfigUser = js_yaml_1.default.load(yarnrcUser); let npmConfig = { ...(0, keyValueBy_1.keyValueBy)((yarnConfigUser === null || yarnConfigUser === void 0 ? void 0 : yarnConfigUser.npmScopes) || {}, npmRegistryKeyValue), ...(0, keyValueBy_1.keyValueBy)((yarnConfigLocal === null || yarnConfigLocal === void 0 ? void 0 : yarnConfigLocal.npmScopes) || {}, npmRegistryKeyValue), }; // npmAuthTokenKeyValue uses scoped npmRegistryServer, so must come after npmRegistryKeyValue npmConfig = { ...npmConfig, ...(0, keyValueBy_1.keyValueBy)((yarnConfigUser === null || yarnConfigUser === void 0 ? void 0 : yarnConfigUser.npmScopes) || {}, (0, exports.npmAuthTokenKeyValue)(npmConfig)), ...(0, keyValueBy_1.keyValueBy)((yarnConfigLocal === null || yarnConfigLocal === void 0 ? void 0 : yarnConfigLocal.npmScopes) || {}, (0, exports.npmAuthTokenKeyValue)(npmConfig)), }; // set auth token after npm registry, since auth token syntax uses regitry if (yarnrcLocalExists) { (0, logging_1.print)(options, `\nUsing local yarn config at ${yarnrcLocalPath}:`, 'verbose'); (0, logging_1.print)(options, yarnConfigLocal, 'verbose'); } if (yarnrcUserExists) { (0, logging_1.print)(options, `\nUsing user yarn config at ${yarnrcUserPath}:`, 'verbose'); (0, logging_1.print)(options, yarnConfigLocal, 'verbose'); } if (Object.keys(npmConfig)) { (0, logging_1.print)(options, '\nMerged yarn config in npm format:', 'verbose'); (0, logging_1.print)(options, npmConfig, 'verbose'); } return npmConfig; }); /** * Parse JSON lines and throw an informative error on failure. * * Note: although this is similar to the NPM parseJson() function we always return the * same concrete-type here, for now. * * @param result Output from `yarn list --json` to be parsed */ function parseJsonLines(result) { return new Promise((resolve, reject) => { const dependencies = {}; const parser = jsonlines_1.default.parse(); parser.on('data', d => { // only parse info data // ignore error info, e.g. "Visit https://yarnpkg.com/en/docs/cli/list for documentation about this command." if (d.type === 'info' && !d.data.match(/^Visit/)) { // parse package name and version number from info data, e.g. "nodemon@2.0.4" has binaries const [, pkgName, pkgVersion] = d.data.match(/"(@?.*)@(.*)"/) || []; dependencies[pkgName] = { version: pkgVersion, from: pkgName, }; } else if (d.type === 'error') { reject(new Error(d.data)); } }); parser.on('end', () => { resolve({ dependencies }); }); parser.on('error', reject); parser.write(result); parser.end(); }); } /** * Spawn yarn requires a different command on Windows. * * @param args * @param [yarnOptions={}] * @param [spawnOptions={}] * @returns */ async function spawnYarn(args, yarnOptions = {}, spawnOptions) { const cmd = process.platform === 'win32' ? 'yarn.cmd' : 'yarn'; const fullArgs = [ ...(yarnOptions.location === 'global' ? ['global'] : []), ...(yarnOptions.prefix ? [`--prefix=${yarnOptions.prefix}`] : []), '--depth=0', '--json', '--no-progress', // args must go after yarn options, otherwise they are passed through to npm scripts // https://github.com/raineorshine/npm-check-updates/issues/1362 ...(Array.isArray(args) ? args : [args]), ]; return (0, spawn_please_1.default)(cmd, fullArgs, spawnOptions); } /** * Get platform-specific default prefix to pass on to yarn. * * @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' ? 'yarn.cmd' : 'yarn'; const prefix = await (0, spawn_please_1.default)(cmd, ['global', 'dir']) // yarn 2.0 does not support yarn global // catch error to prevent process from crashing // https://github.com/raineorshine/npm-check-updates/issues/873 .catch(() => { /* empty */ }); // 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 && 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.LOCALAPPDATA}\\Yarn\\Data\\global` : null; } exports.defaultPrefix = defaultPrefix; /** * Fetches the list of all installed packages. * * @param [options] * @param [options.cwd] * @param [options.global] * @param [options.prefix] * @returns */ const list = async (options = {}, spawnOptions) => { const jsonLines = await spawnYarn('list', options, { ...(options.cwd ? { cwd: options.cwd } : {}), ...spawnOptions, }); const json = await parseJsonLines(jsonLines); const keyValues = (0, keyValueBy_1.keyValueBy)(json.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), }); }); return keyValues; }; exports.list = list; /** Wraps a GetVersion function and passes the yarn config. */ const withNpmConfigFromYarn = (getVersion) => async (packageName, currentVersion, options = {}) => getVersion(packageName, currentVersion, options, await npmConfigFromYarn(options)); exports.distTag = withNpmConfigFromYarn(npm.distTag); exports.greatest = withNpmConfigFromYarn(npm.greatest); exports.latest = withNpmConfigFromYarn(npm.latest); exports.minor = withNpmConfigFromYarn(npm.minor); exports.newest = withNpmConfigFromYarn(npm.newest); exports.patch = withNpmConfigFromYarn(npm.patch); exports.semver = withNpmConfigFromYarn(npm.semver); exports.default = spawnYarn; //# sourceMappingURL=yarn.js.map