mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-24 07:38:12 -05:00
feat!: lockfile format v6 (#5810)
This commit is contained in:
5
.changeset/orange-cobras-joke.md
Normal file
5
.changeset/orange-cobras-joke.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/constants": minor
|
||||
---
|
||||
|
||||
Exported a constant for the new lockfile format version: `LOCKFILE_FORMAT_V6`.
|
||||
5
.changeset/orange-pears-flow.md
Normal file
5
.changeset/orange-pears-flow.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/lockfile-file": major
|
||||
---
|
||||
|
||||
Breaking change to the API of the read functions. Instead of one wanted lockfile version, it now expects an array of `wantedVersions`.
|
||||
10
.changeset/shy-balloons-build.md
Normal file
10
.changeset/shy-balloons-build.md
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-installation": minor
|
||||
"@pnpm/resolve-dependencies": minor
|
||||
"@pnpm/get-context": minor
|
||||
"@pnpm/core": minor
|
||||
"@pnpm/config": minor
|
||||
"pnpm": minor
|
||||
---
|
||||
|
||||
Added support for `pnpm-lock.yaml` format v6. This new format will be the new lockfile format in pnpm v8. To use the new lockfile format, use the `use-lockfile-v6=true` setting in `.npmrc`. Or run `pnpm install --use-lockfile-v6` [#5810](https://github.com/pnpm/pnpm/pull/5810).
|
||||
5
.changeset/thick-dingos-enjoy.md
Normal file
5
.changeset/thick-dingos-enjoy.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/dependency-path": minor
|
||||
---
|
||||
|
||||
Updated the functions to support dependency paths used in the 6th version of the lockfile. Exported a new function: createPeersFolderSuffixNewFormat.
|
||||
@@ -88,6 +88,7 @@ export interface Config {
|
||||
registrySupportsTimeField?: boolean
|
||||
failedToLoadBuiltInConfig: boolean
|
||||
resolvePeersFromWorkspaceRoot?: boolean
|
||||
useLockfileV6?: boolean
|
||||
|
||||
// proxy
|
||||
httpProxy?: string
|
||||
|
||||
@@ -111,6 +111,7 @@ export const types = Object.assign({
|
||||
'strict-peer-dependencies': Boolean,
|
||||
'use-beta-cli': Boolean,
|
||||
'use-inline-specifiers-lockfile-format': Boolean,
|
||||
'use-lockfile-v6': Boolean,
|
||||
'use-node-version': String,
|
||||
'use-running-store-server': Boolean,
|
||||
'use-store-server': Boolean,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import * as dp from '@pnpm/dependency-path'
|
||||
import type { Lockfile, ProjectSnapshot, ResolvedDependencies } from '@pnpm/lockfile-types'
|
||||
import {
|
||||
INLINE_SPECIFIERS_FORMAT_LOCKFILE_VERSION_SUFFIX,
|
||||
@@ -10,15 +11,89 @@ export function isExperimentalInlineSpecifiersFormat (
|
||||
lockfile: InlineSpecifiersLockfile | Lockfile
|
||||
): lockfile is InlineSpecifiersLockfile {
|
||||
const { lockfileVersion } = lockfile
|
||||
return typeof lockfileVersion === 'string' && lockfileVersion.endsWith(INLINE_SPECIFIERS_FORMAT_LOCKFILE_VERSION_SUFFIX)
|
||||
return lockfileVersion.toString().startsWith('6.') || typeof lockfileVersion === 'string' && lockfileVersion.endsWith(INLINE_SPECIFIERS_FORMAT_LOCKFILE_VERSION_SUFFIX)
|
||||
}
|
||||
|
||||
export function convertToInlineSpecifiersFormat (lockfile: Lockfile): InlineSpecifiersLockfile {
|
||||
return {
|
||||
...lockfile,
|
||||
lockfileVersion: `${lockfile.lockfileVersion}${INLINE_SPECIFIERS_FORMAT_LOCKFILE_VERSION_SUFFIX}`,
|
||||
importers: mapValues(lockfile.importers, convertProjectSnapshotToInlineSpecifiersFormat),
|
||||
let importers = lockfile.importers
|
||||
let packages = lockfile.packages
|
||||
if (lockfile.lockfileVersion.toString().startsWith('6.')) {
|
||||
importers = Object.fromEntries(
|
||||
Object.entries(lockfile.importers ?? {})
|
||||
.map(([importerId, pkgSnapshot]: [string, ProjectSnapshot]) => {
|
||||
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().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(importers, convertProjectSnapshotToInlineSpecifiersFormat),
|
||||
}
|
||||
if (lockfile.lockfileVersion.toString().startsWith('6.') && newLockfile.time) {
|
||||
newLockfile.time = Object.fromEntries(
|
||||
Object.entries(newLockfile.time)
|
||||
.map(([depPath, time]) => [convertOldDepPathToNewDepPath(depPath), time])
|
||||
)
|
||||
}
|
||||
return newLockfile
|
||||
}
|
||||
|
||||
function convertOldDepPathToNewDepPath (oldDepPath: string) {
|
||||
const parsedDepPath = dp.parse(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
|
||||
}
|
||||
|
||||
function convertOldRefToNewRef (oldRef: string) {
|
||||
if (oldRef.startsWith('link:') || oldRef.startsWith('file:')) {
|
||||
return oldRef
|
||||
}
|
||||
if (oldRef.includes('/')) {
|
||||
return convertOldDepPathToNewDepPath(oldRef)
|
||||
}
|
||||
return oldRef
|
||||
}
|
||||
|
||||
export function revertFromInlineSpecifiersFormatIfNecessary (lockfile: Lockfile | InlineSpecifiersLockfile): Lockfile {
|
||||
@@ -36,11 +111,69 @@ export function revertFromInlineSpecifiersFormat (lockfile: InlineSpecifiersLock
|
||||
throw new Error(`Unable to revert lockfile from inline specifiers format. Invalid version parsed: ${originalVersionStr}`)
|
||||
}
|
||||
|
||||
return {
|
||||
...rest,
|
||||
lockfileVersion: originalVersion,
|
||||
importers: mapValues(importers, revertProjectSnapshot),
|
||||
let revertedImporters = mapValues(importers, revertProjectSnapshot)
|
||||
let packages = lockfile.packages
|
||||
if (originalVersion === 6) {
|
||||
revertedImporters = Object.fromEntries(
|
||||
Object.entries(revertedImporters ?? {})
|
||||
.map(([importerId, pkgSnapshot]: [string, ProjectSnapshot]) => {
|
||||
const newSnapshot = { ...pkgSnapshot }
|
||||
if (newSnapshot.dependencies != null) {
|
||||
newSnapshot.dependencies = mapValues(newSnapshot.dependencies, convertNewRefToOldRef)
|
||||
}
|
||||
if (newSnapshot.optionalDependencies != null) {
|
||||
newSnapshot.optionalDependencies = mapValues(newSnapshot.optionalDependencies, convertNewRefToOldRef)
|
||||
}
|
||||
if (newSnapshot.devDependencies != null) {
|
||||
newSnapshot.devDependencies = mapValues(newSnapshot.devDependencies, convertNewRefToOldRef)
|
||||
}
|
||||
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, convertNewRefToOldRef)
|
||||
}
|
||||
if (newSnapshot.optionalDependencies != null) {
|
||||
newSnapshot.optionalDependencies = mapValues(newSnapshot.optionalDependencies, convertNewRefToOldRef)
|
||||
}
|
||||
return [convertNewDepPathToOldDepPath(depPath), newSnapshot]
|
||||
})
|
||||
)
|
||||
}
|
||||
const newLockfile = {
|
||||
...rest,
|
||||
lockfileVersion: lockfileVersion.endsWith(INLINE_SPECIFIERS_FORMAT_LOCKFILE_VERSION_SUFFIX) ? originalVersion : lockfileVersion,
|
||||
packages,
|
||||
importers: revertedImporters,
|
||||
}
|
||||
if (originalVersion === 6 && newLockfile.time) {
|
||||
newLockfile.time = Object.fromEntries(
|
||||
Object.entries(newLockfile.time)
|
||||
.map(([depPath, time]) => [convertNewDepPathToOldDepPath(depPath), time])
|
||||
)
|
||||
}
|
||||
return newLockfile
|
||||
}
|
||||
|
||||
export function convertNewDepPathToOldDepPath (oldDepPath: string) {
|
||||
if (!oldDepPath.includes('@', 2)) return oldDepPath
|
||||
const index = oldDepPath.indexOf('@', oldDepPath.indexOf('/@') + 2)
|
||||
if (oldDepPath.includes('(') && index > oldDepPath.indexOf('(')) return oldDepPath
|
||||
return `${oldDepPath.substring(0, index)}/${oldDepPath.substring(index + 1)}`
|
||||
}
|
||||
|
||||
function convertNewRefToOldRef (oldRef: string) {
|
||||
if (oldRef.startsWith('link:') || oldRef.startsWith('file:')) {
|
||||
return oldRef
|
||||
}
|
||||
if (oldRef.includes('@')) {
|
||||
return convertNewDepPathToOldDepPath(oldRef)
|
||||
}
|
||||
return oldRef
|
||||
}
|
||||
|
||||
function convertProjectSnapshotToInlineSpecifiersFormat (
|
||||
|
||||
@@ -23,7 +23,7 @@ import { revertFromInlineSpecifiersFormatIfNecessary } from './experiments/inlin
|
||||
export async function readCurrentLockfile (
|
||||
virtualStoreDir: string,
|
||||
opts: {
|
||||
wantedVersion?: number
|
||||
wantedVersions?: string[]
|
||||
ignoreIncompatible: boolean
|
||||
}
|
||||
): Promise<Lockfile | null> {
|
||||
@@ -34,7 +34,7 @@ export async function readCurrentLockfile (
|
||||
export async function readWantedLockfileAndAutofixConflicts (
|
||||
pkgPath: string,
|
||||
opts: {
|
||||
wantedVersion?: number
|
||||
wantedVersions?: string[]
|
||||
ignoreIncompatible: boolean
|
||||
useGitBranchLockfile?: boolean
|
||||
mergeGitBranchLockfiles?: boolean
|
||||
@@ -52,7 +52,7 @@ export async function readWantedLockfileAndAutofixConflicts (
|
||||
export async function readWantedLockfile (
|
||||
pkgPath: string,
|
||||
opts: {
|
||||
wantedVersion?: number
|
||||
wantedVersions?: string[]
|
||||
ignoreIncompatible: boolean
|
||||
useGitBranchLockfile?: boolean
|
||||
mergeGitBranchLockfiles?: boolean
|
||||
@@ -66,7 +66,7 @@ async function _read (
|
||||
prefix: string, // only for logging
|
||||
opts: {
|
||||
autofixMergeConflicts?: boolean
|
||||
wantedVersion?: number
|
||||
wantedVersions?: string[]
|
||||
ignoreIncompatible: boolean
|
||||
}
|
||||
): Promise<{
|
||||
@@ -105,14 +105,21 @@ async function _read (
|
||||
const lockfile = revertFromInlineSpecifiersFormatIfNecessary(convertFromLockfileFileMutable(lockfileFile))
|
||||
const lockfileSemver = comverToSemver((lockfile.lockfileVersion ?? 0).toString())
|
||||
/* eslint-enable @typescript-eslint/dot-notation */
|
||||
if (typeof opts.wantedVersion !== 'number' || semver.major(lockfileSemver) === semver.major(comverToSemver(opts.wantedVersion.toString()))) {
|
||||
if (typeof opts.wantedVersion === 'number' && semver.gt(lockfileSemver, comverToSemver(opts.wantedVersion.toString()))) {
|
||||
logger.warn({
|
||||
message: `Your ${WANTED_LOCKFILE} was generated by a newer version of pnpm. ` +
|
||||
`It is a compatible version but it might get downgraded to version ${opts.wantedVersion}`,
|
||||
prefix,
|
||||
})
|
||||
}
|
||||
if (
|
||||
!opts.wantedVersions ||
|
||||
opts.wantedVersions.length === 0 ||
|
||||
opts.wantedVersions.some((wantedVersion) => {
|
||||
if (semver.major(lockfileSemver) !== semver.major(comverToSemver(wantedVersion))) return false
|
||||
if (semver.gt(lockfileSemver, comverToSemver(wantedVersion))) {
|
||||
logger.warn({
|
||||
message: `Your ${WANTED_LOCKFILE} was generated by a newer version of pnpm. ` +
|
||||
`It is a compatible version but it might get downgraded to version ${wantedVersion}`,
|
||||
prefix,
|
||||
})
|
||||
}
|
||||
return true
|
||||
})
|
||||
) {
|
||||
return { lockfile, hadConflicts }
|
||||
}
|
||||
}
|
||||
@@ -129,7 +136,7 @@ async function _read (
|
||||
export function createLockfileObject (
|
||||
importerIds: string[],
|
||||
opts: {
|
||||
lockfileVersion: number
|
||||
lockfileVersion: number | string
|
||||
}
|
||||
) {
|
||||
const importers = importerIds.reduce((acc, importerId) => {
|
||||
@@ -148,7 +155,7 @@ export function createLockfileObject (
|
||||
async function _readWantedLockfile (
|
||||
pkgPath: string,
|
||||
opts: {
|
||||
wantedVersion?: number
|
||||
wantedVersions?: string[]
|
||||
ignoreIncompatible: boolean
|
||||
useGitBranchLockfile?: boolean
|
||||
mergeGitBranchLockfiles?: boolean
|
||||
@@ -184,7 +191,7 @@ async function _mergeGitBranchLockfiles (
|
||||
prefix: string,
|
||||
opts: {
|
||||
autofixMergeConflicts?: boolean
|
||||
wantedVersion?: number
|
||||
wantedVersions?: string[]
|
||||
ignoreIncompatible: boolean
|
||||
}
|
||||
): Promise<Lockfile | null> {
|
||||
@@ -210,7 +217,7 @@ async function _readGitBranchLockfiles (
|
||||
prefix: string,
|
||||
opts: {
|
||||
autofixMergeConflicts?: boolean
|
||||
wantedVersion?: number
|
||||
wantedVersions?: string[]
|
||||
ignoreIncompatible: boolean
|
||||
}
|
||||
): Promise<Array<{
|
||||
|
||||
@@ -71,7 +71,7 @@ async function writeLockfile (
|
||||
return rimraf(lockfilePath)
|
||||
}
|
||||
|
||||
const lockfileToStringify = (opts?.useInlineSpecifiersFormat ?? false)
|
||||
const lockfileToStringify = (Boolean(opts?.useInlineSpecifiersFormat) || wantedLockfile['lockfileVersion'].toString().startsWith('6.'))
|
||||
? convertToInlineSpecifiersFormat(wantedLockfile) as unknown as Lockfile
|
||||
: wantedLockfile
|
||||
|
||||
@@ -143,7 +143,7 @@ export function normalizeLockfile (lockfile: Lockfile, opts: NormalizeLockfileOp
|
||||
}
|
||||
}
|
||||
if (lockfileToSave.time) {
|
||||
lockfileToSave.time = pruneTime(lockfileToSave.time, lockfile.importers)
|
||||
lockfileToSave.time = (lockfileToSave.lockfileVersion.toString().startsWith('6.') ? pruneTimeInLockfileV6 : pruneTime)(lockfileToSave.time, lockfile.importers)
|
||||
}
|
||||
if ((lockfileToSave.overrides != null) && isEmpty(lockfileToSave.overrides)) {
|
||||
delete lockfileToSave.overrides
|
||||
@@ -167,6 +167,41 @@ export function normalizeLockfile (lockfile: Lockfile, opts: NormalizeLockfileOp
|
||||
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] ?? {})) {
|
||||
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
|
||||
}
|
||||
|
||||
function pruneTime (time: Record<string, string>, importers: Record<string, ProjectSnapshot>): Record<string, string> {
|
||||
const rootDepPaths = new Set<string>()
|
||||
for (const importer of Object.values(importers)) {
|
||||
@@ -212,7 +247,7 @@ export async function writeLockfiles (
|
||||
}
|
||||
|
||||
const forceSharedFormat = opts?.forceSharedFormat === true
|
||||
const wantedLockfileToStringify = (opts.useInlineSpecifiersFormat ?? false)
|
||||
const wantedLockfileToStringify = (Boolean(opts.useInlineSpecifiersFormat) || opts.wantedLockfile.lockfileVersion.toString().startsWith('6.'))
|
||||
? convertToInlineSpecifiersFormat(opts.wantedLockfile) as unknown as Lockfile
|
||||
: opts.wantedLockfile
|
||||
const normalizeOpts = {
|
||||
|
||||
2
lockfile/lockfile-file/test/fixtures/3/pnpm-lock.yaml
generated
vendored
2
lockfile/lockfile-file/test/fixtures/3/pnpm-lock.yaml
generated
vendored
@@ -1 +1 @@
|
||||
version: 2
|
||||
lockfileVersion: 2
|
||||
|
||||
171
lockfile/lockfile-file/test/lockfileV6Converters.test.ts
Normal file
171
lockfile/lockfile-file/test/lockfileV6Converters.test.ts
Normal file
@@ -0,0 +1,171 @@
|
||||
import { convertToInlineSpecifiersFormat, revertFromInlineSpecifiersFormat } from '../lib/experiments/inlineSpecifiersLockfileConverters'
|
||||
|
||||
test('convertToInlineSpecifiersFormat()', () => {
|
||||
const lockfileV5 = {
|
||||
lockfileVersion: 5.0,
|
||||
importers: {
|
||||
project1: {
|
||||
specifiers: {
|
||||
foo: '^1.0.0',
|
||||
bar: '^1.0.0',
|
||||
qar: '^1.0.0',
|
||||
tarball: '^1.0.0',
|
||||
},
|
||||
dependencies: {
|
||||
foo: '1.0.0',
|
||||
tarball: '@registry.npmjs.org/is-positive/-/is-positive-1.0.0.tgz',
|
||||
},
|
||||
devDependencies: {
|
||||
bar: '/@bar/bar/1.0.0_@babel+core@2.0.0',
|
||||
},
|
||||
optionalDependencies: {
|
||||
qar: 'reg.com/qar/1.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
packages: {
|
||||
'/foo/1.0.0': {
|
||||
resolution: { integrity: '' },
|
||||
},
|
||||
'/@bar/bar/1.0.0_@babel+core@2.0.0': {
|
||||
resolution: { integrity: '' },
|
||||
},
|
||||
'reg.com/qar/1.0.0': {
|
||||
resolution: { integrity: '' },
|
||||
},
|
||||
'@registry.npmjs.org/is-positive/-/is-positive-1.0.0.tgz': {
|
||||
resolution: { integrity: '' },
|
||||
},
|
||||
},
|
||||
}
|
||||
const lockfileV6 = {
|
||||
lockfileVersion: '5-inlineSpecifiers',
|
||||
importers: {
|
||||
project1: {
|
||||
dependencies: {
|
||||
foo: {
|
||||
specifier: '^1.0.0',
|
||||
version: '1.0.0',
|
||||
},
|
||||
tarball: {
|
||||
specifier: '^1.0.0',
|
||||
version: '@registry.npmjs.org/is-positive/-/is-positive-1.0.0.tgz',
|
||||
},
|
||||
},
|
||||
devDependencies: {
|
||||
bar: {
|
||||
specifier: '^1.0.0',
|
||||
version: '/@bar/bar/1.0.0_@babel+core@2.0.0',
|
||||
},
|
||||
},
|
||||
optionalDependencies: {
|
||||
qar: {
|
||||
specifier: '^1.0.0',
|
||||
version: 'reg.com/qar/1.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
packages: {
|
||||
'/foo/1.0.0': {
|
||||
resolution: { integrity: '' },
|
||||
},
|
||||
'/@bar/bar/1.0.0_@babel+core@2.0.0': {
|
||||
resolution: { integrity: '' },
|
||||
},
|
||||
'reg.com/qar/1.0.0': {
|
||||
resolution: { integrity: '' },
|
||||
},
|
||||
'@registry.npmjs.org/is-positive/-/is-positive-1.0.0.tgz': {
|
||||
resolution: { integrity: '' },
|
||||
},
|
||||
},
|
||||
}
|
||||
expect(convertToInlineSpecifiersFormat(lockfileV5)).toEqual(lockfileV6)
|
||||
expect(revertFromInlineSpecifiersFormat(lockfileV6)).toEqual(lockfileV5)
|
||||
})
|
||||
|
||||
test('convertToInlineSpecifiersFormat() with lockfile v6', () => {
|
||||
const lockfileV5 = {
|
||||
lockfileVersion: '6.0',
|
||||
importers: {
|
||||
project1: {
|
||||
specifiers: {
|
||||
foo: '^1.0.0',
|
||||
bar: '^1.0.0',
|
||||
qar: '^1.0.0',
|
||||
tarball: '^1.0.0',
|
||||
},
|
||||
dependencies: {
|
||||
foo: '1.0.0',
|
||||
tarball: '@registry.npmjs.org/is-positive/-/is-positive-1.0.0.tgz',
|
||||
},
|
||||
devDependencies: {
|
||||
bar: '/@bar/bar/1.0.0_@babel+core@2.0.0',
|
||||
},
|
||||
optionalDependencies: {
|
||||
qar: 'reg.com/qar/1.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
packages: {
|
||||
'/foo/1.0.0': {
|
||||
resolution: { integrity: '' },
|
||||
},
|
||||
'/@bar/bar/1.0.0_@babel+core@2.0.0': {
|
||||
resolution: { integrity: '' },
|
||||
},
|
||||
'reg.com/qar/1.0.0': {
|
||||
resolution: { integrity: '' },
|
||||
},
|
||||
'@registry.npmjs.org/is-positive/-/is-positive-1.0.0.tgz': {
|
||||
resolution: { integrity: '' },
|
||||
},
|
||||
},
|
||||
}
|
||||
const lockfileV6 = {
|
||||
lockfileVersion: '6.0',
|
||||
importers: {
|
||||
project1: {
|
||||
dependencies: {
|
||||
foo: {
|
||||
specifier: '^1.0.0',
|
||||
version: '1.0.0',
|
||||
},
|
||||
tarball: {
|
||||
specifier: '^1.0.0',
|
||||
version: '@registry.npmjs.org/is-positive/-/is-positive-1.0.0.tgz',
|
||||
},
|
||||
},
|
||||
devDependencies: {
|
||||
bar: {
|
||||
specifier: '^1.0.0',
|
||||
version: '/@bar/bar@1.0.0_@babel+core@2.0.0',
|
||||
},
|
||||
},
|
||||
optionalDependencies: {
|
||||
qar: {
|
||||
specifier: '^1.0.0',
|
||||
version: 'reg.com/qar@1.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
packages: {
|
||||
'/foo@1.0.0': {
|
||||
resolution: { integrity: '' },
|
||||
},
|
||||
'/@bar/bar@1.0.0_@babel+core@2.0.0': {
|
||||
resolution: { integrity: '' },
|
||||
},
|
||||
'reg.com/qar@1.0.0': {
|
||||
resolution: { integrity: '' },
|
||||
},
|
||||
'@registry.npmjs.org/is-positive/-/is-positive-1.0.0.tgz': {
|
||||
resolution: { integrity: '' },
|
||||
},
|
||||
},
|
||||
}
|
||||
expect(convertToInlineSpecifiersFormat(lockfileV5)).toEqual(lockfileV6)
|
||||
expect(revertFromInlineSpecifiersFormat(lockfileV6)).toEqual(lockfileV5)
|
||||
})
|
||||
@@ -35,7 +35,7 @@ test('readWantedLockfile()', async () => {
|
||||
try {
|
||||
await readWantedLockfile(path.join('fixtures', '3'), {
|
||||
ignoreIncompatible: false,
|
||||
wantedVersion: 3,
|
||||
wantedVersions: ['3'],
|
||||
})
|
||||
fail()
|
||||
} catch (err: any) { // eslint-disable-line
|
||||
@@ -47,7 +47,7 @@ test('readWantedLockfile() when lockfileVersion is a string', async () => {
|
||||
{
|
||||
const lockfile = await readWantedLockfile(path.join('fixtures', '4'), {
|
||||
ignoreIncompatible: false,
|
||||
wantedVersion: 3,
|
||||
wantedVersions: ['3'],
|
||||
})
|
||||
expect(lockfile!.lockfileVersion).toEqual('v3')
|
||||
}
|
||||
@@ -55,7 +55,7 @@ test('readWantedLockfile() when lockfileVersion is a string', async () => {
|
||||
{
|
||||
const lockfile = await readWantedLockfile(path.join('fixtures', '5'), {
|
||||
ignoreIncompatible: false,
|
||||
wantedVersion: 3,
|
||||
wantedVersions: ['3'],
|
||||
})
|
||||
expect(lockfile!.lockfileVersion).toEqual('3')
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ export { PatchFile }
|
||||
|
||||
export interface Lockfile {
|
||||
importers: Record<string, ProjectSnapshot>
|
||||
lockfileVersion: number
|
||||
lockfileVersion: number | string
|
||||
time?: Record<string, string>
|
||||
packages?: PackageSnapshots
|
||||
neverBuiltDependencies?: string[]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export const WANTED_LOCKFILE = 'pnpm-lock.yaml'
|
||||
export const LOCKFILE_VERSION = 5.4
|
||||
export const LOCKFILE_VERSION_V6 = '6.0'
|
||||
|
||||
export const ENGINE_NAME = `${process.platform}-${process.arch}-node-${process.version.split('.')[0]}`
|
||||
export const LAYOUT_VERSION = 5
|
||||
|
||||
@@ -30,6 +30,10 @@ export function tryGetPackageId (registries: Registries, relDepPath: string) {
|
||||
if (relDepPath[0] !== '/') {
|
||||
return null
|
||||
}
|
||||
const sepIndex = relDepPath.indexOf('(', relDepPath.lastIndexOf('/'))
|
||||
if (sepIndex !== -1) {
|
||||
return resolve(registries, relDepPath.slice(0, sepIndex))
|
||||
}
|
||||
const underscoreIndex = relDepPath.indexOf('_', relDepPath.lastIndexOf('/'))
|
||||
if (underscoreIndex !== -1) {
|
||||
return resolve(registries, relDepPath.slice(0, underscoreIndex))
|
||||
@@ -45,7 +49,7 @@ export function refToAbsolute (
|
||||
if (reference.startsWith('link:')) {
|
||||
return null
|
||||
}
|
||||
if (!reference.includes('/')) {
|
||||
if (!reference.includes('/') || reference.includes('(') && reference.lastIndexOf('/', reference.indexOf('(')) === -1) {
|
||||
const registryName = encodeRegistry(getRegistryByPackageName(registries, pkgName))
|
||||
return `${registryName}/${pkgName}/${reference}`
|
||||
}
|
||||
@@ -83,7 +87,7 @@ export function refToRelative (
|
||||
if (reference.startsWith('file:')) {
|
||||
return reference
|
||||
}
|
||||
if (!reference.includes('/')) {
|
||||
if (!reference.includes('/') || reference.includes('(') && reference.lastIndexOf('/', reference.indexOf('(')) === -1) {
|
||||
return `/${pkgName}/${reference}`
|
||||
}
|
||||
return reference
|
||||
@@ -104,13 +108,22 @@ export function parse (dependencyPath: string) {
|
||||
const name = parts[0].startsWith('@')
|
||||
? `${parts.shift()}/${parts.shift()}` // eslint-disable-line @typescript-eslint/restrict-template-expressions
|
||||
: parts.shift()
|
||||
let version = parts.shift()
|
||||
let version = parts.join('/')
|
||||
if (version) {
|
||||
const underscoreIndex = version.indexOf('_')
|
||||
let peerSepIndex!: number
|
||||
let peersSuffix: string | undefined
|
||||
if (underscoreIndex !== -1) {
|
||||
peersSuffix = version.substring(underscoreIndex + 1)
|
||||
version = version.substring(0, underscoreIndex)
|
||||
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 (semver.valid(version)) {
|
||||
return {
|
||||
@@ -142,12 +155,17 @@ function depPathToFilenameUnescaped (depPath: string) {
|
||||
if (depPath.startsWith('/')) {
|
||||
depPath = depPath.substring(1)
|
||||
}
|
||||
const index = depPath.lastIndexOf('/')
|
||||
const index = depPath.lastIndexOf('/', depPath.includes('(') ? depPath.indexOf('(') - 1 : depPath.length)
|
||||
return `${depPath.substring(0, index)}@${depPath.slice(index + 1)}`
|
||||
}
|
||||
return depPath.replace(':', '+')
|
||||
}
|
||||
|
||||
export function createPeersFolderSuffixNewFormat (peers: Array<{ name: string, version: string }>): string {
|
||||
const folderName = peers.map(({ name, version }) => `${name}@${version}`).sort().join(')(')
|
||||
return `(${folderName})`
|
||||
}
|
||||
|
||||
export function createPeersFolderSuffix (peers: Array<{ name: string, version: string }>): string {
|
||||
const folderName = peers.map(({ name, version }) => `${name.replace('/', '+')}@${version}`).sort().join('+')
|
||||
|
||||
|
||||
@@ -82,6 +82,22 @@ test('parse()', () => {
|
||||
version: '1.0.0',
|
||||
})
|
||||
|
||||
expect(parse('example.com/foo/1.0.0(bar@2.0.0)')).toStrictEqual({
|
||||
host: 'example.com',
|
||||
isAbsolute: true,
|
||||
name: 'foo',
|
||||
peersSuffix: '(bar@2.0.0)',
|
||||
version: '1.0.0',
|
||||
})
|
||||
|
||||
expect(parse('/foo/1.0.0(@types/babel__core@7.1.14)(foo@1.0.0)')).toStrictEqual({
|
||||
host: undefined,
|
||||
isAbsolute: false,
|
||||
name: 'foo',
|
||||
peersSuffix: '(@types/babel__core@7.1.14)(foo@1.0.0)',
|
||||
version: '1.0.0',
|
||||
})
|
||||
|
||||
expect(() => parse('/foo/bar')).toThrow(/\/foo\/bar is an invalid relative dependency path/)
|
||||
})
|
||||
|
||||
@@ -95,15 +111,21 @@ test('refToAbsolute()', () => {
|
||||
expect(refToAbsolute('registry.npmjs.org/foo/1.0.0', 'foo', registries)).toEqual('registry.npmjs.org/foo/1.0.0')
|
||||
expect(refToAbsolute('/foo/1.0.0', 'foo', registries)).toEqual('registry.npmjs.org/foo/1.0.0')
|
||||
expect(refToAbsolute('/@foo/foo/1.0.0', '@foo/foo', registries)).toEqual('foo.com/@foo/foo/1.0.0')
|
||||
expect(refToAbsolute('/@foo/foo@1.0.0(@foo/bar@1.0.0)', '@foo/foo', registries)).toEqual('foo.com/@foo/foo@1.0.0(@foo/bar@1.0.0)')
|
||||
expect(refToAbsolute('/@foo/foo@1.0.0(@foo/bar@1.0.0)(@foo/qar@1.0.0)', '@foo/foo', registries)).toEqual('foo.com/@foo/foo@1.0.0(@foo/bar@1.0.0)(@foo/qar@1.0.0)')
|
||||
// linked dependencies don't have an absolute path
|
||||
expect(refToAbsolute('link:../foo', 'foo', registries)).toBeNull()
|
||||
})
|
||||
|
||||
test('refToRelative()', () => {
|
||||
expect(refToRelative('/@most/multicast/1.3.0/most@1.7.3', '@most/multicast')).toEqual('/@most/multicast/1.3.0/most@1.7.3')
|
||||
expect(refToRelative('/@most/multicast/1.3.0/most@1.7.3(@foo/bar@1.0.0)', '@most/multicast')).toEqual('/@most/multicast/1.3.0/most@1.7.3(@foo/bar@1.0.0)')
|
||||
expect(refToRelative('/@most/multicast/1.3.0/most@1.7.3(@foo/bar@1.0.0)(@foo/qar@1.0.0)', '@most/multicast')).toEqual('/@most/multicast/1.3.0/most@1.7.3(@foo/bar@1.0.0)(@foo/qar@1.0.0)')
|
||||
// linked dependencies don't have a relative path
|
||||
expect(refToRelative('link:../foo', 'foo')).toBeNull()
|
||||
expect(refToRelative('file:../tarball.tgz', 'foo')).toEqual('file:../tarball.tgz')
|
||||
expect(refToRelative('1.3.0(@foo/bar@1.0.0)', '@qar/bar')).toEqual('/@qar/bar/1.3.0(@foo/bar@1.0.0)')
|
||||
expect(refToRelative('1.3.0(@foo/bar@1.0.0)(@foo/qar@1.0.0)', '@qar/bar')).toEqual('/@qar/bar/1.3.0(@foo/bar@1.0.0)(@foo/qar@1.0.0)')
|
||||
})
|
||||
|
||||
test('relative()', () => {
|
||||
@@ -143,4 +165,5 @@ test('depPathToFilename()', () => {
|
||||
|
||||
test('tryGetPackageId', () => {
|
||||
expect(tryGetPackageId({ default: 'https://registry.npmjs.org/' }, '/foo/1.0.0_@types+babel__core@7.1.14')).toEqual('registry.npmjs.org/foo/1.0.0')
|
||||
expect(tryGetPackageId({ default: 'https://registry.npmjs.org/' }, '/foo/1.0.0(@types+babel__core@7.1.14)')).toEqual('registry.npmjs.org/foo/1.0.0')
|
||||
})
|
||||
|
||||
@@ -120,6 +120,7 @@ export interface StrictInstallOptions {
|
||||
allProjects: ProjectOptions[]
|
||||
resolveSymlinksInInjectedDirs: boolean
|
||||
dedupeDirectDeps: boolean
|
||||
useLockfileV6: boolean
|
||||
}
|
||||
|
||||
export type InstallOptions =
|
||||
@@ -206,6 +207,7 @@ const defaults = async (opts: InstallOptions) => {
|
||||
resolveSymlinksInInjectedDirs: false,
|
||||
dedupeDirectDeps: false,
|
||||
resolvePeersFromWorkspaceRoot: false,
|
||||
useLockfileV6: false,
|
||||
} as StrictInstallOptions
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { buildModules, DepsStateCache, linkBinsOfDependencies } from '@pnpm/buil
|
||||
import {
|
||||
LAYOUT_VERSION,
|
||||
LOCKFILE_VERSION,
|
||||
LOCKFILE_VERSION_V6,
|
||||
WANTED_LOCKFILE,
|
||||
} from '@pnpm/constants'
|
||||
import {
|
||||
@@ -286,7 +287,8 @@ export async function mutateModules (
|
||||
packageExtensionsChecksum,
|
||||
patchedDependencies,
|
||||
}) ||
|
||||
opts.fixLockfile
|
||||
opts.fixLockfile ||
|
||||
opts.useLockfileV6 && !ctx.wantedLockfile.lockfileVersion.toString().startsWith('6.')
|
||||
if (needsFullResolution) {
|
||||
ctx.wantedLockfile.overrides = opts.overrides
|
||||
ctx.wantedLockfile.neverBuiltDependencies = opts.neverBuiltDependencies
|
||||
@@ -836,6 +838,7 @@ const _installInContext: InstallFunction = async (projects, ctx, opts) => {
|
||||
patchedDependencies: opts.patchedDependencies,
|
||||
lockfileIncludeTarballUrl: opts.lockfileIncludeTarballUrl,
|
||||
resolvePeersFromWorkspaceRoot: opts.resolvePeersFromWorkspaceRoot,
|
||||
useLockfileV6: opts.useLockfileV6,
|
||||
}
|
||||
)
|
||||
if (!opts.include.optionalDependencies || !opts.include.devDependencies || !opts.include.dependencies) {
|
||||
@@ -873,7 +876,11 @@ const _installInContext: InstallFunction = async (projects, ctx, opts) => {
|
||||
: newLockfile
|
||||
|
||||
if (opts.updateLockfileMinorVersion) {
|
||||
newLockfile.lockfileVersion = LOCKFILE_VERSION
|
||||
if (opts.useLockfileV6 || newLockfile.lockfileVersion.toString().startsWith('6.')) {
|
||||
newLockfile.lockfileVersion = LOCKFILE_VERSION_V6
|
||||
} else {
|
||||
newLockfile.lockfileVersion = LOCKFILE_VERSION
|
||||
}
|
||||
}
|
||||
|
||||
const depsStateCache: DepsStateCache = {}
|
||||
|
||||
@@ -1374,3 +1374,44 @@ test('include tarball URL', async () => {
|
||||
expect((lockfile.packages['/@pnpm.e2e/pkg-with-1-dep/100.0.0'].resolution as TarballResolution).tarball)
|
||||
.toBe(`http://localhost:${REGISTRY_MOCK_PORT}/@pnpm.e2e%2fpkg-with-1-dep/-/pkg-with-1-dep-100.0.0.tgz`)
|
||||
})
|
||||
|
||||
test('lockfile v6', async () => {
|
||||
prepareEmpty()
|
||||
|
||||
const manifest = await addDependenciesToPackage({}, ['@pnpm.e2e/pkg-with-1-dep@100.0.0'], await testDefaults({ useLockfileV6: true }))
|
||||
|
||||
{
|
||||
const lockfile = await readYamlFile<any>(WANTED_LOCKFILE) // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
expect(lockfile.lockfileVersion).toBe('6.0')
|
||||
expect(lockfile.packages).toHaveProperty(['/@pnpm.e2e/pkg-with-1-dep@100.0.0'])
|
||||
}
|
||||
|
||||
await addDependenciesToPackage(manifest, ['@pnpm.e2e/foo@100.0.0'], await testDefaults())
|
||||
|
||||
{
|
||||
const lockfile = await readYamlFile<any>(WANTED_LOCKFILE) // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
expect(lockfile.lockfileVersion).toBe('6.0')
|
||||
expect(lockfile.packages).toHaveProperty(['/@pnpm.e2e/pkg-with-1-dep@100.0.0'])
|
||||
expect(lockfile.packages).toHaveProperty(['/@pnpm.e2e/foo@100.0.0'])
|
||||
}
|
||||
})
|
||||
|
||||
test('lockfile v5 is converted to lockfile v6', async () => {
|
||||
prepareEmpty()
|
||||
|
||||
const manifest = await addDependenciesToPackage({}, ['@pnpm.e2e/pkg-with-1-dep@100.0.0'], await testDefaults())
|
||||
|
||||
{
|
||||
const lockfile = await readYamlFile<any>(WANTED_LOCKFILE) // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
expect(lockfile.lockfileVersion).toBe(5.4)
|
||||
expect(lockfile.packages).toHaveProperty(['/@pnpm.e2e/pkg-with-1-dep/100.0.0'])
|
||||
}
|
||||
|
||||
await install(manifest, await testDefaults({ useLockfileV6: true }))
|
||||
|
||||
{
|
||||
const lockfile = await readYamlFile<any>(WANTED_LOCKFILE) // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
expect(lockfile.lockfileVersion).toBe('6.0')
|
||||
expect(lockfile.packages).toHaveProperty(['/@pnpm.e2e/pkg-with-1-dep@100.0.0'])
|
||||
}
|
||||
})
|
||||
|
||||
@@ -91,6 +91,8 @@ export interface GetContextOptions {
|
||||
|
||||
publicHoistPattern?: string[] | undefined
|
||||
forcePublicHoistPattern?: boolean
|
||||
|
||||
useLockfileV6?: boolean
|
||||
}
|
||||
|
||||
export async function getContext (
|
||||
@@ -180,6 +182,7 @@ export async function getContext (
|
||||
useGitBranchLockfile: opts.useGitBranchLockfile,
|
||||
mergeGitBranchLockfiles: opts.mergeGitBranchLockfiles,
|
||||
virtualStoreDir,
|
||||
useLockfileV6: opts.useLockfileV6,
|
||||
}),
|
||||
}
|
||||
contextLogger.debug({
|
||||
@@ -386,6 +389,7 @@ export async function getContextForSingleImporter (
|
||||
|
||||
publicHoistPattern?: string[] | undefined
|
||||
forcePublicHoistPattern?: boolean
|
||||
useLockfileV6?: boolean
|
||||
},
|
||||
alreadyPurged: boolean = false
|
||||
): Promise<PnpmSingleContext> {
|
||||
@@ -485,6 +489,7 @@ export async function getContextForSingleImporter (
|
||||
useGitBranchLockfile: opts.useGitBranchLockfile,
|
||||
mergeGitBranchLockfiles: opts.mergeGitBranchLockfiles,
|
||||
virtualStoreDir,
|
||||
useLockfileV6: opts.useLockfileV6,
|
||||
}),
|
||||
}
|
||||
packageManifestLogger.debug({
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
LOCKFILE_VERSION,
|
||||
LOCKFILE_VERSION_V6,
|
||||
WANTED_LOCKFILE,
|
||||
} from '@pnpm/constants'
|
||||
import {
|
||||
@@ -37,6 +38,7 @@ export async function readLockfiles (
|
||||
useGitBranchLockfile?: boolean
|
||||
mergeGitBranchLockfiles?: boolean
|
||||
virtualStoreDir: string
|
||||
useLockfileV6?: boolean
|
||||
}
|
||||
): Promise<{
|
||||
currentLockfile: Lockfile
|
||||
@@ -46,11 +48,12 @@ export async function readLockfiles (
|
||||
wantedLockfile: Lockfile
|
||||
lockfileHadConflicts: boolean
|
||||
}> {
|
||||
const wantedLockfileVersion = opts.useLockfileV6 ? LOCKFILE_VERSION_V6 : LOCKFILE_VERSION
|
||||
// ignore `pnpm-lock.yaml` on CI servers
|
||||
// a latest pnpm should not break all the builds
|
||||
const lockfileOpts = {
|
||||
ignoreIncompatible: opts.force || isCI,
|
||||
wantedVersion: LOCKFILE_VERSION,
|
||||
wantedVersions: [LOCKFILE_VERSION.toString(), LOCKFILE_VERSION_V6],
|
||||
useGitBranchLockfile: opts.useGitBranchLockfile,
|
||||
mergeGitBranchLockfiles: opts.mergeGitBranchLockfiles,
|
||||
}
|
||||
@@ -99,7 +102,7 @@ export async function readLockfiles (
|
||||
})()
|
||||
)
|
||||
const files = await Promise.all<Lockfile | null | undefined>(fileReads)
|
||||
const sopts = { lockfileVersion: LOCKFILE_VERSION }
|
||||
const sopts = { lockfileVersion: wantedLockfileVersion }
|
||||
const importerIds = opts.projects.map((importer) => importer.id)
|
||||
const currentLockfile = files[1] ?? createLockfileObject(importerIds, sopts)
|
||||
for (const importerId of importerIds) {
|
||||
|
||||
@@ -62,6 +62,7 @@ export function rcOptionsTypes () {
|
||||
'only',
|
||||
'optional',
|
||||
'unsafe-perm',
|
||||
'use-lockfile-v6',
|
||||
'use-running-store-server',
|
||||
'use-store-server',
|
||||
'verify-store-integrity',
|
||||
|
||||
@@ -20,7 +20,7 @@ export function depPathToRef (
|
||||
}
|
||||
if (depPath[0] === '/' && opts.alias === opts.realName) {
|
||||
const ref = depPath.replace(`/${opts.realName}/`, '')
|
||||
if (!ref.includes('/')) return ref
|
||||
if (!ref.includes('/') || !ref.replace(/(\([^)]+\))+$/, '').includes('/')) return ref
|
||||
}
|
||||
return depPath
|
||||
}
|
||||
|
||||
@@ -208,6 +208,7 @@ export async function resolveDependencies (
|
||||
projects: projectsToLink,
|
||||
virtualStoreDir: opts.virtualStoreDir,
|
||||
resolvePeersFromWorkspaceRoot: Boolean(opts.resolvePeersFromWorkspaceRoot),
|
||||
useLockfileV6: Boolean(opts.useLockfileV6),
|
||||
})
|
||||
|
||||
for (const { id, manifest } of projectsToLink) {
|
||||
|
||||
@@ -87,6 +87,7 @@ export interface ResolveDependenciesOptions {
|
||||
virtualStoreDir: string
|
||||
wantedLockfile: Lockfile
|
||||
workspacePackages: WorkspacePackages
|
||||
useLockfileV6?: boolean
|
||||
}
|
||||
|
||||
export async function resolveDependencyTree<T> (
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
PeerDependencyIssues,
|
||||
PeerDependencyIssuesByProjects,
|
||||
} from '@pnpm/types'
|
||||
import { depPathToFilename, createPeersFolderSuffix } from '@pnpm/dependency-path'
|
||||
import { depPathToFilename, createPeersFolderSuffix, createPeersFolderSuffixNewFormat } from '@pnpm/dependency-path'
|
||||
import { KeyValuePair } from 'ramda'
|
||||
import isEmpty from 'ramda/src/isEmpty'
|
||||
import mapValues from 'ramda/src/map'
|
||||
@@ -62,6 +62,7 @@ export function resolvePeers<T extends PartialResolvedPackage> (
|
||||
virtualStoreDir: string
|
||||
lockfileDir: string
|
||||
resolvePeersFromWorkspaceRoot?: boolean
|
||||
useLockfileV6?: boolean
|
||||
}
|
||||
): {
|
||||
dependenciesGraph: GenericDependenciesGraph<T>
|
||||
@@ -91,6 +92,7 @@ export function resolvePeers<T extends PartialResolvedPackage> (
|
||||
purePkgs: new Set(),
|
||||
rootDir,
|
||||
virtualStoreDir: opts.virtualStoreDir,
|
||||
useLockfileV6: opts.useLockfileV6,
|
||||
})
|
||||
if (!isEmpty(peerDependencyIssues.bad) || !isEmpty(peerDependencyIssues.missing)) {
|
||||
peerDependencyIssuesByProjects[id] = {
|
||||
@@ -176,6 +178,7 @@ function resolvePeersOfNode<T extends PartialResolvedPackage> (
|
||||
purePkgs: Set<string> // pure packages are those that don't rely on externally resolved peers
|
||||
rootDir: string
|
||||
lockfileDir: string
|
||||
useLockfileV6?: boolean
|
||||
}
|
||||
): PeersResolution {
|
||||
const node = ctx.dependenciesTree[nodeId]
|
||||
@@ -256,7 +259,7 @@ function resolvePeersOfNode<T extends PartialResolvedPackage> (
|
||||
if (isEmpty(allResolvedPeers)) {
|
||||
depPath = resolvedPackage.depPath
|
||||
} else {
|
||||
const peersFolderSuffix = createPeersFolderSuffix(
|
||||
const peersFolderSuffix = (ctx.useLockfileV6 ? createPeersFolderSuffixNewFormat : createPeersFolderSuffix)(
|
||||
Object.entries(allResolvedPeers)
|
||||
.map(([alias, nodeId]) => {
|
||||
if (nodeId.startsWith('link:')) {
|
||||
@@ -372,6 +375,7 @@ function resolvePeersOfChildren<T extends PartialResolvedPackage> (
|
||||
dependenciesTree: DependenciesTree<T>
|
||||
rootDir: string
|
||||
lockfileDir: string
|
||||
useLockfileV6?: boolean
|
||||
}
|
||||
): PeersResolution {
|
||||
const allResolvedPeers: Record<string, string> = {}
|
||||
|
||||
Reference in New Issue
Block a user