nx
Version:
855 lines (854 loc) • 33.6 kB
JavaScript
/**
* 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;
}
;