mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-23 23:29:17 -05:00
refactor: lockfile-file (#7655)
This commit is contained in:
23
__fixtures__/has-major-outdated-deps/node_modules/.pnpm/lock.yaml
generated
vendored
23
__fixtures__/has-major-outdated-deps/node_modules/.pnpm/lock.yaml
generated
vendored
@@ -1,21 +1,28 @@
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
dependencies:
|
||||
is-negative: 1.0.0
|
||||
is-negative:
|
||||
version: 1.0.0
|
||||
specifier: 1.0.0
|
||||
|
||||
devDependencies:
|
||||
is-positive: 2.0.0
|
||||
lockfileVersion: 5.1
|
||||
is-positive:
|
||||
version: 2.0.0
|
||||
specifier: 2.0.0
|
||||
|
||||
packages:
|
||||
/is-negative/1.0.0:
|
||||
|
||||
/is-negative@1.0.0:
|
||||
dev: false
|
||||
engines:
|
||||
node: '>=0.10.0'
|
||||
resolution:
|
||||
integrity: sha1-clmHeoPIAKwxkd17nZ+80PdS1P4=
|
||||
/is-positive/2.0.0:
|
||||
|
||||
/is-positive@2.0.0:
|
||||
dev: true
|
||||
engines:
|
||||
node: '>=0.10.0'
|
||||
resolution:
|
||||
integrity: sha1-sU8GvS24EK5sixJ0HRNr+u8Nh70=
|
||||
specifiers:
|
||||
is-negative: 1.0.0
|
||||
is-positive: 2.0.0
|
||||
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
lockfileVersion: '6.0'
|
||||
|
||||
dependencies:
|
||||
is-negative:
|
||||
version: 1.0.0
|
||||
specifier: 1.0.0
|
||||
|
||||
devDependencies:
|
||||
is-positive:
|
||||
version: 2.0.0
|
||||
specifier: 2.0.0
|
||||
|
||||
packages:
|
||||
|
||||
/is-negative@1.0.0:
|
||||
dev: false
|
||||
engines:
|
||||
node: '>=0.10.0'
|
||||
resolution:
|
||||
integrity: sha512-1aKMsFUc7vYQGzt//8zhkjRWPoYkajY/I5MJEvrc0pDoHXrW7n5ri8DYxhy3rR+Dk0QFl7GjHHsZU1sppQrWtw==
|
||||
|
||||
/is-positive@2.0.0:
|
||||
dev: true
|
||||
engines:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import path from 'path'
|
||||
import { assertStore } from '@pnpm/assert-store'
|
||||
import { WANTED_LOCKFILE } from '@pnpm/constants'
|
||||
import { type LockfileV6 as Lockfile, type ProjectSnapshotV6 as ProjectSnapshot } from '@pnpm/lockfile-types'
|
||||
import { type LockfileFile } from '@pnpm/lockfile-types'
|
||||
import { type Modules, readModulesManifest } from '@pnpm/modules-yaml'
|
||||
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
|
||||
import readYamlFile from 'read-yaml-file'
|
||||
@@ -11,8 +11,6 @@ import isExecutable from './isExecutable'
|
||||
|
||||
export { isExecutable, type Modules }
|
||||
|
||||
export type RawLockfile = Lockfile & Partial<ProjectSnapshot>
|
||||
|
||||
export interface Project {
|
||||
// eslint-disable-next-line
|
||||
requireModule: (moduleName: string) => any
|
||||
@@ -32,14 +30,14 @@ export interface Project {
|
||||
*
|
||||
* https://github.com/microsoft/TypeScript/pull/32695 might help with this.
|
||||
*/
|
||||
readCurrentLockfile: () => Promise<Required<RawLockfile>>
|
||||
readCurrentLockfile: () => Promise<Required<LockfileFile>>
|
||||
readModulesManifest: () => Promise<Modules | null>
|
||||
/**
|
||||
* TODO: Remove the `Required<T>` cast.
|
||||
*
|
||||
* https://github.com/microsoft/TypeScript/pull/32695 might help with this.
|
||||
*/
|
||||
readLockfile: (lockfileName?: string) => Promise<Required<RawLockfile>>
|
||||
readLockfile: (lockfileName?: string) => Promise<Required<LockfileFile>>
|
||||
writePackageJson: (pkgJson: object) => Promise<void>
|
||||
}
|
||||
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
import type { Lockfile, ProjectSnapshot, ResolvedDependencies } from '@pnpm/lockfile-types'
|
||||
import {
|
||||
INLINE_SPECIFIERS_FORMAT_LOCKFILE_VERSION_SUFFIX,
|
||||
type InlineSpecifiersLockfile,
|
||||
type InlineSpecifiersProjectSnapshot,
|
||||
type InlineSpecifiersResolvedDependencies,
|
||||
} from './InlineSpecifiersLockfile'
|
||||
|
||||
export function isExperimentalInlineSpecifiersFormat (
|
||||
lockfile: InlineSpecifiersLockfile | Lockfile
|
||||
): lockfile is InlineSpecifiersLockfile {
|
||||
const { lockfileVersion } = lockfile
|
||||
return lockfileVersion.toString().startsWith('6.') || typeof lockfileVersion === 'string' && lockfileVersion.endsWith(INLINE_SPECIFIERS_FORMAT_LOCKFILE_VERSION_SUFFIX)
|
||||
}
|
||||
|
||||
export function convertToInlineSpecifiersFormat (lockfile: Lockfile): InlineSpecifiersLockfile {
|
||||
const newLockfile = {
|
||||
...lockfile,
|
||||
lockfileVersion: lockfile.lockfileVersion.toString().startsWith('6.')
|
||||
? lockfile.lockfileVersion.toString()
|
||||
: (
|
||||
lockfile.lockfileVersion.toString().endsWith(INLINE_SPECIFIERS_FORMAT_LOCKFILE_VERSION_SUFFIX)
|
||||
? lockfile.lockfileVersion.toString()
|
||||
: `${lockfile.lockfileVersion}${INLINE_SPECIFIERS_FORMAT_LOCKFILE_VERSION_SUFFIX}`
|
||||
),
|
||||
importers: mapValues(lockfile.importers, convertProjectSnapshotToInlineSpecifiersFormat),
|
||||
}
|
||||
return newLockfile
|
||||
}
|
||||
|
||||
export function revertFromInlineSpecifiersFormatIfNecessary (lockfile: Lockfile | InlineSpecifiersLockfile): Lockfile {
|
||||
return isExperimentalInlineSpecifiersFormat(lockfile)
|
||||
? revertFromInlineSpecifiersFormat(lockfile)
|
||||
: lockfile
|
||||
}
|
||||
|
||||
export function revertFromInlineSpecifiersFormat (lockfile: InlineSpecifiersLockfile): Lockfile {
|
||||
const { lockfileVersion, importers, ...rest } = lockfile
|
||||
|
||||
const originalVersionStr = lockfileVersion.replace(INLINE_SPECIFIERS_FORMAT_LOCKFILE_VERSION_SUFFIX, '')
|
||||
const originalVersion = Number(originalVersionStr)
|
||||
if (isNaN(originalVersion)) {
|
||||
throw new Error(`Unable to revert lockfile from inline specifiers format. Invalid version parsed: ${originalVersionStr}`)
|
||||
}
|
||||
|
||||
const newLockfile = {
|
||||
...rest,
|
||||
lockfileVersion: lockfileVersion.endsWith(INLINE_SPECIFIERS_FORMAT_LOCKFILE_VERSION_SUFFIX) ? originalVersion : lockfileVersion,
|
||||
importers: mapValues(importers, revertProjectSnapshot),
|
||||
}
|
||||
return newLockfile
|
||||
}
|
||||
|
||||
function convertProjectSnapshotToInlineSpecifiersFormat (
|
||||
projectSnapshot: ProjectSnapshot
|
||||
): InlineSpecifiersProjectSnapshot {
|
||||
const { specifiers, ...rest } = projectSnapshot
|
||||
const convertBlock = (block?: ResolvedDependencies) =>
|
||||
block != null
|
||||
? convertResolvedDependenciesToInlineSpecifiersFormat(block, { specifiers })
|
||||
: block
|
||||
return {
|
||||
...rest,
|
||||
dependencies: convertBlock(projectSnapshot.dependencies),
|
||||
optionalDependencies: convertBlock(projectSnapshot.optionalDependencies),
|
||||
devDependencies: convertBlock(projectSnapshot.devDependencies),
|
||||
}
|
||||
}
|
||||
|
||||
function convertResolvedDependenciesToInlineSpecifiersFormat (
|
||||
resolvedDependencies: ResolvedDependencies,
|
||||
{ specifiers }: { specifiers: ResolvedDependencies }
|
||||
): InlineSpecifiersResolvedDependencies {
|
||||
return mapValues(resolvedDependencies, (version, depName) => ({
|
||||
specifier: specifiers[depName],
|
||||
version,
|
||||
}))
|
||||
}
|
||||
|
||||
function revertProjectSnapshot (from: InlineSpecifiersProjectSnapshot): ProjectSnapshot {
|
||||
const specifiers: ResolvedDependencies = {}
|
||||
|
||||
function moveSpecifiers (from: InlineSpecifiersResolvedDependencies): ResolvedDependencies {
|
||||
const resolvedDependencies: 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,
|
||||
}
|
||||
}
|
||||
|
||||
function mapValues<T, U> (obj: Record<string, T>, mapper: (val: T, key: string) => U): Record<string, U> {
|
||||
const result: Record<string, U> = {}
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
result[key] = mapper(value, key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
import { type Lockfile } from '@pnpm/lockfile-types'
|
||||
import { type Lockfile, type LockfileFile } from '@pnpm/lockfile-types'
|
||||
import { mergeLockfileChanges } from '@pnpm/merge-lockfile-changes'
|
||||
import yaml from 'js-yaml'
|
||||
import { revertFromInlineSpecifiersFormatIfNecessary } from './experiments/inlineSpecifiersLockfileConverters'
|
||||
import { convertToLockfileObject } from './lockfileFormatConverters'
|
||||
|
||||
const MERGE_CONFLICT_PARENT = '|||||||'
|
||||
const MERGE_CONFLICT_END = '>>>>>>>'
|
||||
const MERGE_CONFLICT_THEIRS = '======='
|
||||
const MERGE_CONFLICT_OURS = '<<<<<<<'
|
||||
|
||||
export function autofixMergeConflicts (fileContent: string) {
|
||||
export function autofixMergeConflicts (fileContent: string): Lockfile {
|
||||
const { ours, theirs } = parseMergeFile(fileContent)
|
||||
return mergeLockfileChanges(
|
||||
revertFromInlineSpecifiersFormatIfNecessary(yaml.load(ours) as Lockfile),
|
||||
revertFromInlineSpecifiersFormatIfNecessary(yaml.load(theirs) as Lockfile)
|
||||
convertToLockfileObject(yaml.load(ours) as LockfileFile),
|
||||
convertToLockfileObject(yaml.load(theirs) as LockfileFile)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
224
lockfile/lockfile-file/src/lockfileFormatConverters.ts
Normal file
224
lockfile/lockfile-file/src/lockfileFormatConverters.ts
Normal file
@@ -0,0 +1,224 @@
|
||||
import {
|
||||
type Lockfile,
|
||||
type ProjectSnapshot,
|
||||
type ResolvedDependencies,
|
||||
type LockfileFile,
|
||||
type InlineSpecifiersLockfile,
|
||||
type InlineSpecifiersProjectSnapshot,
|
||||
type InlineSpecifiersResolvedDependencies,
|
||||
} from '@pnpm/lockfile-types'
|
||||
import { DEPENDENCIES_FIELDS } from '@pnpm/types'
|
||||
import equals from 'ramda/src/equals'
|
||||
import isEmpty from 'ramda/src/isEmpty'
|
||||
import _mapValues from 'ramda/src/map'
|
||||
import pickBy from 'ramda/src/pickBy'
|
||||
|
||||
export interface NormalizeLockfileOpts {
|
||||
forceSharedFormat: boolean
|
||||
}
|
||||
|
||||
export function convertToLockfileFile (lockfile: Lockfile, opts: NormalizeLockfileOpts): LockfileFile {
|
||||
const newLockfile = {
|
||||
...lockfile,
|
||||
lockfileVersion: lockfile.lockfileVersion.toString(),
|
||||
importers: mapValues(lockfile.importers, convertProjectSnapshotToInlineSpecifiersFormat),
|
||||
}
|
||||
return normalizeLockfile(newLockfile, opts)
|
||||
}
|
||||
|
||||
function normalizeLockfile (lockfile: InlineSpecifiersLockfile, opts: NormalizeLockfileOpts): LockfileFile {
|
||||
let lockfileToSave!: LockfileFile
|
||||
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
|
||||
}
|
||||
} else {
|
||||
lockfileToSave = {
|
||||
...lockfile,
|
||||
importers: _mapValues((importer) => {
|
||||
const normalizedImporter: Partial<InlineSpecifiersProjectSnapshot> = {}
|
||||
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 as InlineSpecifiersProjectSnapshot
|
||||
}, lockfile.importers ?? {}),
|
||||
}
|
||||
if (isEmpty(lockfileToSave.packages) || (lockfileToSave.packages == null)) {
|
||||
delete lockfileToSave.packages
|
||||
}
|
||||
}
|
||||
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.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
|
||||
}
|
||||
|
||||
function pruneTimeInLockfileV6 (time: Record<string, string>, importers: Record<string, InlineSpecifiersProjectSnapshot>): Record<string, string> {
|
||||
const rootDepPaths = new Set<string>()
|
||||
for (const importer of Object.values(importers)) {
|
||||
for (const depType of DEPENDENCIES_FIELDS) {
|
||||
for (const [depName, ref] of Object.entries(importer[depType] ?? {})) {
|
||||
const suffixStart = ref.version.indexOf('(')
|
||||
const refWithoutPeerSuffix = suffixStart === -1 ? ref.version : ref.version.slice(0, suffixStart)
|
||||
const depPath = refToRelative(refWithoutPeerSuffix, depName)
|
||||
if (!depPath) continue
|
||||
rootDepPaths.add(depPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
return pickBy((_, depPath) => rootDepPaths.has(depPath), time)
|
||||
}
|
||||
|
||||
function refToRelative (
|
||||
reference: string,
|
||||
pkgName: string
|
||||
): string | null {
|
||||
if (reference.startsWith('link:')) {
|
||||
return null
|
||||
}
|
||||
if (reference.startsWith('file:')) {
|
||||
return reference
|
||||
}
|
||||
if (!reference.includes('/') || !reference.replace(/(\([^)]+\))+$/, '').includes('/')) {
|
||||
return `/${pkgName}@${reference}`
|
||||
}
|
||||
return reference
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverts changes from the "forceSharedFormat" write option if necessary.
|
||||
*/
|
||||
function convertFromLockfileFileMutable (lockfileFile: LockfileFile): InlineSpecifiersLockfile {
|
||||
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]
|
||||
}
|
||||
}
|
||||
}
|
||||
return lockfileFile as InlineSpecifiersLockfile
|
||||
}
|
||||
|
||||
export function convertToLockfileObject (lockfile: LockfileFile): Lockfile {
|
||||
const { importers, ...rest } = convertFromLockfileFileMutable(lockfile)
|
||||
|
||||
const newLockfile = {
|
||||
...rest,
|
||||
importers: mapValues(importers ?? {}, revertProjectSnapshot),
|
||||
}
|
||||
return newLockfile
|
||||
}
|
||||
|
||||
function convertProjectSnapshotToInlineSpecifiersFormat (
|
||||
projectSnapshot: ProjectSnapshot
|
||||
): InlineSpecifiersProjectSnapshot {
|
||||
const { specifiers, ...rest } = projectSnapshot
|
||||
const convertBlock = (block?: ResolvedDependencies) =>
|
||||
block != null
|
||||
? convertResolvedDependenciesToInlineSpecifiersFormat(block, { specifiers })
|
||||
: block
|
||||
return {
|
||||
...rest,
|
||||
dependencies: convertBlock(projectSnapshot.dependencies ?? {}),
|
||||
optionalDependencies: convertBlock(projectSnapshot.optionalDependencies ?? {}),
|
||||
devDependencies: convertBlock(projectSnapshot.devDependencies ?? {}),
|
||||
}
|
||||
}
|
||||
|
||||
function convertResolvedDependenciesToInlineSpecifiersFormat (
|
||||
resolvedDependencies: ResolvedDependencies,
|
||||
{ specifiers }: { specifiers: ResolvedDependencies }
|
||||
): InlineSpecifiersResolvedDependencies {
|
||||
return mapValues(resolvedDependencies, (version, depName) => ({
|
||||
specifier: specifiers[depName],
|
||||
version,
|
||||
}))
|
||||
}
|
||||
|
||||
function revertProjectSnapshot (from: InlineSpecifiersProjectSnapshot): ProjectSnapshot {
|
||||
const specifiers: ResolvedDependencies = {}
|
||||
|
||||
function moveSpecifiers (from: InlineSpecifiersResolvedDependencies): ResolvedDependencies {
|
||||
const resolvedDependencies: 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,
|
||||
}
|
||||
}
|
||||
|
||||
function mapValues<T, U> (obj: Record<string, T>, mapper: (val: T, key: string) => U): Record<string, U> {
|
||||
const result: Record<string, U> = {}
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
result[key] = mapper(value, key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
import { PnpmError } from '@pnpm/error'
|
||||
import { mergeLockfileChanges } from '@pnpm/merge-lockfile-changes'
|
||||
import { type Lockfile } from '@pnpm/lockfile-types'
|
||||
import { DEPENDENCIES_FIELDS } from '@pnpm/types'
|
||||
import comverToSemver from 'comver-to-semver'
|
||||
import yaml from 'js-yaml'
|
||||
import semver from 'semver'
|
||||
@@ -15,10 +14,9 @@ import stripBom from 'strip-bom'
|
||||
import { LockfileBreakingChangeError } from './errors'
|
||||
import { autofixMergeConflicts, isDiff } from './gitMergeFile'
|
||||
import { lockfileLogger as logger } from './logger'
|
||||
import { type LockfileFile } from './write'
|
||||
import { getWantedLockfileName } from './lockfileName'
|
||||
import { getGitBranchLockfileNames } from './gitBranchLockfile'
|
||||
import { revertFromInlineSpecifiersFormatIfNecessary } from './experiments/inlineSpecifiersLockfileConverters'
|
||||
import { convertToLockfileObject } from './lockfileFormatConverters'
|
||||
|
||||
export async function readCurrentLockfile (
|
||||
virtualStoreDir: string,
|
||||
@@ -88,14 +86,14 @@ async function _read (
|
||||
let lockfile: Lockfile
|
||||
let hadConflicts!: boolean
|
||||
try {
|
||||
lockfile = revertFromInlineSpecifiersFormatIfNecessary(convertFromLockfileFileMutable(yaml.load(lockfileRawContent) as Lockfile))
|
||||
lockfile = convertToLockfileObject(yaml.load(lockfileRawContent) as any) // eslint-disable-line
|
||||
hadConflicts = false
|
||||
} catch (err: any) { // eslint-disable-line
|
||||
if (!opts.autofixMergeConflicts || !isDiff(lockfileRawContent)) {
|
||||
throw new PnpmError('BROKEN_LOCKFILE', `The lockfile at "${lockfilePath}" is broken: ${err.message as string}`)
|
||||
}
|
||||
hadConflicts = true
|
||||
lockfile = convertFromLockfileFileMutable(autofixMergeConflicts(lockfileRawContent))
|
||||
lockfile = autofixMergeConflicts(lockfileRawContent)
|
||||
logger.info({
|
||||
message: `Merge conflict detected in ${WANTED_LOCKFILE} and successfully merged`,
|
||||
prefix,
|
||||
@@ -235,26 +233,3 @@ async function _readGitBranchLockfiles (
|
||||
|
||||
return Promise.all(files.map((file) => _read(path.join(lockfileDir, file), prefix, opts)))
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverts changes from the "forceSharedFormat" write option if necessary.
|
||||
*/
|
||||
function convertFromLockfileFileMutable (lockfileFile: LockfileFile): Lockfile {
|
||||
if (typeof lockfileFile?.['importers'] === 'undefined') {
|
||||
lockfileFile.importers = {
|
||||
'.': {
|
||||
specifiers: lockfileFile['specifiers'] ?? {},
|
||||
dependenciesMeta: lockfileFile['dependenciesMeta'],
|
||||
publishDirectory: lockfileFile['publishDirectory'],
|
||||
},
|
||||
}
|
||||
delete lockfileFile.specifiers
|
||||
for (const depType of DEPENDENCIES_FIELDS) {
|
||||
if (lockfileFile[depType] != null) {
|
||||
lockfileFile.importers['.'][depType] = lockfileFile[depType]
|
||||
delete lockfileFile[depType]
|
||||
}
|
||||
}
|
||||
}
|
||||
return lockfileFile as Lockfile
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { lexCompare } from '@pnpm/util.lex-comparator'
|
||||
import sortKeys from 'sort-keys'
|
||||
import { type LockfileFile } from './write'
|
||||
import { type LockfileFile } from '@pnpm/lockfile-types'
|
||||
|
||||
const ORDERED_KEYS = {
|
||||
resolution: 1,
|
||||
@@ -78,7 +78,7 @@ export function sortLockfileKeys (lockfile: LockfileFile) {
|
||||
})
|
||||
}
|
||||
}
|
||||
for (const key of ['specifiers', 'dependencies', 'devDependencies', 'optionalDependencies', 'time', 'patchedDependencies'] as const) {
|
||||
for (const key of ['dependencies', 'devDependencies', 'optionalDependencies', 'time', 'patchedDependencies'] as const) {
|
||||
if (!lockfile[key]) continue
|
||||
lockfile[key] = sortKeys<any>(lockfile[key]) // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
}
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
import { promises as fs } from 'fs'
|
||||
import path from 'path'
|
||||
import { DEPENDENCIES_FIELDS } from '@pnpm/types'
|
||||
import { type Lockfile, type ProjectSnapshot } from '@pnpm/lockfile-types'
|
||||
import { type Lockfile, type LockfileFile } from '@pnpm/lockfile-types'
|
||||
import { WANTED_LOCKFILE } from '@pnpm/constants'
|
||||
import rimraf from '@zkochan/rimraf'
|
||||
import yaml from 'js-yaml'
|
||||
import equals from 'ramda/src/equals'
|
||||
import pickBy from 'ramda/src/pickBy'
|
||||
import isEmpty from 'ramda/src/isEmpty'
|
||||
import mapValues from 'ramda/src/map'
|
||||
import writeFileAtomicCB from 'write-file-atomic'
|
||||
import { lockfileLogger as logger } from './logger'
|
||||
import { sortLockfileKeys } from './sortLockfileKeys'
|
||||
import { getWantedLockfileName } from './lockfileName'
|
||||
import { convertToInlineSpecifiersFormat } from './experiments/inlineSpecifiersLockfileConverters'
|
||||
import { convertToLockfileFile } from './lockfileFormatConverters'
|
||||
|
||||
async function writeFileAtomic (filename: string, data: string) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
@@ -72,137 +68,24 @@ async function writeLockfile (
|
||||
) {
|
||||
const lockfilePath = path.join(pkgPath, lockfileFilename)
|
||||
|
||||
const isLockfileV6 = wantedLockfile['lockfileVersion'].toString().startsWith('6.')
|
||||
const lockfileToStringify = isLockfileV6
|
||||
? convertToInlineSpecifiersFormat(wantedLockfile) as unknown as Lockfile
|
||||
: wantedLockfile
|
||||
|
||||
const yamlDoc = yamlStringify(lockfileToStringify, {
|
||||
const lockfileToStringify = convertToLockfileFile(wantedLockfile, {
|
||||
forceSharedFormat: opts?.forceSharedFormat === true,
|
||||
includeEmptySpecifiersField: !isLockfileV6,
|
||||
})
|
||||
|
||||
const yamlDoc = yamlStringify(lockfileToStringify)
|
||||
|
||||
return writeFileAtomic(lockfilePath, yamlDoc)
|
||||
}
|
||||
|
||||
function yamlStringify (lockfile: Lockfile, opts: NormalizeLockfileOpts) {
|
||||
let normalizedLockfile = normalizeLockfile(lockfile, opts)
|
||||
normalizedLockfile = sortLockfileKeys(normalizedLockfile)
|
||||
return yaml.dump(normalizedLockfile, LOCKFILE_YAML_FORMAT)
|
||||
function yamlStringify (lockfile: LockfileFile) {
|
||||
const sortedLockfile = sortLockfileKeys(lockfile)
|
||||
return yaml.dump(sortedLockfile, LOCKFILE_YAML_FORMAT)
|
||||
}
|
||||
|
||||
export function isEmptyLockfile (lockfile: Lockfile) {
|
||||
return Object.values(lockfile.importers).every((importer) => isEmpty(importer.specifiers ?? {}) && isEmpty(importer.dependencies ?? {}))
|
||||
}
|
||||
|
||||
export type LockfileFile = Omit<Lockfile, 'importers'> & Partial<ProjectSnapshot> & Partial<Pick<Lockfile, 'importers'>>
|
||||
|
||||
export interface NormalizeLockfileOpts {
|
||||
forceSharedFormat: boolean
|
||||
includeEmptySpecifiersField: boolean
|
||||
}
|
||||
|
||||
export function normalizeLockfile (lockfile: Lockfile, opts: NormalizeLockfileOpts) {
|
||||
let lockfileToSave!: LockfileFile
|
||||
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
|
||||
}
|
||||
} else {
|
||||
lockfileToSave = {
|
||||
...lockfile,
|
||||
importers: mapValues((importer) => {
|
||||
const normalizedImporter: Partial<ProjectSnapshot> = {}
|
||||
if (!isEmpty(importer.specifiers ?? {}) || opts.includeEmptySpecifiersField) {
|
||||
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 as ProjectSnapshot
|
||||
}, lockfile.importers),
|
||||
}
|
||||
if (isEmpty(lockfileToSave.packages) || (lockfileToSave.packages == null)) {
|
||||
delete lockfileToSave.packages
|
||||
}
|
||||
}
|
||||
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.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
|
||||
}
|
||||
|
||||
function pruneTimeInLockfileV6 (time: Record<string, string>, importers: Record<string, ProjectSnapshot>): Record<string, string> {
|
||||
const rootDepPaths = new Set<string>()
|
||||
for (const importer of Object.values(importers)) {
|
||||
for (const depType of DEPENDENCIES_FIELDS) {
|
||||
for (let [depName, ref] of Object.entries(importer[depType] ?? {})) {
|
||||
// @ts-expect-error
|
||||
if (ref['version']) ref = ref['version']
|
||||
const suffixStart = ref.indexOf('(')
|
||||
const refWithoutPeerSuffix = suffixStart === -1 ? ref : ref.slice(0, suffixStart)
|
||||
const depPath = refToRelative(refWithoutPeerSuffix, depName)
|
||||
if (!depPath) continue
|
||||
rootDepPaths.add(depPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
return pickBy((_, depPath) => rootDepPaths.has(depPath), time)
|
||||
}
|
||||
|
||||
function refToRelative (
|
||||
reference: string,
|
||||
pkgName: string
|
||||
): string | null {
|
||||
if (reference.startsWith('link:')) {
|
||||
return null
|
||||
}
|
||||
if (reference.startsWith('file:')) {
|
||||
return reference
|
||||
}
|
||||
if (!reference.includes('/') || !reference.replace(/(\([^)]+\))+$/, '').includes('/')) {
|
||||
return `/${pkgName}@${reference}`
|
||||
}
|
||||
return reference
|
||||
}
|
||||
|
||||
export async function writeLockfiles (
|
||||
opts: {
|
||||
forceSharedFormat?: boolean
|
||||
@@ -219,15 +102,11 @@ export async function writeLockfiles (
|
||||
const currentLockfilePath = path.join(opts.currentLockfileDir, 'lock.yaml')
|
||||
|
||||
const forceSharedFormat = opts?.forceSharedFormat === true
|
||||
const isLockfileV6 = opts.wantedLockfile.lockfileVersion.toString().startsWith('6.')
|
||||
const wantedLockfileToStringify = isLockfileV6
|
||||
? convertToInlineSpecifiersFormat(opts.wantedLockfile) as unknown as Lockfile
|
||||
: opts.wantedLockfile
|
||||
const normalizeOpts = {
|
||||
forceSharedFormat,
|
||||
includeEmptySpecifiersField: !isLockfileV6,
|
||||
}
|
||||
const yamlDoc = yamlStringify(wantedLockfileToStringify, normalizeOpts)
|
||||
const wantedLockfileToStringify = convertToLockfileFile(opts.wantedLockfile, normalizeOpts)
|
||||
const yamlDoc = yamlStringify(wantedLockfileToStringify)
|
||||
|
||||
// in most cases the `pnpm-lock.yaml` and `node_modules/.pnpm-lock.yaml` are equal
|
||||
// in those cases the YAML document can be stringified only once for both files
|
||||
@@ -252,10 +131,8 @@ export async function writeLockfiles (
|
||||
prefix: opts.wantedLockfileDir,
|
||||
})
|
||||
|
||||
const currentLockfileToStringify = opts.wantedLockfile.lockfileVersion.toString().startsWith('6.')
|
||||
? convertToInlineSpecifiersFormat(opts.currentLockfile) as unknown as Lockfile
|
||||
: opts.currentLockfile
|
||||
const currentYamlDoc = yamlStringify(currentLockfileToStringify, normalizeOpts)
|
||||
const currentLockfileToStringify = convertToLockfileFile(opts.currentLockfile, normalizeOpts)
|
||||
const currentYamlDoc = yamlStringify(currentLockfileToStringify)
|
||||
|
||||
await Promise.all([
|
||||
writeFileAtomic(wantedLockfilePath, yamlDoc),
|
||||
|
||||
8
lockfile/lockfile-file/test/fixtures/2/node_modules/.pnpm/lock.yaml
generated
vendored
8
lockfile/lockfile-file/test/fixtures/2/node_modules/.pnpm/lock.yaml
generated
vendored
@@ -1,6 +1,8 @@
|
||||
lockfileVersion: 3
|
||||
specifiers:
|
||||
foo: '1'
|
||||
lockfileVersion: '6.0'
|
||||
dependencies:
|
||||
foo:
|
||||
version: '1.0.0'
|
||||
specifier: '1'
|
||||
dependenciesMeta:
|
||||
foo:
|
||||
injected: true
|
||||
|
||||
8
lockfile/lockfile-file/test/fixtures/2/pnpm-lock.yaml
generated
vendored
8
lockfile/lockfile-file/test/fixtures/2/pnpm-lock.yaml
generated
vendored
@@ -1,6 +1,8 @@
|
||||
lockfileVersion: 3
|
||||
specifiers:
|
||||
foo: '1'
|
||||
lockfileVersion: '6.0'
|
||||
dependencies:
|
||||
foo:
|
||||
version: '1.0.0'
|
||||
specifier: '1'
|
||||
dependenciesMeta:
|
||||
foo:
|
||||
injected: true
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
lockfileVersion: 5.3
|
||||
lockfileVersion: '6.0'
|
||||
|
||||
specifiers:
|
||||
is-positive: '2.0.0'
|
||||
dependencies:
|
||||
is-positive:
|
||||
version: '2.0.0'
|
||||
specifier: '2.0.0'
|
||||
|
||||
packages:
|
||||
/is-positive/2.0.0:
|
||||
/is-positive@2.0.0:
|
||||
resolution: {integrity: 'sha1-ChbBDewTLAqLCzb793Fo5VDvg/g='}
|
||||
|
||||
|
||||
12
lockfile/lockfile-file/test/fixtures/6/pnpm-lock.yaml
generated
vendored
12
lockfile/lockfile-file/test/fixtures/6/pnpm-lock.yaml
generated
vendored
@@ -1,8 +1,10 @@
|
||||
lockfileVersion: 5.3
|
||||
lockfileVersion: '6.0'
|
||||
|
||||
specifiers:
|
||||
is-positive: '1.0.0'
|
||||
dependencies:
|
||||
is-positive:
|
||||
version: '1.0.0'
|
||||
specifier: '1.0.0'
|
||||
|
||||
packages:
|
||||
/is-positive/1.0.0:
|
||||
resolution: {integrity: 'sha1-ChbBDewTLAqLCzb793Fo5VDvg/g='}
|
||||
/is-positive@1.0.0:
|
||||
resolution: {integrity: 'sha1-ChbBDewTLAqLCzb793Fo5VDvg/g='}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { convertToInlineSpecifiersFormat, revertFromInlineSpecifiersFormat } from '../lib/experiments/inlineSpecifiersLockfileConverters'
|
||||
import { convertToLockfileFile, convertToLockfileObject } from '../lib/lockfileFormatConverters'
|
||||
|
||||
test('convertToInlineSpecifiersFormat()', () => {
|
||||
test('convertToLockfileFile()', () => {
|
||||
const lockfileV5 = {
|
||||
lockfileVersion: '6.0',
|
||||
importers: {
|
||||
@@ -81,11 +81,11 @@ test('convertToInlineSpecifiersFormat()', () => {
|
||||
},
|
||||
},
|
||||
}
|
||||
expect(convertToInlineSpecifiersFormat(lockfileV5)).toEqual(lockfileV6)
|
||||
expect(revertFromInlineSpecifiersFormat(lockfileV6)).toEqual(lockfileV5)
|
||||
expect(convertToLockfileFile(lockfileV5, { forceSharedFormat: false })).toEqual(lockfileV6)
|
||||
expect(convertToLockfileObject(lockfileV6)).toEqual(lockfileV5)
|
||||
})
|
||||
|
||||
test('convertToInlineSpecifiersFormat() with lockfile v6', () => {
|
||||
test('convertToLockfileFile() with lockfile v6', () => {
|
||||
const lockfileV5 = {
|
||||
lockfileVersion: '6.0',
|
||||
importers: {
|
||||
@@ -166,6 +166,6 @@ test('convertToInlineSpecifiersFormat() with lockfile v6', () => {
|
||||
},
|
||||
},
|
||||
}
|
||||
expect(convertToInlineSpecifiersFormat(lockfileV5)).toEqual(lockfileV6)
|
||||
expect(revertFromInlineSpecifiersFormat(lockfileV6)).toEqual(lockfileV5)
|
||||
expect(convertToLockfileFile(lockfileV5, { forceSharedFormat: false })).toEqual(lockfileV6)
|
||||
expect(convertToLockfileObject(lockfileV6)).toEqual(lockfileV5)
|
||||
})
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { LOCKFILE_VERSION } from '@pnpm/constants'
|
||||
import { normalizeLockfile } from '../lib/write'
|
||||
import { convertToLockfileFile } from '../lib/lockfileFormatConverters'
|
||||
|
||||
test('empty overrides and neverBuiltDependencies are removed during lockfile normalization', () => {
|
||||
expect(normalizeLockfile({
|
||||
expect(convertToLockfileFile({
|
||||
lockfileVersion: LOCKFILE_VERSION,
|
||||
// but this should be preserved.
|
||||
onlyBuiltDependencies: [],
|
||||
@@ -22,67 +22,24 @@ test('empty overrides and neverBuiltDependencies are removed during lockfile nor
|
||||
},
|
||||
}, {
|
||||
forceSharedFormat: false,
|
||||
includeEmptySpecifiersField: false,
|
||||
})).toStrictEqual({
|
||||
lockfileVersion: LOCKFILE_VERSION,
|
||||
onlyBuiltDependencies: [],
|
||||
importers: {
|
||||
foo: {
|
||||
dependencies: {
|
||||
bar: 'link:../bar',
|
||||
},
|
||||
specifiers: {
|
||||
bar: 'link:../bar',
|
||||
bar: {
|
||||
version: 'link:../bar',
|
||||
specifier: 'link:../bar',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('empty specifiers field is preserved', () => {
|
||||
expect(normalizeLockfile({
|
||||
lockfileVersion: LOCKFILE_VERSION,
|
||||
packages: {},
|
||||
importers: {
|
||||
foo: {
|
||||
specifiers: {},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
forceSharedFormat: false,
|
||||
includeEmptySpecifiersField: true,
|
||||
})).toStrictEqual({
|
||||
lockfileVersion: LOCKFILE_VERSION,
|
||||
importers: {
|
||||
foo: {
|
||||
specifiers: {},
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('empty specifiers field is removed', () => {
|
||||
expect(normalizeLockfile({
|
||||
lockfileVersion: LOCKFILE_VERSION,
|
||||
packages: {},
|
||||
importers: {
|
||||
foo: {
|
||||
specifiers: {},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
forceSharedFormat: false,
|
||||
includeEmptySpecifiersField: false,
|
||||
})).toStrictEqual({
|
||||
lockfileVersion: LOCKFILE_VERSION,
|
||||
importers: {
|
||||
foo: {},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('redundant fields are removed from "time"', () => {
|
||||
expect(normalizeLockfile({
|
||||
expect(convertToLockfileFile({
|
||||
lockfileVersion: LOCKFILE_VERSION,
|
||||
packages: {},
|
||||
importers: {
|
||||
@@ -111,24 +68,27 @@ test('redundant fields are removed from "time"', () => {
|
||||
},
|
||||
}, {
|
||||
forceSharedFormat: false,
|
||||
includeEmptySpecifiersField: false,
|
||||
})).toStrictEqual({
|
||||
lockfileVersion: LOCKFILE_VERSION,
|
||||
importers: {
|
||||
foo: {
|
||||
dependencies: {
|
||||
bar: '1.0.0',
|
||||
bar: {
|
||||
version: '1.0.0',
|
||||
specifier: '1.0.0',
|
||||
},
|
||||
},
|
||||
devDependencies: {
|
||||
foo: '1.0.0(react@18.0.0)',
|
||||
foo: {
|
||||
version: '1.0.0(react@18.0.0)',
|
||||
specifier: '1.0.0',
|
||||
},
|
||||
},
|
||||
optionalDependencies: {
|
||||
qar: '1.0.0',
|
||||
},
|
||||
specifiers: {
|
||||
bar: '1.0.0',
|
||||
foo: '1.0.0',
|
||||
qar: '1.0.0',
|
||||
qar: {
|
||||
version: '1.0.0',
|
||||
specifier: '1.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -18,9 +18,14 @@ test('readWantedLockfile()', async () => {
|
||||
const lockfile = await readWantedLockfile(path.join('fixtures', '2'), {
|
||||
ignoreIncompatible: false,
|
||||
})
|
||||
expect(lockfile?.lockfileVersion).toEqual(3)
|
||||
expect(lockfile?.lockfileVersion).toEqual('6.0')
|
||||
expect(lockfile?.importers).toStrictEqual({
|
||||
'.': {
|
||||
dependencies: {
|
||||
foo: '1.0.0',
|
||||
},
|
||||
devDependencies: undefined,
|
||||
optionalDependencies: undefined,
|
||||
specifiers: {
|
||||
foo: '1',
|
||||
},
|
||||
@@ -65,7 +70,7 @@ test('readCurrentLockfile()', async () => {
|
||||
const lockfile = await readCurrentLockfile('fixtures/2/node_modules/.pnpm', {
|
||||
ignoreIncompatible: false,
|
||||
})
|
||||
expect(lockfile!.lockfileVersion).toEqual(3)
|
||||
expect(lockfile!.lockfileVersion).toEqual('6.0')
|
||||
})
|
||||
|
||||
test('writeWantedLockfile()', async () => {
|
||||
@@ -83,9 +88,9 @@ test('writeWantedLockfile()', async () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
lockfileVersion: 3,
|
||||
lockfileVersion: '6.0',
|
||||
packages: {
|
||||
'/is-negative/1.0.0': {
|
||||
'/is-negative@1.0.0': {
|
||||
dependencies: {
|
||||
'is-positive': '2.0.0',
|
||||
},
|
||||
@@ -93,12 +98,12 @@ test('writeWantedLockfile()', async () => {
|
||||
integrity: 'sha1-ChbBDewTLAqLCzb793Fo5VDvg/g=',
|
||||
},
|
||||
},
|
||||
'/is-positive/1.0.0': {
|
||||
'/is-positive@1.0.0': {
|
||||
resolution: {
|
||||
integrity: 'sha1-ChbBDewTLAqLCzb793Fo5VDvg/g=',
|
||||
},
|
||||
},
|
||||
'/is-positive/2.0.0': {
|
||||
'/is-positive@2.0.0': {
|
||||
resolution: {
|
||||
integrity: 'sha1-ChbBDewTLAqLCzb793Fo5VDvg/g=',
|
||||
},
|
||||
@@ -126,9 +131,9 @@ test('writeCurrentLockfile()', async () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
lockfileVersion: 3,
|
||||
lockfileVersion: '6.0',
|
||||
packages: {
|
||||
'/is-negative/1.0.0': {
|
||||
'/is-negative@1.0.0': {
|
||||
dependencies: {
|
||||
'is-positive': '2.0.0',
|
||||
},
|
||||
@@ -136,12 +141,12 @@ test('writeCurrentLockfile()', async () => {
|
||||
integrity: 'sha1-ChbBDewTLAqLCzb793Fo5VDvg/g=',
|
||||
},
|
||||
},
|
||||
'/is-positive/1.0.0': {
|
||||
'/is-positive@1.0.0': {
|
||||
resolution: {
|
||||
integrity: 'sha1-ChbBDewTLAqLCzb793Fo5VDvg/g=',
|
||||
},
|
||||
},
|
||||
'/is-positive/2.0.0': {
|
||||
'/is-positive@2.0.0': {
|
||||
resolution: {
|
||||
integrity: 'sha1-ChbBDewTLAqLCzb793Fo5VDvg/g=',
|
||||
},
|
||||
@@ -202,13 +207,16 @@ test('readWantedLockfile() when useGitBranchLockfile', async () => {
|
||||
})
|
||||
expect(lockfile?.importers).toEqual({
|
||||
'.': {
|
||||
dependencies: {
|
||||
'is-positive': '1.0.0',
|
||||
},
|
||||
specifiers: {
|
||||
'is-positive': '1.0.0',
|
||||
},
|
||||
},
|
||||
})
|
||||
expect(lockfile?.packages).toStrictEqual({
|
||||
'/is-positive/1.0.0': {
|
||||
'/is-positive@1.0.0': {
|
||||
resolution: {
|
||||
integrity: 'sha1-ChbBDewTLAqLCzb793Fo5VDvg/g=',
|
||||
},
|
||||
@@ -221,13 +229,16 @@ test('readWantedLockfile() when useGitBranchLockfile', async () => {
|
||||
})
|
||||
expect(gitBranchLockfile?.importers).toEqual({
|
||||
'.': {
|
||||
dependencies: {
|
||||
'is-positive': '2.0.0',
|
||||
},
|
||||
specifiers: {
|
||||
'is-positive': '2.0.0',
|
||||
},
|
||||
},
|
||||
})
|
||||
expect(gitBranchLockfile?.packages).toStrictEqual({
|
||||
'/is-positive/2.0.0': {
|
||||
'/is-positive@2.0.0': {
|
||||
resolution: {
|
||||
integrity: 'sha1-ChbBDewTLAqLCzb793Fo5VDvg/g=',
|
||||
},
|
||||
@@ -244,18 +255,21 @@ test('readWantedLockfile() when useGitBranchLockfile and mergeGitBranchLockfiles
|
||||
})
|
||||
expect(lockfile?.importers).toEqual({
|
||||
'.': {
|
||||
dependencies: {
|
||||
'is-positive': '2.0.0',
|
||||
},
|
||||
specifiers: {
|
||||
'is-positive': '2.0.0',
|
||||
},
|
||||
},
|
||||
})
|
||||
expect(lockfile?.packages).toStrictEqual({
|
||||
'/is-positive/1.0.0': {
|
||||
'/is-positive@1.0.0': {
|
||||
resolution: {
|
||||
integrity: 'sha1-ChbBDewTLAqLCzb793Fo5VDvg/g=',
|
||||
},
|
||||
},
|
||||
'/is-positive/2.0.0': {
|
||||
'/is-positive@2.0.0': {
|
||||
resolution: {
|
||||
integrity: 'sha1-ChbBDewTLAqLCzb793Fo5VDvg/g=',
|
||||
},
|
||||
|
||||
@@ -7,22 +7,26 @@ test('sorts keys alphabetically', () => {
|
||||
importers: {
|
||||
foo: {
|
||||
dependencies: {
|
||||
zzz: 'link:../zzz',
|
||||
bar: 'link:../bar',
|
||||
aaa: 'link:../aaa',
|
||||
},
|
||||
specifiers: {
|
||||
zzz: 'link:../zzz',
|
||||
bar: 'link:../bar',
|
||||
aaa: 'link:../aaa',
|
||||
zzz: {
|
||||
version: 'link:../zzz',
|
||||
specifier: 'link:../zzz',
|
||||
},
|
||||
bar: {
|
||||
version: 'link:../bar',
|
||||
specifier: 'link:../bar',
|
||||
},
|
||||
aaa: {
|
||||
version: 'link:../aaa',
|
||||
specifier: 'link:../aaa',
|
||||
},
|
||||
},
|
||||
},
|
||||
bar: {
|
||||
specifiers: {
|
||||
baz: 'link:../baz',
|
||||
},
|
||||
dependencies: {
|
||||
baz: 'link:../baz',
|
||||
baz: {
|
||||
version: 'link:../baz',
|
||||
specifier: 'link:../baz',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -38,22 +42,26 @@ test('sorts keys alphabetically', () => {
|
||||
importers: {
|
||||
bar: {
|
||||
dependencies: {
|
||||
baz: 'link:../baz',
|
||||
},
|
||||
specifiers: {
|
||||
baz: 'link:../baz',
|
||||
baz: {
|
||||
version: 'link:../baz',
|
||||
specifier: 'link:../baz',
|
||||
},
|
||||
},
|
||||
},
|
||||
foo: {
|
||||
dependencies: {
|
||||
aaa: 'link:../aaa',
|
||||
bar: 'link:../bar',
|
||||
zzz: 'link:../zzz',
|
||||
},
|
||||
specifiers: {
|
||||
aaa: 'link:../aaa',
|
||||
bar: 'link:../bar',
|
||||
zzz: 'link:../zzz',
|
||||
aaa: {
|
||||
version: 'link:../aaa',
|
||||
specifier: 'link:../aaa',
|
||||
},
|
||||
bar: {
|
||||
version: 'link:../bar',
|
||||
specifier: 'link:../bar',
|
||||
},
|
||||
zzz: {
|
||||
version: 'link:../zzz',
|
||||
specifier: 'link:../zzz',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -64,7 +72,6 @@ test('sorts keys alphabetically', () => {
|
||||
},
|
||||
})
|
||||
expect(Object.keys(normalizedLockfile.importers?.foo.dependencies ?? {})).toStrictEqual(['aaa', 'bar', 'zzz'])
|
||||
expect(Object.keys(normalizedLockfile.importers?.foo.specifiers ?? {})).toStrictEqual(['aaa', 'bar', 'zzz'])
|
||||
expect(Object.keys(normalizedLockfile.patchedDependencies ?? {})).toStrictEqual(['aaa', 'bar', 'zzz'])
|
||||
})
|
||||
|
||||
@@ -75,14 +82,18 @@ test('sorting does not care about locale (e.g. Czech has "ch" as a single charac
|
||||
importers: {
|
||||
foo: {
|
||||
dependencies: {
|
||||
bar: 'link:../bar',
|
||||
href: 'link:../href',
|
||||
chmod: 'link:../chmod',
|
||||
},
|
||||
specifiers: {
|
||||
bar: 'link:../bar',
|
||||
href: 'link:../href',
|
||||
chmod: 'link:../chmod',
|
||||
bar: {
|
||||
version: 'link:../bar',
|
||||
specifier: 'link:../bar',
|
||||
},
|
||||
href: {
|
||||
version: 'link:../href',
|
||||
specifier: 'link:../href',
|
||||
},
|
||||
chmod: {
|
||||
version: 'link:../chmod',
|
||||
specifier: 'link:../chmod',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -94,18 +105,21 @@ test('sorting does not care about locale (e.g. Czech has "ch" as a single charac
|
||||
importers: {
|
||||
foo: {
|
||||
dependencies: {
|
||||
bar: 'link:../bar',
|
||||
chmod: 'link:../chmod',
|
||||
href: 'link:../href',
|
||||
},
|
||||
specifiers: {
|
||||
bar: 'link:../bar',
|
||||
chmod: 'link:../chmod',
|
||||
href: 'link:../href',
|
||||
bar: {
|
||||
version: 'link:../bar',
|
||||
specifier: 'link:../bar',
|
||||
},
|
||||
chmod: {
|
||||
version: 'link:../chmod',
|
||||
specifier: 'link:../chmod',
|
||||
},
|
||||
href: {
|
||||
version: 'link:../href',
|
||||
specifier: 'link:../href',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
expect(Object.keys(normalizedLockfile.importers?.foo.dependencies ?? {})).toStrictEqual(['bar', 'chmod', 'href'])
|
||||
expect(Object.keys(normalizedLockfile.importers?.foo.specifiers ?? {})).toStrictEqual(['bar', 'chmod', 'href'])
|
||||
})
|
||||
|
||||
@@ -2,6 +2,8 @@ import { type DependenciesMeta, type PatchFile } from '@pnpm/types'
|
||||
|
||||
export type { PatchFile }
|
||||
|
||||
export * from './lockfileFileTypes'
|
||||
|
||||
export interface LockfileSettings {
|
||||
autoInstallPeers?: boolean
|
||||
excludeLinksFromLockfile?: boolean
|
||||
@@ -29,27 +31,6 @@ export interface ProjectSnapshot {
|
||||
publishDirectory?: string
|
||||
}
|
||||
|
||||
export interface LockfileV6 {
|
||||
importers: Record<string, ProjectSnapshotV6>
|
||||
lockfileVersion: number | string
|
||||
time?: Record<string, string>
|
||||
packages?: PackageSnapshots
|
||||
neverBuiltDependencies?: string[]
|
||||
onlyBuiltDependencies?: string[]
|
||||
overrides?: Record<string, string>
|
||||
packageExtensionsChecksum?: string
|
||||
patchedDependencies?: Record<string, PatchFile>
|
||||
settings?: LockfileSettings
|
||||
}
|
||||
|
||||
export interface ProjectSnapshotV6 {
|
||||
dependencies?: ResolvedDependenciesOfImporters
|
||||
optionalDependencies?: ResolvedDependenciesOfImporters
|
||||
devDependencies?: ResolvedDependenciesOfImporters
|
||||
dependenciesMeta?: DependenciesMeta
|
||||
publishDirectory?: string
|
||||
}
|
||||
|
||||
export type ResolvedDependenciesOfImporters = Record<string, { version: string, specifier: string }>
|
||||
|
||||
export interface PackageSnapshots {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import type { Lockfile } from '@pnpm/lockfile-types'
|
||||
import type { Lockfile, ProjectSnapshot } from '.'
|
||||
import type { DependenciesMeta } from '@pnpm/types'
|
||||
|
||||
export const INLINE_SPECIFIERS_FORMAT_LOCKFILE_VERSION_SUFFIX = '-inlineSpecifiers'
|
||||
export type LockfileFile = Omit<InlineSpecifiersLockfile, 'importers'> &
|
||||
Partial<InlineSpecifiersProjectSnapshot> &
|
||||
Partial<Pick<InlineSpecifiersLockfile, 'importers'>>
|
||||
|
||||
/**
|
||||
* Similar to the current Lockfile importers format (lockfile version 5.4 at
|
||||
@@ -13,7 +15,7 @@ export const INLINE_SPECIFIERS_FORMAT_LOCKFILE_VERSION_SUFFIX = '-inlineSpecifie
|
||||
*/
|
||||
export interface InlineSpecifiersLockfile extends Omit<Lockfile, 'lockfileVersion' | 'importers'> {
|
||||
lockfileVersion: string
|
||||
importers: Record<string, InlineSpecifiersProjectSnapshot>
|
||||
importers?: Record<string, InlineSpecifiersProjectSnapshot>
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -21,7 +23,7 @@ export interface InlineSpecifiersLockfile extends Omit<Lockfile, 'lockfileVersio
|
||||
* field in favor of inlining each specifier next to its version resolution in
|
||||
* dependency blocks.
|
||||
*/
|
||||
export interface InlineSpecifiersProjectSnapshot {
|
||||
export type InlineSpecifiersProjectSnapshot = Omit<ProjectSnapshot, 'dependencies' | 'devDependencies' | 'optionalDependencies' | 'dependenciesMeta' | 'specifiers'> & {
|
||||
dependencies?: InlineSpecifiersResolvedDependencies
|
||||
devDependencies?: InlineSpecifiersResolvedDependencies
|
||||
optionalDependencies?: InlineSpecifiersResolvedDependencies
|
||||
@@ -2,7 +2,7 @@ import { type Lockfile, type PackageSnapshot, type PackageSnapshots } from '@pnp
|
||||
import comverToSemver from 'comver-to-semver'
|
||||
import semver from 'semver'
|
||||
|
||||
export function mergeLockfileChanges (ours: Lockfile, theirs: Lockfile) {
|
||||
export function mergeLockfileChanges (ours: Lockfile, theirs: Lockfile): Lockfile {
|
||||
const newLockfile: Lockfile = {
|
||||
importers: {},
|
||||
lockfileVersion: semver.gt(comverToSemver(theirs.lockfileVersion.toString()), comverToSemver(ours.lockfileVersion.toString()))
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
type MutatedProject,
|
||||
type ProjectOptions,
|
||||
} from '@pnpm/core'
|
||||
import { type Lockfile, type LockfileV6 } from '@pnpm/lockfile-types'
|
||||
import { type Lockfile, type LockfileFile } from '@pnpm/lockfile-types'
|
||||
import { prepareEmpty, preparePackages, tempDir } from '@pnpm/prepare'
|
||||
import { addDistTag } from '@pnpm/registry-mock'
|
||||
import { fixtures } from '@pnpm/test-fixtures'
|
||||
@@ -78,9 +78,9 @@ test('links are not added to the lockfile when excludeLinksFromLockfile is true'
|
||||
},
|
||||
]
|
||||
await mutateModules(importers, await testDefaults({ allProjects, excludeLinksFromLockfile: true }))
|
||||
const lockfile: LockfileV6 = await readYamlFile(WANTED_LOCKFILE)
|
||||
expect(lockfile.importers['project-1'].dependencies?.['external-1']).toBeUndefined()
|
||||
expect(lockfile.importers['project-2'].dependencies?.['external-2']).toBeUndefined()
|
||||
const lockfile: LockfileFile = await readYamlFile(WANTED_LOCKFILE)
|
||||
expect(lockfile.importers?.['project-1'].dependencies?.['external-1']).toBeUndefined()
|
||||
expect(lockfile.importers?.['project-2'].dependencies?.['external-2']).toBeUndefined()
|
||||
|
||||
expect(fs.existsSync(path.resolve('project-1/node_modules/external-1/index.js'))).toBeTruthy()
|
||||
expect(fs.existsSync(path.resolve('project-2/node_modules/external-2/index.js'))).toBeTruthy()
|
||||
@@ -90,8 +90,8 @@ test('links are not added to the lockfile when excludeLinksFromLockfile is true'
|
||||
await rimraf('project-2/node_modules')
|
||||
|
||||
await mutateModules(importers, await testDefaults({ allProjects, excludeLinksFromLockfile: true, frozenLockfile: true }))
|
||||
expect(lockfile.importers['project-1'].dependencies?.['external-1']).toBeUndefined()
|
||||
expect(lockfile.importers['project-2'].dependencies?.['external-2']).toBeUndefined()
|
||||
expect(lockfile.importers?.['project-1'].dependencies?.['external-1']).toBeUndefined()
|
||||
expect(lockfile.importers?.['project-2'].dependencies?.['external-2']).toBeUndefined()
|
||||
|
||||
expect(fs.existsSync(path.resolve('project-1/node_modules/external-1/index.js'))).toBeTruthy()
|
||||
expect(fs.existsSync(path.resolve('project-2/node_modules/external-2/index.js'))).toBeTruthy()
|
||||
@@ -101,8 +101,8 @@ test('links are not added to the lockfile when excludeLinksFromLockfile is true'
|
||||
await rimraf('project-2/node_modules')
|
||||
|
||||
await mutateModules(importers, await testDefaults({ allProjects, excludeLinksFromLockfile: true, frozenLockfile: false, preferFrozenLockfile: false }))
|
||||
expect(lockfile.importers['project-1'].dependencies?.['external-1']).toBeUndefined()
|
||||
expect(lockfile.importers['project-2'].dependencies?.['external-2']).toBeUndefined()
|
||||
expect(lockfile.importers?.['project-1'].dependencies?.['external-1']).toBeUndefined()
|
||||
expect(lockfile.importers?.['project-2'].dependencies?.['external-2']).toBeUndefined()
|
||||
|
||||
expect(fs.existsSync(path.resolve('project-1/node_modules/external-1/index.js'))).toBeTruthy()
|
||||
expect(fs.existsSync(path.resolve('project-2/node_modules/external-2/index.js'))).toBeTruthy()
|
||||
@@ -110,9 +110,9 @@ test('links are not added to the lockfile when excludeLinksFromLockfile is true'
|
||||
delete allProjects[1].manifest.dependencies!['external-2']
|
||||
allProjects[1].manifest.dependencies!['external-3'] = `link:${path.relative(project2Dir, externalPkg3)}`
|
||||
await mutateModules(importers, await testDefaults({ allProjects, excludeLinksFromLockfile: true }))
|
||||
expect(lockfile.importers['project-1'].dependencies?.['external-1']).toBeUndefined()
|
||||
expect(lockfile.importers['project-2'].dependencies?.['external-2']).toBeUndefined()
|
||||
expect(lockfile.importers['project-2'].dependencies?.['external-3']).toBeUndefined()
|
||||
expect(lockfile.importers?.['project-1'].dependencies?.['external-1']).toBeUndefined()
|
||||
expect(lockfile.importers?.['project-2'].dependencies?.['external-2']).toBeUndefined()
|
||||
expect(lockfile.importers?.['project-2'].dependencies?.['external-3']).toBeUndefined()
|
||||
|
||||
expect(fs.existsSync(path.resolve('project-1/node_modules/external-1/index.js'))).toBeTruthy()
|
||||
// expect(fs.existsSync(path.resolve('project-2/node_modules/external-2'))).toBeFalsy() // Should we remove external links that are not in deps anymore?
|
||||
@@ -301,8 +301,8 @@ test('links resolved from workspace protocol dependencies are not removed', asyn
|
||||
workspacePackages,
|
||||
}))
|
||||
|
||||
const lockfile: LockfileV6 = await readYamlFile(WANTED_LOCKFILE)
|
||||
expect(lockfile.importers['project-1'].dependencies?.['project-2']).toStrictEqual({
|
||||
const lockfile: LockfileFile = await readYamlFile(WANTED_LOCKFILE)
|
||||
expect(lockfile.importers?.['project-1'].dependencies?.['project-2']).toStrictEqual({
|
||||
specifier: 'workspace:*',
|
||||
version: 'link:../project-2',
|
||||
})
|
||||
|
||||
@@ -5,7 +5,7 @@ import { type RootLog } from '@pnpm/core-loggers'
|
||||
import { type PnpmError } from '@pnpm/error'
|
||||
import { fixtures } from '@pnpm/test-fixtures'
|
||||
import { type Lockfile, type TarballResolution } from '@pnpm/lockfile-file'
|
||||
import { type LockfileV6 } from '@pnpm/lockfile-types'
|
||||
import { type LockfileFile } from '@pnpm/lockfile-types'
|
||||
import { tempDir, prepareEmpty, preparePackages } from '@pnpm/prepare'
|
||||
import { readPackageJsonFromDir } from '@pnpm/read-package-json'
|
||||
import { addDistTag, getIntegrity, REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
|
||||
@@ -855,18 +855,18 @@ test('lockfile file has correct format when lockfile directory does not equal th
|
||||
expect(modules.pendingBuilds.length).toBe(0)
|
||||
|
||||
{
|
||||
const lockfile: LockfileV6 = await readYamlFile(WANTED_LOCKFILE)
|
||||
const lockfile: LockfileFile = await readYamlFile(WANTED_LOCKFILE)
|
||||
const id = '/@pnpm.e2e/pkg-with-1-dep@100.0.0'
|
||||
|
||||
expect(lockfile.lockfileVersion).toBe(LOCKFILE_VERSION)
|
||||
|
||||
expect(lockfile.importers).toBeTruthy()
|
||||
expect(lockfile.importers.project).toBeTruthy()
|
||||
expect(lockfile.importers.project).toBeTruthy()
|
||||
expect(lockfile.importers.project.dependencies).toBeTruthy()
|
||||
expect(lockfile.importers.project.dependencies!['@pnpm.e2e/pkg-with-1-dep'].version).toBe('100.0.0')
|
||||
expect(lockfile.importers.project.dependencies!['@zkochan/foo']).toBeTruthy()
|
||||
expect(lockfile.importers.project.dependencies!['is-negative'].version).toContain('/')
|
||||
expect(lockfile.importers?.project).toBeTruthy()
|
||||
expect(lockfile.importers?.project).toBeTruthy()
|
||||
expect(lockfile.importers?.project.dependencies).toBeTruthy()
|
||||
expect(lockfile.importers?.project.dependencies!['@pnpm.e2e/pkg-with-1-dep'].version).toBe('100.0.0')
|
||||
expect(lockfile.importers?.project.dependencies!['@zkochan/foo']).toBeTruthy()
|
||||
expect(lockfile.importers?.project.dependencies!['is-negative'].version).toContain('/')
|
||||
|
||||
expect(lockfile.packages![id].dependencies).toHaveProperty(['@pnpm.e2e/dep-of-pkg-with-1-dep'])
|
||||
expect(lockfile.packages![id].resolution).toHaveProperty(['integrity'])
|
||||
@@ -889,16 +889,16 @@ test('lockfile file has correct format when lockfile directory does not equal th
|
||||
}))
|
||||
|
||||
{
|
||||
const lockfile = await readYamlFile<LockfileV6>(path.join('..', WANTED_LOCKFILE))
|
||||
const lockfile = await readYamlFile<LockfileFile>(path.join('..', WANTED_LOCKFILE))
|
||||
|
||||
expect(lockfile.importers).toHaveProperty(['project-2'])
|
||||
|
||||
// previous entries are not removed
|
||||
const id = '/@pnpm.e2e/pkg-with-1-dep@100.0.0'
|
||||
|
||||
expect(lockfile.importers.project.dependencies!['@pnpm.e2e/pkg-with-1-dep'].version).toBe('100.0.0')
|
||||
expect(lockfile.importers.project.dependencies).toHaveProperty(['@zkochan/foo'])
|
||||
expect(lockfile.importers.project.dependencies!['is-negative'].version).toContain('/')
|
||||
expect(lockfile.importers?.project.dependencies!['@pnpm.e2e/pkg-with-1-dep'].version).toBe('100.0.0')
|
||||
expect(lockfile.importers?.project.dependencies).toHaveProperty(['@zkochan/foo'])
|
||||
expect(lockfile.importers?.project.dependencies!['is-negative'].version).toContain('/')
|
||||
|
||||
expect(lockfile.packages).toHaveProperty([id])
|
||||
expect(lockfile.packages![id].dependencies).toBeTruthy()
|
||||
@@ -977,9 +977,9 @@ test(`doing named installation when shared ${WANTED_LOCKFILE} exists already`, a
|
||||
})
|
||||
)
|
||||
|
||||
const currentLockfile = await readYamlFile<LockfileV6>(path.resolve('node_modules/.pnpm/lock.yaml'))
|
||||
const currentLockfile = await readYamlFile<LockfileFile>(path.resolve('node_modules/.pnpm/lock.yaml'))
|
||||
|
||||
expect(Object.keys(currentLockfile['importers'])).toStrictEqual(['pkg2'])
|
||||
expect(Object.keys(currentLockfile.importers ?? {})).toStrictEqual(['pkg2'])
|
||||
|
||||
await mutateModules(
|
||||
[
|
||||
|
||||
@@ -2,7 +2,7 @@ import { promises as fs } from 'fs'
|
||||
import path from 'path'
|
||||
import { type PnpmError } from '@pnpm/error'
|
||||
import { readProjects } from '@pnpm/filter-workspace-packages'
|
||||
import { type LockfileV6 as Lockfile } from '@pnpm/lockfile-types'
|
||||
import { type LockfileFile } from '@pnpm/lockfile-types'
|
||||
import { add, install, remove, update } from '@pnpm/plugin-commands-installation'
|
||||
import { preparePackages } from '@pnpm/prepare'
|
||||
import { addDistTag } from '@pnpm/registry-mock'
|
||||
@@ -617,8 +617,8 @@ test('recursive install on workspace with custom lockfile-dir', async () => {
|
||||
workspaceDir: process.cwd(),
|
||||
})
|
||||
|
||||
const lockfile = await readYamlFile<Lockfile>(path.join(lockfileDir, 'pnpm-lock.yaml'))
|
||||
expect(Object.keys(lockfile.importers)).toStrictEqual(['../project-1', '../project-2'])
|
||||
const lockfile = await readYamlFile<LockfileFile>(path.join(lockfileDir, 'pnpm-lock.yaml'))
|
||||
expect(Object.keys(lockfile.importers!)).toStrictEqual(['../project-1', '../project-2'])
|
||||
})
|
||||
|
||||
test('recursive install in a monorepo with different modules directories', async () => {
|
||||
@@ -725,8 +725,8 @@ test('prefer-workspace-package', async () => {
|
||||
workspaceDir: process.cwd(),
|
||||
})
|
||||
|
||||
const lockfile = await readYamlFile<Lockfile>(path.resolve('pnpm-lock.yaml'))
|
||||
expect(lockfile.importers['project-1'].dependencies?.['@pnpm.e2e/foo'].version).toBe('link:../foo')
|
||||
const lockfile = await readYamlFile<LockfileFile>(path.resolve('pnpm-lock.yaml'))
|
||||
expect(lockfile.importers?.['project-1'].dependencies?.['@pnpm.e2e/foo'].version).toBe('link:../foo')
|
||||
})
|
||||
|
||||
test('installing in monorepo with shared lockfile should work on virtual drives', async () => {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { promises as fs } from 'fs'
|
||||
import path from 'path'
|
||||
import { LOCKFILE_VERSION, WANTED_LOCKFILE } from '@pnpm/constants'
|
||||
import { findWorkspacePackages } from '@pnpm/workspace.find-packages'
|
||||
import { type LockfileV6 as Lockfile } from '@pnpm/lockfile-types'
|
||||
import { type LockfileFile } from '@pnpm/lockfile-types'
|
||||
import { readModulesManifest } from '@pnpm/modules-yaml'
|
||||
import {
|
||||
prepare,
|
||||
@@ -635,9 +635,9 @@ test('shared-workspace-lockfile: installation with --link-workspace-packages lin
|
||||
await execPnpm(['recursive', 'install'])
|
||||
|
||||
{
|
||||
const lockfile = await readYamlFile<Lockfile>(WANTED_LOCKFILE)
|
||||
expect(lockfile.importers.project!.dependencies!['is-positive'].version).toBe('2.0.0')
|
||||
expect(lockfile.importers.project!.dependencies!.negative.version).toBe('/is-negative@1.0.0')
|
||||
const lockfile = await readYamlFile<LockfileFile>(WANTED_LOCKFILE)
|
||||
expect(lockfile.importers!.project!.dependencies!['is-positive'].version).toBe('2.0.0')
|
||||
expect(lockfile.importers!.project!.dependencies!.negative.version).toBe('/is-negative@1.0.0')
|
||||
}
|
||||
|
||||
await projects['is-positive'].writePackageJson({
|
||||
@@ -653,9 +653,9 @@ test('shared-workspace-lockfile: installation with --link-workspace-packages lin
|
||||
await execPnpm(['recursive', 'install'])
|
||||
|
||||
{
|
||||
const lockfile = await readYamlFile<Lockfile>(WANTED_LOCKFILE)
|
||||
expect(lockfile.importers.project!.dependencies!['is-positive'].version).toBe('link:../is-positive')
|
||||
expect(lockfile.importers.project!.dependencies!.negative.version).toBe('link:../is-negative')
|
||||
const lockfile = await readYamlFile<LockfileFile>(WANTED_LOCKFILE)
|
||||
expect(lockfile.importers!.project!.dependencies!['is-positive'].version).toBe('link:../is-positive')
|
||||
expect(lockfile.importers!.project!.dependencies!.negative.version).toBe('link:../is-negative')
|
||||
}
|
||||
})
|
||||
|
||||
@@ -710,8 +710,8 @@ test('recursive install with link-workspace-packages and shared-workspace-lockfi
|
||||
expect(projects['is-positive'].requireModule('is-negative')).toBeTruthy()
|
||||
expect(projects['project-1'].requireModule('is-positive/package.json').author).toBeFalsy()
|
||||
|
||||
const sharedLockfile = await readYamlFile<Lockfile>(WANTED_LOCKFILE)
|
||||
expect(sharedLockfile.importers['project-1']!.devDependencies!['is-positive'].version).toBe('link:../is-positive')
|
||||
const sharedLockfile = await readYamlFile<LockfileFile>(WANTED_LOCKFILE)
|
||||
expect(sharedLockfile.importers!['project-1']!.devDependencies!['is-positive'].version).toBe('link:../is-positive')
|
||||
|
||||
expect(server.getLines()).toStrictEqual(['is-positive', 'project-1'])
|
||||
|
||||
@@ -860,7 +860,7 @@ test('recursive installation with shared-workspace-lockfile and a readPackage ho
|
||||
|
||||
await execPnpm(['recursive', 'install', '--shared-workspace-lockfile', '--store-dir', 'store'])
|
||||
|
||||
const lockfile = await readYamlFile<Lockfile>(`./${WANTED_LOCKFILE}`)
|
||||
const lockfile = await readYamlFile<LockfileFile>(`./${WANTED_LOCKFILE}`)
|
||||
expect(lockfile.packages).toHaveProperty(['/@pnpm.e2e/dep-of-pkg-with-1-dep@100.1.0'])
|
||||
|
||||
await execPnpm(['recursive', 'install', '--shared-workspace-lockfile', '--store-dir', 'store', '--filter', 'project-1'])
|
||||
@@ -909,7 +909,7 @@ test('shared-workspace-lockfile: create shared lockfile format when installation
|
||||
|
||||
await execPnpm(['install', '--store-dir', 'store'])
|
||||
|
||||
const lockfile = await readYamlFile<Lockfile>(WANTED_LOCKFILE)
|
||||
const lockfile = await readYamlFile<LockfileFile>(WANTED_LOCKFILE)
|
||||
|
||||
expect(lockfile.importers).toHaveProperty(['.'])
|
||||
expect(lockfile.lockfileVersion).toBe(LOCKFILE_VERSION)
|
||||
@@ -952,7 +952,7 @@ test("shared-workspace-lockfile: don't install dependencies in projects that are
|
||||
|
||||
await execPnpm(['recursive', 'install', '--store-dir', 'store', '--shared-workspace-lockfile', '--link-workspace-packages'])
|
||||
|
||||
const lockfile = await readYamlFile<Lockfile>(WANTED_LOCKFILE)
|
||||
const lockfile = await readYamlFile<LockfileFile>(WANTED_LOCKFILE)
|
||||
|
||||
expect(lockfile).toStrictEqual({
|
||||
settings: {
|
||||
@@ -1033,7 +1033,7 @@ test('shared-workspace-lockfile: install dependencies in projects that are relat
|
||||
|
||||
await execPnpm(['-r', 'install', '--store-dir', 'store', '--shared-workspace-lockfile', '--link-workspace-packages', '--no-save-workspace-protocol'])
|
||||
|
||||
const lockfile = await readYamlFile<Lockfile>(WANTED_LOCKFILE)
|
||||
const lockfile = await readYamlFile<LockfileFile>(WANTED_LOCKFILE)
|
||||
|
||||
expect(lockfile).toStrictEqual({
|
||||
settings: {
|
||||
@@ -1123,8 +1123,8 @@ test('shared-workspace-lockfile: entries of removed projects should be removed f
|
||||
await execPnpm(['recursive', 'install', '--store-dir', 'store', '--shared-workspace-lockfile', '--link-workspace-packages'])
|
||||
|
||||
{
|
||||
const lockfile = await readYamlFile<Lockfile>(WANTED_LOCKFILE)
|
||||
expect(Object.keys(lockfile.importers)).toStrictEqual(['package-1', 'package-2'])
|
||||
const lockfile = await readYamlFile<LockfileFile>(WANTED_LOCKFILE)
|
||||
expect(Object.keys(lockfile.importers!)).toStrictEqual(['package-1', 'package-2'])
|
||||
}
|
||||
|
||||
await rimraf('package-2')
|
||||
@@ -1132,8 +1132,8 @@ test('shared-workspace-lockfile: entries of removed projects should be removed f
|
||||
await execPnpm(['recursive', 'install', '--store-dir', 'store', '--shared-workspace-lockfile', '--link-workspace-packages'])
|
||||
|
||||
{
|
||||
const lockfile = await readYamlFile<Lockfile>(WANTED_LOCKFILE)
|
||||
expect(Object.keys(lockfile.importers)).toStrictEqual(['package-1'])
|
||||
const lockfile = await readYamlFile<LockfileFile>(WANTED_LOCKFILE)
|
||||
expect(Object.keys(lockfile.importers!)).toStrictEqual(['package-1'])
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1196,7 +1196,7 @@ test('shared-workspace-lockfile: removing a package recursively', async () => {
|
||||
expect(pkg.dependencies).toStrictEqual({ 'is-negative': '1.0.0' }) // is-positive removed from project2')
|
||||
}
|
||||
|
||||
const lockfile = await readYamlFile<Lockfile>(WANTED_LOCKFILE)
|
||||
const lockfile = await readYamlFile<LockfileFile>(WANTED_LOCKFILE)
|
||||
|
||||
expect(Object.keys(lockfile.packages ?? {})).toStrictEqual(['/is-negative@1.0.0']) // is-positive removed from ${WANTED_LOCKFILE}
|
||||
})
|
||||
@@ -1228,8 +1228,8 @@ auto-install-peers=false`, 'utf8')
|
||||
await execPnpm(['install', 'ajv@4.10.4', 'ajv-keywords@1.5.0'])
|
||||
|
||||
{
|
||||
const lockfile = await readYamlFile<Lockfile>(path.resolve('..', WANTED_LOCKFILE))
|
||||
expect(lockfile.importers.foo).toStrictEqual({
|
||||
const lockfile = await readYamlFile<LockfileFile>(path.resolve('..', WANTED_LOCKFILE))
|
||||
expect(lockfile.importers!.foo).toStrictEqual({
|
||||
dependencies: {
|
||||
ajv: {
|
||||
specifier: '4.10.4',
|
||||
@@ -1250,8 +1250,8 @@ auto-install-peers=false`, 'utf8')
|
||||
await execPnpm(['uninstall', 'ajv', '--no-strict-peer-dependencies'])
|
||||
|
||||
{
|
||||
const lockfile = await readYamlFile<Lockfile>(path.resolve('..', WANTED_LOCKFILE))
|
||||
expect(lockfile.importers.foo).toStrictEqual({
|
||||
const lockfile = await readYamlFile<LockfileFile>(path.resolve('..', WANTED_LOCKFILE))
|
||||
expect(lockfile.importers!.foo).toStrictEqual({
|
||||
dependencies: {
|
||||
'ajv-keywords': {
|
||||
specifier: '1.5.0',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import { assertStore } from '@pnpm/assert-store'
|
||||
import { type LockfileV6 as Lockfile } from '@pnpm/lockfile-file'
|
||||
import { type LockfileFile } from '@pnpm/lockfile-file'
|
||||
import { store } from '@pnpm/plugin-commands-store'
|
||||
import { prepare } from '@pnpm/prepare'
|
||||
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
|
||||
@@ -136,7 +136,7 @@ test('keep dependencies used by others', async () => {
|
||||
await project.hasNot('map-obj')
|
||||
|
||||
// all dependencies are marked as dev
|
||||
const lockfile = await project.readLockfile() as Lockfile
|
||||
const lockfile = await project.readLockfile() as LockfileFile
|
||||
expect(isEmpty(lockfile.packages)).toBeFalsy()
|
||||
|
||||
Object.entries(lockfile.packages ?? {}).forEach(([_, dep]) => {
|
||||
|
||||
Reference in New Issue
Block a user