UNPKG

nx

Version:

The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.

855 lines (854 loc) • 33.6 kB
"use strict"; /** * This file contains the logic to convert pnpm lockfile to a standard format. * It will convert inline specifiers to the separate specifiers format and ensure importers are present. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.isV5Syntax = isV5Syntax; exports.usesLeadingDash = usesLeadingDash; exports.loadPnpmHoistedDepsDefinition = loadPnpmHoistedDepsDefinition; exports.parseAndNormalizePnpmLockfile = parseAndNormalizePnpmLockfile; exports.stringifyToPnpmYaml = stringifyToPnpmYaml; const fs_1 = require("fs"); const semver_1 = require("semver"); const workspace_root_1 = require("../../../../utils/workspace-root"); const file_hasher_1 = require("../../../../hasher/file-hasher"); function isV5Syntax(data) { if (+data.lockfileVersion.toString() >= 6) { return false; } else { return true; } } function usesLeadingDash(data) { if (+data.lockfileVersion.toString() >= 9) { false; } else { return true; } } function loadPnpmHoistedDepsDefinition() { const fullPath = `${workspace_root_1.workspaceRoot}/node_modules/.modules.yaml`; if ((0, fs_1.existsSync)(fullPath)) { const content = (0, fs_1.readFileSync)(fullPath, 'utf-8'); const { load } = require('@zkochan/js-yaml'); return load(content)?.hoistedDependencies ?? {}; } else { throw new Error(`Could not find ".modules.yaml" at "${fullPath}"`); } } /** * Parsing and mapping logic from pnpm lockfile `read` function */ function parseAndNormalizePnpmLockfile(content) { const { load } = require('@zkochan/js-yaml'); return convertToLockfileObject(load(content)); } // https://github.com/pnpm/pnpm/blob/50e37072f42bcca6d393a74bed29f7f0e029805d/lockfile/lockfile-file/src/write.ts#L22 const LOCKFILE_YAML_FORMAT = { blankLines: true, lineWidth: -1, // This is setting line width to never wrap noCompatMode: true, noRefs: true, sortKeys: false, }; const LOCKFILE_YAML_PRE9_FORMAT = { ...LOCKFILE_YAML_FORMAT, lineWidth: 1000, }; /** * Mapping and writing logic from pnpm lockfile `write` function */ function stringifyToPnpmYaml(lockfile) { const { dump } = require('@zkochan/js-yaml'); const lockfileVersion = +lockfile.lockfileVersion; if (lockfileVersion >= 9) { const adaptedLockfile = convertToLockfileFile(lockfile, { forceSharedFormat: true, }); return dump(sortLockfileKeys(adaptedLockfile), LOCKFILE_YAML_FORMAT); } else { // https://github.com/pnpm/pnpm/blob/af3e5559d377870d4c3d303429b3ed1a4e64fedc/lockfile/lockfile-file/src/write.ts#L77 const adaptedLockfile = lockfileVersion >= 6 ? convertToInlineSpecifiersFormat(lockfile) : lockfile; return dump(sortLockfileKeys(normalizeLockfileV6(adaptedLockfile, lockfileVersion >= 6)), LOCKFILE_YAML_PRE9_FORMAT); } } /** * The following code was copied over from pnpm source code and modified to work in this context. */ // https://github.com/pnpm/pnpm/blob/af3e5559d377870d4c3d303429b3ed1a4e64fedc/lockfile/lockfile-file/src/experiments/inlineSpecifiersLockfileConverters.ts#L17 function convertToInlineSpecifiersFormat(lockfile) { let importers = lockfile.importers; let packages = lockfile.packages; importers = Object.fromEntries(Object.entries(lockfile.importers ?? {}).map(([importerId, pkgSnapshot]) => { const newSnapshot = { ...pkgSnapshot }; if (newSnapshot.dependencies != null) { newSnapshot.dependencies = mapValues(newSnapshot.dependencies, convertOldRefToNewRef); } if (newSnapshot.optionalDependencies != null) { newSnapshot.optionalDependencies = mapValues(newSnapshot.optionalDependencies, convertOldRefToNewRef); } if (newSnapshot.devDependencies != null) { newSnapshot.devDependencies = mapValues(newSnapshot.devDependencies, convertOldRefToNewRef); } return [importerId, newSnapshot]; })); packages = Object.fromEntries(Object.entries(lockfile.packages ?? {}).map(([depPath, pkgSnapshot]) => { const newSnapshot = { ...pkgSnapshot }; if (newSnapshot.dependencies != null) { newSnapshot.dependencies = mapValues(newSnapshot.dependencies, convertOldRefToNewRef); } if (newSnapshot.optionalDependencies != null) { newSnapshot.optionalDependencies = mapValues(newSnapshot.optionalDependencies, convertOldRefToNewRef); } return [convertOldDepPathToNewDepPath(depPath), newSnapshot]; })); const newLockfile = { ...lockfile, packages, lockfileVersion: lockfile.lockfileVersion.toString(), importers: mapValues(importers, convertProjectSnapshotToInlineSpecifiersFormat), }; if (newLockfile.time) { newLockfile.time = Object.fromEntries(Object.entries(newLockfile.time).map(([depPath, time]) => [ convertOldDepPathToNewDepPath(depPath), time, ])); } return newLockfile; } // https://github.com/pnpm/pnpm/blob/af3e5559d377870d4c3d303429b3ed1a4e64fedc/lockfile/lockfile-file/src/experiments/inlineSpecifiersLockfileConverters.ts#L72 function convertOldDepPathToNewDepPath(oldDepPath) { const parsedDepPath = dpParse(oldDepPath); if (!parsedDepPath.name || !parsedDepPath.version) return oldDepPath; let newDepPath = `/${parsedDepPath.name}@${parsedDepPath.version}`; if (parsedDepPath.peersSuffix) { if (parsedDepPath.peersSuffix.startsWith('(')) { newDepPath += parsedDepPath.peersSuffix; } else { newDepPath += `_${parsedDepPath.peersSuffix}`; } } if (parsedDepPath.host) { newDepPath = `${parsedDepPath.host}${newDepPath}`; } return newDepPath; } // https://github.com/pnpm/pnpm/blob/af3e5559d377870d4c3d303429b3ed1a4e64fedc/lockfile/lockfile-file/src/experiments/inlineSpecifiersLockfileConverters.ts#L89 function convertOldRefToNewRef(oldRef) { if (oldRef.startsWith('link:') || oldRef.startsWith('file:')) { return oldRef; } if (oldRef.includes('/')) { return convertOldDepPathToNewDepPath(oldRef); } return oldRef; } // https://github.com/pnpm/pnpm/blob/af3e5559d377870d4c3d303429b3ed1a4e64fedc/lockfile/lockfile-file/src/experiments/inlineSpecifiersLockfileConverters.ts#L179 function convertProjectSnapshotToInlineSpecifiersFormat(projectSnapshot) { const { specifiers, ...rest } = projectSnapshot; const convertBlock = (block) => block != null ? convertResolvedDependenciesToInlineSpecifiersFormat(block, { specifiers, }) : block; return { ...rest, dependencies: convertBlock(projectSnapshot.dependencies), optionalDependencies: convertBlock(projectSnapshot.optionalDependencies), devDependencies: convertBlock(projectSnapshot.devDependencies), }; } // https://github.com/pnpm/pnpm/blob/af3e5559d377870d4c3d303429b3ed1a4e64fedc/lockfile/lockfile-file/src/experiments/inlineSpecifiersLockfileConverters.ts#L195 function convertResolvedDependenciesToInlineSpecifiersFormat(resolvedDependencies, { specifiers }) { return mapValues(resolvedDependencies, (version, depName) => ({ specifier: specifiers[depName], version, })); } // https://github.com/pnpm/pnpm/blob/af3e5559d377870d4c3d303429b3ed1a4e64fedc/packages/types/src/misc.ts#L6 const DEPENDENCIES_FIELDS = [ 'optionalDependencies', 'dependencies', 'devDependencies', ]; // https://github.com/pnpm/pnpm/blob/cca56c0c6c956d036883003092ca1d11bbb700f6/lockfile/lockfile-file/src/lockfileFormatConverters.ts#L169 function convertFromLockfileFileMutable(lockfileFile) { if (typeof lockfileFile?.['importers'] === 'undefined') { lockfileFile.importers = { '.': { dependenciesMeta: lockfileFile['dependenciesMeta'], publishDirectory: lockfileFile['publishDirectory'], }, }; for (const depType of DEPENDENCIES_FIELDS) { if (lockfileFile[depType] != null) { lockfileFile.importers['.'][depType] = lockfileFile[depType]; delete lockfileFile[depType]; } } } else if (isV5Syntax(lockfileFile)) { // remap the importers from v5 to the new format for (const depType of DEPENDENCIES_FIELDS) { if (lockfileFile.importers['.'][depType]) { for (const [depName, version] of Object.entries(lockfileFile.importers['.'][depType])) { lockfileFile.importers['.'][depType][depName] = { version, specifier: (lockfileFile['specifiers'] || lockfileFile.importers['.']['specifiers'])[depName], }; } } } } return lockfileFile; } // https://github.com/pnpm/pnpm/blob/cca56c0c6c956d036883003092ca1d11bbb700f6/lockfile/lockfile-file/src/lockfileFormatConverters.ts#L187 function convertToLockfileObject(lockfile) { if (lockfile.snapshots) { return convertLockfileV9ToLockfileObject(lockfile); } convertPkgIds(lockfile); const { importers, ...rest } = convertFromLockfileFileMutable(lockfile); const newLockfile = { ...rest, importers: mapValues(importers ?? {}, revertProjectSnapshot), }; return newLockfile; } // https://github.com/pnpm/pnpm/blob/cca56c0c6c956d036883003092ca1d11bbb700f6/lockfile/lockfile-file/src/lockfileFormatConverters.ts#L201 function convertPkgIds(lockfile) { const oldIdToNewId = {}; if (lockfile.packages == null || isEmpty(lockfile.packages)) return; for (const [pkgId, pkg] of Object.entries(lockfile.packages ?? {})) { if (pkg.name) { const { id, peersSuffix } = parseDepPath(pkgId); let newId = `${pkg.name}@`; if ('tarball' in pkg.resolution) { newId += pkg.resolution.tarball; if (pkg.resolution.path) { newId += `#path:${pkg.resolution.path}`; } } else if ('repo' in pkg.resolution) { newId += createGitHostedPkgId(pkg.resolution); } else if ('directory' in pkg.resolution) { newId += id; } else { continue; } oldIdToNewId[pkgId] = `${newId}${peersSuffix}`; if (id !== pkgId) { oldIdToNewId[id] = newId; } } else { const { id, peersSuffix } = parseDepPath(pkgId); const newId = id.substring(1); oldIdToNewId[pkgId] = `${newId}${peersSuffix}`; if (id !== pkgId) { oldIdToNewId[id] = newId; } } } const newLockfilePackages = {}; for (const [pkgId, pkg] of Object.entries(lockfile.packages ?? {})) { if (oldIdToNewId[pkgId]) { if (pkg.id) { pkg.id = oldIdToNewId[pkg.id]; } newLockfilePackages[oldIdToNewId[pkgId]] = pkg; } else { newLockfilePackages[pkgId] = pkg; } for (const depType of ['dependencies', 'optionalDependencies']) { for (const [alias, depPath] of Object.entries(pkg[depType] ?? {})) { if (oldIdToNewId[depPath]) { if (oldIdToNewId[depPath].startsWith(`${alias}@`)) { pkg[depType][alias] = oldIdToNewId[depPath].substring(alias.length + 1); } else { pkg[depType][alias] = oldIdToNewId[depPath]; } } } } } lockfile.packages = newLockfilePackages; if ((lockfile.dependencies != null || lockfile.devDependencies != null || lockfile.optionalDependencies != null) && !lockfile.importers?.['.']) { lockfile.importers = lockfile.importers ?? {}; lockfile.importers['.'] = { dependencies: lockfile.dependencies, devDependencies: lockfile.devDependencies, optionalDependencies: lockfile.optionalDependencies, }; delete lockfile.dependencies; delete lockfile.devDependencies; delete lockfile.optionalDependencies; } for (const importer of Object.values(lockfile.importers ?? {})) { for (const depType of [ 'dependencies', 'optionalDependencies', 'devDependencies', ]) { for (const [alias, { version }] of Object.entries(importer[depType] ?? {})) { if (oldIdToNewId[version]) { if (oldIdToNewId[version].startsWith(`${alias}@`)) { importer[depType][alias].version = oldIdToNewId[version].substring(alias.length + 1); } else { importer[depType][alias].version = oldIdToNewId[version]; } } } } } for (const depType of [ 'dependencies', 'optionalDependencies', 'devDependencies', ]) { for (const [alias, { version }] of Object.entries(lockfile[depType] ?? {})) { if (oldIdToNewId[version]) { lockfile[depType][alias].version = oldIdToNewId[version]; } } } } // https://github.com/pnpm/pnpm/blob/cca56c0c6c956d036883003092ca1d11bbb700f6/lockfile/lockfile-file/src/lockfileFormatConverters.ts#L289 function convertLockfileV9ToLockfileObject(lockfile) { const { importers, ...rest } = convertFromLockfileFileMutable(lockfile); const packages = {}; for (const [depPath, pkg] of Object.entries(lockfile.snapshots ?? {})) { const pkgId = removePeersSuffix(depPath); packages[depPath] = Object.assign(pkg, lockfile.packages?.[pkgId]); } return { ...omit(['snapshots'], rest), packages, importers: mapValues(importers ?? {}, revertProjectSnapshot), }; } // https://github.com/pnpm/pnpm/blob/cca56c0c6c956d036883003092ca1d11bbb700f6/lockfile/lockfile-file/src/lockfileFormatConverters.ts#L331 function revertProjectSnapshot(from) { const specifiers = {}; function moveSpecifiers(from) { const resolvedDependencies = {}; for (const [depName, { specifier, version }] of Object.entries(from)) { const existingValue = specifiers[depName]; if (existingValue != null && existingValue !== specifier) { throw new Error(`Project snapshot lists the same dependency more than once with conflicting versions: ${depName}`); } specifiers[depName] = specifier; resolvedDependencies[depName] = version; } return resolvedDependencies; } const dependencies = from.dependencies == null ? from.dependencies : moveSpecifiers(from.dependencies); const devDependencies = from.devDependencies == null ? from.devDependencies : moveSpecifiers(from.devDependencies); const optionalDependencies = from.optionalDependencies == null ? from.optionalDependencies : moveSpecifiers(from.optionalDependencies); return { ...from, specifiers, dependencies, devDependencies, optionalDependencies, }; } // https://github.com/pnpm/pnpm/blob/cca56c0c6c956d036883003092ca1d11bbb700f6/lockfile/lockfile-file/src/lockfileFormatConverters.ts#L367 function mapValues(obj, mapper) { const result = {}; for (const [key, value] of Object.entries(obj)) { result[key] = mapper(value, key); } return result; } // https://github.com/pnpm/pnpm/blob/cca56c0c6c956d036883003092ca1d11bbb700f6/resolving/git-resolver/src/createGitHostedPkgId.ts#L1 function createGitHostedPkgId({ repo, commit, path, }) { let id = `${repo.includes('://') ? '' : 'https://'}${repo}#${commit}`; if (!id.startsWith('git+')) id = `git+${id}`; if (path) { id += `&path:${path}`; } return id; } // https://github.com/pnpm/pnpm/blob/af3e5559d377870d4c3d303429b3ed1a4e64fedc/lockfile/lockfile-file/src/write.ts#L106 function normalizeLockfileV6(lockfile, isLockfileV6) { let lockfileToSave; if (Object.keys(lockfile.importers).length === 1 && lockfile.importers['.']) { lockfileToSave = { ...lockfile, ...lockfile.importers['.'], }; delete lockfileToSave.importers; for (const depType of DEPENDENCIES_FIELDS) { if (isEmpty(lockfileToSave[depType])) { delete lockfileToSave[depType]; } } if (isEmpty(lockfileToSave.packages) || lockfileToSave.packages == null) { delete lockfileToSave.packages; } } else { lockfileToSave = { ...lockfile, importers: mapValues(lockfile.importers, (importer) => { const normalizedImporter = {}; if (!isEmpty(importer.specifiers ?? {}) || !isLockfileV6) { normalizedImporter['specifiers'] = importer.specifiers ?? {}; } if (importer.dependenciesMeta != null && !isEmpty(importer.dependenciesMeta)) { normalizedImporter['dependenciesMeta'] = importer.dependenciesMeta; } for (const depType of DEPENDENCIES_FIELDS) { if (!isEmpty(importer[depType] ?? {})) { normalizedImporter[depType] = importer[depType]; } } if (importer.publishDirectory) { normalizedImporter.publishDirectory = importer.publishDirectory; } return normalizedImporter; }), }; if (isEmpty(lockfileToSave.packages) || lockfileToSave.packages == null) { delete lockfileToSave.packages; } } if (lockfileToSave.packages) { const newPackages = {}; for (const [depPath, pkgSnapshot] of Object.entries(lockfileToSave.packages)) { const newDepPath = depPath.replace(/\/$/, ''); newPackages[newDepPath] = pkgSnapshot; } } if (lockfileToSave.time) { lockfileToSave.time = (isLockfileV6 ? pruneTimeInLockfileV6 : pruneTime)(lockfileToSave.time, lockfile.importers); } if (lockfileToSave.overrides != null && isEmpty(lockfileToSave.overrides)) { delete lockfileToSave.overrides; } if (lockfileToSave.patchedDependencies != null && isEmpty(lockfileToSave.patchedDependencies)) { delete lockfileToSave.patchedDependencies; } if (lockfileToSave['neverBuiltDependencies'] != null) { if (isEmpty(lockfileToSave['neverBuiltDependencies'])) { delete lockfileToSave['neverBuiltDependencies']; } else { lockfileToSave['neverBuiltDependencies'] = lockfileToSave['neverBuiltDependencies'].sort(); } } if (lockfileToSave['onlyBuiltDependencies'] != null) { lockfileToSave['onlyBuiltDependencies'] = lockfileToSave['onlyBuiltDependencies'].sort(); } if (!lockfileToSave.packageExtensionsChecksum) { delete lockfileToSave.packageExtensionsChecksum; } return lockfileToSave; } // https://github.com/pnpm/pnpm/blob/af3e5559d377870d4c3d303429b3ed1a4e64fedc/lockfile/lockfile-file/src/write.ts#L173 function pruneTimeInLockfileV6(time, importers) { const rootDepPaths = new Set(); for (const importer of Object.values(importers)) { for (const depType of DEPENDENCIES_FIELDS) { for (let [depName, ref] of Object.entries(importer[depType] ?? {})) { let version; if (ref['version']) { version = ref['version']; } else { version = ref; } const suffixStart = version.indexOf('('); const refWithoutPeerSuffix = suffixStart === -1 ? version : version.slice(0, suffixStart); const depPath = refToRelative(refWithoutPeerSuffix, depName); if (!depPath) continue; rootDepPaths.add(depPath); } } } return pickBy((prop) => rootDepPaths.has(prop), time); } // https://github.com/pnpm/pnpm/blob/af3e5559d377870d4c3d303429b3ed1a4e64fedc/lockfile/lockfile-file/src/write.ts#L191 function refToRelative(reference, pkgName) { if (reference.startsWith('link:')) { return null; } if (reference.startsWith('file:')) { return reference; } if (!reference.includes('/') || !reference.replace(/(\([^)]+\))+$/, '').includes('/')) { return `/${pkgName}@${reference}`; } return reference; } // https://github.com/pnpm/pnpm/blob/af3e5559d377870d4c3d303429b3ed1a4e64fedc/lockfile/lockfile-file/src/write.ts#L207 function pruneTime(time, importers) { const rootDepPaths = new Set(); for (const importer of Object.values(importers)) { for (const depType of DEPENDENCIES_FIELDS) { for (let [depName, ref] of Object.entries(importer[depType] ?? {})) { let version; if (ref['version']) { version = ref['version']; } else { version = ref; } const suffixStart = version.indexOf('_'); const refWithoutPeerSuffix = suffixStart === -1 ? version : version.slice(0, suffixStart); const depPath = dpRefToRelative(refWithoutPeerSuffix, depName); if (!depPath) continue; rootDepPaths.add(depPath); } } } return pickBy((depPath) => rootDepPaths.has(depPath), time); } // https://github.com/pnpm/pnpm/blob/34bc8f48e10dc5a7d54eaa657638f8ccfb406aa4/lockfile/lockfile-file/src/lockfileFormatConverters.ts#L29 function convertToLockfileFile(lockfile, opts) { const packages = {}; const snapshots = {}; for (const [depPath, pkg] of Object.entries(lockfile.packages ?? {})) { snapshots[depPath] = pick([ 'dependencies', 'optionalDependencies', 'transitivePeerDependencies', 'optional', 'id', ], pkg); const pkgId = removePeersSuffix(depPath); if (!packages[pkgId]) { packages[pkgId] = pick([ 'resolution', 'bundledDependencies', 'cpu', 'deprecated', 'engines', 'hasBin', 'libc', 'name', 'os', 'peerDependencies', 'peerDependenciesMeta', 'version', ], pkg); } } const newLockfile = { ...lockfile, snapshots, packages, lockfileVersion: lockfile.lockfileVersion.toString(), importers: mapValues(lockfile.importers, convertProjectSnapshotToInlineSpecifiersFormat), }; return normalizeLockfile(newLockfile, opts); } // https://github.com/pnpm/pnpm/blob/34bc8f48e10dc5a7d54eaa657638f8ccfb406aa4/lockfile/lockfile-file/src/lockfileFormatConverters.ts#L68 function normalizeLockfile(lockfile, opts) { let lockfileToSave; if (!opts.forceSharedFormat && equals(Object.keys(lockfile.importers ?? {}), ['.'])) { lockfileToSave = { ...lockfile, ...lockfile.importers?.['.'], }; delete lockfileToSave.importers; for (const depType of DEPENDENCIES_FIELDS) { if (isEmpty(lockfileToSave[depType])) { delete lockfileToSave[depType]; } } if (isEmpty(lockfileToSave.packages) || lockfileToSave.packages == null) { delete lockfileToSave.packages; } if (isEmpty(lockfileToSave.snapshots) || lockfileToSave.snapshots == null) { delete lockfileToSave.snapshots; } } else { lockfileToSave = { ...lockfile, importers: mapValues(lockfile.importers ?? {}, (importer) => { const normalizedImporter = {}; if (importer.dependenciesMeta != null && !isEmpty(importer.dependenciesMeta)) { normalizedImporter.dependenciesMeta = importer.dependenciesMeta; } for (const depType of DEPENDENCIES_FIELDS) { if (!isEmpty(importer[depType] ?? {})) { normalizedImporter[depType] = importer[depType]; } } if (importer.publishDirectory) { normalizedImporter.publishDirectory = importer.publishDirectory; } return normalizedImporter; }), }; if (isEmpty(lockfileToSave.packages) || lockfileToSave.packages == null) { delete lockfileToSave.packages; } if (isEmpty(lockfileToSave.snapshots) || lockfileToSave.snapshots == null) { delete lockfileToSave.snapshots; } } // This code only handles v9 format // if (lockfileToSave.time) { // lockfileToSave.time = pruneTimeInLockfileV6(lockfileToSave.time, lockfile.importers ?? {}) // } if (lockfileToSave.overrides != null && isEmpty(lockfileToSave.overrides)) { delete lockfileToSave.overrides; } if (lockfileToSave.patchedDependencies != null && isEmpty(lockfileToSave.patchedDependencies)) { delete lockfileToSave.patchedDependencies; } if (!lockfileToSave.packageExtensionsChecksum) { delete lockfileToSave.packageExtensionsChecksum; } if (!lockfileToSave.ignoredOptionalDependencies?.length) { delete lockfileToSave.ignoredOptionalDependencies; } if (!lockfileToSave.pnpmfileChecksum) { delete lockfileToSave.pnpmfileChecksum; } return lockfileToSave; } const ROOT_KEYS = [ 'lockfileVersion', 'neverBuiltDependencies', 'onlyBuiltDependencies', 'settings', 'overrides', 'packageExtensionsChecksum', 'pnpmfileChecksum', 'patchedDependencies', 'specifiers', 'dependencies', 'optionalDependencies', 'devDependencies', 'dependenciesMeta', 'importers', 'packages', ]; const ROOT_KEYS_ORDER = Object.fromEntries(ROOT_KEYS.map((key, index) => [key, index])); // https://github.com/pnpm/pnpm/blob/af3e5559d377870d4c3d303429b3ed1a4e64fedc/lockfile/lockfile-file/src/sortLockfileKeys.ts#L60 // TODO(meeroslav): pnpm has not a more sophisticated implementation for this function. check if this becomes a bottleneck function sortLockfileKeys(lockfile) { let sortedLockfile = {}; const sortedKeys = Object.keys(lockfile).sort((a, b) => ROOT_KEYS_ORDER[a] - ROOT_KEYS_ORDER[b]); for (const key of sortedKeys) { sortedLockfile[key] = lockfile[key]; } return sortedLockfile; } /************************************************************************* * THE FOLLOWING CODE IS COPIED FROM @pnpm/dependency-path for convenience *************************************************************************/ // https://github.com/pnpm/pnpm/blob/af3e5559d377870d4c3d303429b3ed1a4e64fedc/packages/dependency-path/src/index.ts#L6 function isAbsolute(dependencyPath) { return dependencyPath[0] !== '/'; } // https://github.com/pnpm/pnpm/blob/cca56c0c6c956d036883003092ca1d11bbb700f6/packages/dependency-path/src/index.ts#L9 function indexOfPeersSuffix(depPath) { if (!depPath.endsWith(')')) return -1; let open = 1; for (let i = depPath.length - 2; i >= 0; i--) { if (depPath[i] === '(') { open--; } else if (depPath[i] === ')') { open++; } else if (!open) { return i + 1; } } return -1; } // https://github.com/pnpm/pnpm/blob/cca56c0c6c956d036883003092ca1d11bbb700f6/packages/dependency-path/src/index.ts#L29 function parseDepPath(relDepPath) { const sepIndex = indexOfPeersSuffix(relDepPath); if (sepIndex !== -1) { return { id: relDepPath.substring(0, sepIndex), peersSuffix: relDepPath.substring(sepIndex), }; } return { id: relDepPath, peersSuffix: '', }; } // https://github.com/pnpm/pnpm/blob/cca56c0c6c956d036883003092ca1d11bbb700f6/packages/dependency-path/src/index.ts#L43 function removePeersSuffix(relDepPath) { const sepIndex = indexOfPeersSuffix(relDepPath); if (sepIndex !== -1) { return relDepPath.substring(0, sepIndex); } return relDepPath; } // https://github.com/pnpm/pnpm/blob/af3e5559d377870d4c3d303429b3ed1a4e64fedc/packages/dependency-path/src/index.ts#L80 function dpRefToRelative(reference, pkgName) { if (reference.startsWith('link:')) { return null; } if (reference.startsWith('file:')) { return reference; } if (!reference.includes('/') || (reference.includes('(') && reference.lastIndexOf('/', reference.indexOf('(')) === -1)) { return `/${pkgName}/${reference}`; } return reference; } // https://github.com/pnpm/pnpm/blob/af3e5559d377870d4c3d303429b3ed1a4e64fedc/packages/dependency-path/src/index.ts#L96 function dpParse(dependencyPath) { // eslint-disable-next-line: strict-type-predicates if (typeof dependencyPath !== 'string') { throw new TypeError(`Expected \`dependencyPath\` to be of type \`string\`, got \`${ // eslint-disable-next-line: strict-type-predicates dependencyPath === null ? 'null' : typeof dependencyPath}\``); } const _isAbsolute = isAbsolute(dependencyPath); const parts = dependencyPath.split('/'); if (!_isAbsolute) parts.shift(); const host = _isAbsolute ? parts.shift() : undefined; if (parts.length === 0) return { host, isAbsolute: _isAbsolute, }; const name = parts[0].startsWith('@') ? `${parts.shift()}/${parts.shift()}` // eslint-disable-line @typescript-eslint/restrict-template-expressions : parts.shift(); let version = parts.join('/'); if (version) { let peerSepIndex; let peersSuffix; if (version.includes('(') && version.endsWith(')')) { peerSepIndex = version.indexOf('('); if (peerSepIndex !== -1) { peersSuffix = version.substring(peerSepIndex); version = version.substring(0, peerSepIndex); } } else { peerSepIndex = version.indexOf('_'); if (peerSepIndex !== -1) { peersSuffix = version.substring(peerSepIndex + 1); version = version.substring(0, peerSepIndex); } } if ((0, semver_1.valid)(version)) { return { host, isAbsolute: _isAbsolute, name, peersSuffix, version, }; } } if (!_isAbsolute) throw new Error(`${dependencyPath} is an invalid relative dependency path`); return { host, isAbsolute: _isAbsolute, }; } /******************************************************************************** * THE FOLLOWING CODE IS COPIED AND SIMPLIFIED FROM @pnpm/ramda for convenience *******************************************************************************/ // https://github.com/pnpm/ramda/blob/50c6b57110b2f3631ed8633141f12012b7768d85/source/pick.js#L22 function pick(names, obj) { var result = {}; var idx = 0; while (idx < names.length) { if (names[idx] in obj) { result[names[idx]] = obj[names[idx]]; } idx += 1; } return result; } // https://github.com/pnpm/ramda/blob/50c6b57110b2f3631ed8633141f12012b7768d85/source/pickBy.js#L24 function pickBy(test, obj) { let result = {}; for (const prop in obj) { if (test(obj[prop])) { result[prop] = obj[prop]; } } return result; } // https://github.com/pnpm/ramda/blob/50c6b57110b2f3631ed8633141f12012b7768d85/source/isEmpty.js#L28 function isEmpty(obj) { return obj != null && Object.keys(obj).length === 0; } // https://github.com/pnpm/ramda/blob/50c6b57110b2f3631ed8633141f12012b7768d85/source/omit.js#L19 function omit(names, obj) { let result = {}; let index = {}; let idx = 0; const len = names.length; while (idx < len) { index[names[idx]] = 1; idx += 1; } for (var prop in obj) { if (!index.hasOwnProperty(prop)) { result[prop] = obj[prop]; } } return result; } // This is a simplified internal implementation of the `equals` to replace complex function from Ramda function equals(a, b) { if (Array.isArray(a) && Array.isArray(b)) { return a.length === b.length && a.every((v, i) => v === b[i]); } if (typeof a === 'object' && typeof b === 'object') { return (0, file_hasher_1.hashObject)(a) === (0, file_hasher_1.hashObject)(b); } return a === b; }