From 0ab7fab76d5c092d5ccf850c8a43d067a3bc7714 Mon Sep 17 00:00:00 2001 From: Zoltan Kochan Date: Tue, 16 Mar 2021 01:52:34 +0200 Subject: [PATCH] feat(lockfile): change order of keys in the lockfile (#3244) --- .../lockfile-file/src/sortLockfileKeys.ts | 78 +++++++++++++++++++ packages/lockfile-file/src/write.ts | 23 +----- .../test/__snapshots__/write.ts.snap | 16 ++-- 3 files changed, 89 insertions(+), 28 deletions(-) create mode 100644 packages/lockfile-file/src/sortLockfileKeys.ts diff --git a/packages/lockfile-file/src/sortLockfileKeys.ts b/packages/lockfile-file/src/sortLockfileKeys.ts new file mode 100644 index 0000000000..f1a0b3d5b3 --- /dev/null +++ b/packages/lockfile-file/src/sortLockfileKeys.ts @@ -0,0 +1,78 @@ +import sortKeys from 'sort-keys' +import { LockfileFile } from './write' + +const ORDERED_KEYS = { + resolution: 1, + id: 2, + + name: 3, + version: 4, + + engines: 5, + cpu: 6, + os: 7, + + deprecated: 8, + hasBin: 9, + prepare: 10, + requiresBuild: 11, + + bundleDependencies: 12, + peerDependencies: 13, + peerDependenciesMeta: 14, + + dependencies: 15, + optionalDependencies: 16, + + transitivePeerDependencies: 17, + dev: 18, + optional: 19, +} + +const ROOT_KEYS_ORDER = { + lockfileVersion: 1, + neverBuiltDependencies: 2, + overrides: 3, + specifiers: 10, + dependencies: 11, + optionalDependencies: 12, + devDependencies: 13, + importers: 14, + packages: 15, +} + +function compareWithPriority (priority: Record, left: string, right: string) { + const leftPriority = priority[left] + const rightPriority = priority[right] + if (leftPriority && rightPriority) return leftPriority - rightPriority + if (leftPriority) return -1 + if (rightPriority) return 1 + return left.localeCompare(right) +} + +export function sortLockfileKeys (lockfile: LockfileFile) { + const compareRootKeys = compareWithPriority.bind(null, ROOT_KEYS_ORDER) + if (lockfile.importers) { + lockfile.importers = sortKeys(lockfile.importers) + for (const importerId of Object.keys(lockfile.importers)) { + lockfile.importers[importerId] = sortKeys(lockfile.importers[importerId], { + compare: compareRootKeys, + deep: true, + }) + } + } + if (lockfile.packages) { + lockfile.packages = sortKeys(lockfile.packages) + for (const pkgId of Object.keys(lockfile.packages)) { + lockfile.packages[pkgId] = sortKeys(lockfile.packages[pkgId], { + compare: compareWithPriority.bind(null, ORDERED_KEYS), + deep: true, + }) + } + } + for (const key of ['specifiers', 'dependencies', 'devDependencies', 'optionalDependencies']) { + if (!lockfile[key]) continue + lockfile[key] = sortKeys(lockfile[key]) + } + return sortKeys(lockfile, { compare: compareRootKeys }) +} diff --git a/packages/lockfile-file/src/write.ts b/packages/lockfile-file/src/write.ts index 2e05ffab8a..b3da16b888 100644 --- a/packages/lockfile-file/src/write.ts +++ b/packages/lockfile-file/src/write.ts @@ -6,9 +6,9 @@ import { WANTED_LOCKFILE } from '@pnpm/constants' import rimraf from '@zkochan/rimraf' import yaml from 'js-yaml' import * as R from 'ramda' -import sortKeys from 'sort-keys' import writeFileAtomicCB from 'write-file-atomic' import logger from './logger' +import { sortLockfileKeys } from './sortLockfileKeys' async function writeFileAtomic (filename: string, data: string) { return new Promise((resolve, reject) => writeFileAtomicCB(filename, data, {}, (err?: Error) => err ? reject(err) : resolve())) @@ -63,26 +63,9 @@ async function writeLockfile ( return writeFileAtomic(lockfilePath, yamlDoc) } -const ORDERED_KEYS = { - resolution: 1, - engines: 2, - os: 3, - cpu: 4, -} - function yamlStringify (lockfile: Lockfile, forceSharedFormat: boolean) { let normalizedLockfile = normalizeLockfile(lockfile, forceSharedFormat) - normalizedLockfile = sortKeys(normalizedLockfile, { - compare: (left, right) => { - const leftPriority = ORDERED_KEYS[left] - const rightPriority = ORDERED_KEYS[right] - if (leftPriority && rightPriority) return leftPriority - rightPriority - if (leftPriority) return -1 - if (rightPriority) return 1 - return left.localeCompare(right) - }, - deep: true, - }) + normalizedLockfile = sortLockfileKeys(normalizedLockfile) return yaml.dump(normalizedLockfile, LOCKFILE_YAML_FORMAT) } @@ -90,7 +73,7 @@ function isEmptyLockfile (lockfile: Lockfile) { return R.values(lockfile.importers).every((importer) => R.isEmpty(importer.specifiers ?? {}) && R.isEmpty(importer.dependencies ?? {})) } -type LockfileFile = Omit & Partial & Partial> +export type LockfileFile = Omit & Partial & Partial> export function normalizeLockfile (lockfile: Lockfile, forceSharedFormat: boolean) { let lockfileToSave!: LockfileFile diff --git a/packages/lockfile-file/test/__snapshots__/write.ts.snap b/packages/lockfile-file/test/__snapshots__/write.ts.snap index 5a2d11a480..72eba2f26c 100644 --- a/packages/lockfile-file/test/__snapshots__/write.ts.snap +++ b/packages/lockfile-file/test/__snapshots__/write.ts.snap @@ -1,19 +1,23 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`writeLockfiles() 1`] = ` -"dependencies: +"lockfileVersion: 5.3 + +specifiers: + is-negative: ^1.0.0 + is-positive: ^1.0.0 + +dependencies: is-negative: 1.0.0 is-positive: 1.0.0 -lockfileVersion: 5.3 - packages: /is-negative/1.0.0: resolution: {integrity: sha1-ChbBDewTLAqLCzb793Fo5VDvg/g=} engines: {node: '>=10'} - os: [darwin] cpu: [x86] + os: [darwin] dependencies: is-positive: 2.0.0 @@ -22,9 +26,5 @@ packages: /is-positive/2.0.0: resolution: {integrity: sha1-ChbBDewTLAqLCzb793Fo5VDvg/g=} - -specifiers: - is-negative: ^1.0.0 - is-positive: ^1.0.0 " `;