feat: support Plug'n'Play

ref #2902
PR #2908
This commit is contained in:
Zoltan Kochan
2020-10-11 13:12:02 +03:00
committed by GitHub
parent 3a83db4072
commit f591fdeeb9
34 changed files with 278 additions and 26 deletions

View File

@@ -0,0 +1,5 @@
---
"@pnpm/config": minor
---
New option added: `node-linker`. When `node-linker` is set to `pnp`, pnpm will create a `.pnp.js` file.

View File

@@ -0,0 +1,6 @@
---
"@pnpm/build-modules": minor
"@pnpm/lifecycle": minor
---
New option added: extraEnv. extraEnv allows to pass environment variables that will be set for the child process.

View File

@@ -0,0 +1,5 @@
---
"@pnpm/lifecycle": minor
---
New function exported: `makeNodeRequireOption()`.

View File

@@ -0,0 +1,6 @@
---
"@pnpm/headless": minor
"supi": patch
---
New option added: `enablePnp`. When enablePnp is true, a `.pnp.js` file is generated.

View File

@@ -0,0 +1,5 @@
---
"@pnpm/plugin-commands-script-runners": minor
---
Scripts support Plug'n'Play.

View File

@@ -0,0 +1,5 @@
---
"@pnpm/lockfile-to-pnp": minor
---
CLI command removed.

1
.gitignore vendored
View File

@@ -6,6 +6,7 @@ npm-debug.log*
# Dependency directory
**/node_modules/**
_node_modules
.pnp.js
# Coverage directory used by tools like istanbul
coverage

View File

@@ -18,6 +18,7 @@ export default async (
childConcurrency?: number
depsToBuild?: Set<string>
extraBinPaths?: string[]
extraEnv?: Record<string, string>
lockfileDir: string
optional: boolean
rawConfig: object
@@ -63,6 +64,7 @@ async function buildDependency (
depGraph: DependenciesGraph,
opts: {
extraBinPaths?: string[]
extraEnv?: Record<string, string>
lockfileDir: string
optional: boolean
rawConfig: object
@@ -79,6 +81,7 @@ async function buildDependency (
const hasSideEffects = await runPostinstallHooks({
depPath,
extraBinPaths: opts.extraBinPaths,
extraEnv: opts.extraEnv,
initCwd: opts.lockfileDir,
optional: depNode.optional,
pkgRoot: depNode.dir,

View File

@@ -114,6 +114,7 @@ export interface Config {
publishBranch?: string
recursiveInstall?: boolean
symlink: boolean
enablePnp?: boolean
registries: Registries
ignoreWorkspaceRootCheck: boolean

View File

@@ -51,6 +51,7 @@ export const types = Object.assign({
loglevel: ['silent', 'error', 'warn', 'info', 'debug'],
'modules-dir': String,
'network-concurrency': Number,
'node-linker': ['pnp'],
'npm-path': String,
offline: Boolean,
'package-import-method': ['auto', 'hardlink', 'clone', 'copy'],
@@ -376,6 +377,7 @@ export default async (
if (!pnpmConfig.noProxy) {
pnpmConfig.noProxy = getProcessEnv('no_proxy')
}
pnpmConfig.enablePnp = pnpmConfig['nodeLinker'] === 'pnp'
return { config: pnpmConfig, warnings }
}

View File

@@ -81,6 +81,7 @@
"@pnpm/lifecycle": "workspace:9.4.0",
"@pnpm/link-bins": "workspace:5.3.14",
"@pnpm/lockfile-file": "workspace:3.0.14",
"@pnpm/lockfile-to-pnp": "workspace:^0.2.0",
"@pnpm/lockfile-utils": "workspace:2.0.16",
"@pnpm/modules-cleaner": "workspace:10.0.11",
"@pnpm/modules-yaml": "workspace:8.0.2",

View File

@@ -17,7 +17,10 @@ import {
filterLockfileByImportersAndEngine,
} from '@pnpm/filter-lockfile'
import hoist from '@pnpm/hoist'
import { runLifecycleHooksConcurrently } from '@pnpm/lifecycle'
import {
runLifecycleHooksConcurrently,
makeNodeRequireOption,
} from '@pnpm/lifecycle'
import linkBins, { linkBinsOfPackages } from '@pnpm/link-bins'
import {
getLockfileImporterId,
@@ -27,6 +30,7 @@ import {
readWantedLockfile,
writeCurrentLockfile,
} from '@pnpm/lockfile-file'
import { writePnpFile } from '@pnpm/lockfile-to-pnp'
import {
nameVerFromPkgSnapshot,
packageIdFromSnapshot,
@@ -70,6 +74,7 @@ export interface HeadlessOptions {
nodeVersion: string
pnpmVersion: string
}
enablePnp?: boolean
engineStrict: boolean
extraBinPaths?: string[]
ignoreScripts: boolean
@@ -211,6 +216,17 @@ export default async (opts: HeadlessOptions) => {
virtualStoreDir,
} as LockfileToDepGraphOptions
)
if (opts.enablePnp) {
const importerNames = R.fromPairs(
opts.projects.map(({ manifest, id }) => [id, manifest.name ?? id])
)
await writePnpFile(filteredLockfile, {
importerNames,
lockfileDir,
virtualStoreDir,
registries: opts.registries,
})
}
const depNodes = R.values(graph)
statsLogger.debug({
@@ -313,9 +329,14 @@ export default async (opts: HeadlessOptions) => {
if (opts.hoistPattern) {
extraBinPaths.unshift(path.join(virtualStoreDir, 'node_modules/.bin'))
}
let extraEnv: Record<string, string> | undefined
if (opts.enablePnp) {
extraEnv = makeNodeRequireOption(path.join(opts.lockfileDir, '.pnp.js'))
}
await buildModules(graph, Array.from(directNodes), {
childConcurrency: opts.childConcurrency,
extraBinPaths,
extraEnv,
lockfileDir,
optional: opts.include.optionalDependencies,
rawConfig: opts.rawConfig,

View File

@@ -752,11 +752,13 @@ test('installing in a workspace', async (t) => {
t.end()
})
test('installing with no symlinks', async (t) => {
test('installing with no symlinks but with PnP', async (t) => {
const prefix = path.join(fixtures, 'simple')
await rimraf(path.join(prefix, 'node_modules'))
await rimraf(path.join(prefix, '.pnp.js'))
await headless(await testDefaults({
enablePnp: true,
lockfileDir: prefix,
symlink: false,
}))
@@ -767,6 +769,7 @@ test('installing with no symlinks', async (t) => {
const project = assertProject(t, prefix)
t.ok(await project.readCurrentLockfile())
t.ok(await project.readModulesManifest())
t.ok(await exists(path.join(prefix, '.pnp.js')))
t.end()
})

View File

@@ -36,6 +36,9 @@
{
"path": "../lockfile-file"
},
{
"path": "../lockfile-to-pnp"
},
{
"path": "../lockfile-utils"
},

View File

@@ -4,6 +4,12 @@ import runLifecycleHooksConcurrently, { RunLifecycleHooksConcurrentlyOptions } f
import path = require('path')
import exists = require('path-exists')
export function makeNodeRequireOption (modulePath: string) {
let { NODE_OPTIONS } = process.env
NODE_OPTIONS = `${NODE_OPTIONS ?? ''} --require=${modulePath}`.trim()
return { NODE_OPTIONS }
}
export default runLifecycleHook
export {
runLifecycleHooksConcurrently,

View File

@@ -8,6 +8,7 @@ export interface RunLifecycleHookOptions {
args?: string[]
depPath: string
extraBinPaths?: string[]
extraEnv?: Record<string, string>
initCwd?: string
optional?: boolean
pkgRoot: string
@@ -54,6 +55,7 @@ export default async function runLifecycleHook (
dir: opts.rootModulesDir,
extraBinPaths: opts.extraBinPaths ?? [],
extraEnv: {
...opts.extraEnv,
INIT_CWD: opts.initCwd ?? process.cwd(),
PNPM_SCRIPT_SRC_DIR: opts.pkgRoot,
},

View File

@@ -10,14 +10,6 @@
pnpm add -g @pnpm/lockfile-to-pnp
```
## Usage
1. Run `pnpm install` to create an up-to-date lockfile and virtual store.
1. Run `lockfile-to-pnp` in the directory that has a lockfile.
1. When executing a Node script, use the generated `.pnp.js` file to hook Node's resolver.
E.g., if to run `index.js`, use this command: `node --require ./.pnp.js index.js`
## License
MIT

View File

@@ -4,7 +4,6 @@
"description": "Creates a Plug'n'Play file from a pnpm-lock.yaml",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
"bin": "lib/createPnpBin.js",
"engines": {
"node": ">=10.16"
},

View File

@@ -1,6 +0,0 @@
#!/usr/bin/env node
import { lockfileToPnp } from '.'
lockfileToPnp(process.cwd())
.then(() => console.log('Created .pnp.js'))
.catch((err) => console.error(err))

View File

@@ -40,7 +40,7 @@ export async function lockfileToPnp (lockfileDir: string) {
export async function writePnpFile (
lockfile: Lockfile,
opts: {
importerNames: { [importerId: string]: string }
importerNames: Record<string, string>
lockfileDir: string
virtualStoreDir: string
registries: Registries

View File

@@ -54,6 +54,7 @@
"@pnpm/sort-packages": "workspace:1.0.13",
"@pnpm/types": "workspace:6.2.0",
"p-limit": "^3.0.2",
"path-exists": "^4.0.0",
"ramda": "^0.27.1",
"realpath-missing": "^1.0.0",
"render-help": "^1.0.0"

View File

@@ -1,8 +1,10 @@
import { RecursiveSummary, throwOnCommandFail } from '@pnpm/cli-utils'
import { Config, types } from '@pnpm/config'
import PnpmError from '@pnpm/error'
import { makeNodeRequireOption } from '@pnpm/lifecycle'
import logger from '@pnpm/logger'
import sortPackages from '@pnpm/sort-packages'
import existsInDir from './existsInDir'
import {
PARALLEL_OPTION_HELP,
shorthands as runShorthands,
@@ -55,7 +57,7 @@ export async function handler (
rawConfig: object
sort?: boolean
workspaceConcurrency?: number
} & Pick<Config, 'recursive'>,
} & Pick<Config, 'recursive' | 'workspaceDir'>,
params: string[]
) {
if (!opts.recursive) {
@@ -71,15 +73,22 @@ export async function handler (
const chunks = opts.sort
? sortPackages(opts.selectedProjectsGraph)
: [Object.keys(opts.selectedProjectsGraph).sort()]
const existsPnp = existsInDir.bind(null, '.pnp.js')
const workspacePnpPath = opts.workspaceDir && await existsPnp(opts.workspaceDir)
for (const chunk of chunks) {
await Promise.all(chunk.map((prefix: string) =>
limitRun(async () => {
try {
const pnpPath = workspacePnpPath ?? await existsPnp(prefix)
const extraEnv = pnpPath
? makeNodeRequireOption(pnpPath)
: {}
await execa(params[0], params.slice(1), {
cwd: prefix,
env: {
...process.env,
...extraEnv,
PNPM_PACKAGE_NAME: opts.selectedProjectsGraph[prefix].package.manifest.name,
},
stdio: 'inherit',

View File

@@ -0,0 +1,8 @@
import path = require('path')
import exists = require('path-exists')
export default async (entityName: string, dir: string) => {
const entityPath = path.join(dir, entityName)
if (await exists(entityPath)) return entityPath
return undefined
}

View File

@@ -7,8 +7,12 @@ import { CompletionFunc } from '@pnpm/command'
import { FILTERING, UNIVERSAL_OPTIONS } from '@pnpm/common-cli-options-help'
import { Config, types as allTypes } from '@pnpm/config'
import PnpmError from '@pnpm/error'
import runLifecycleHooks from '@pnpm/lifecycle'
import runLifecycleHooks, {
makeNodeRequireOption,
RunLifecycleHookOptions,
} from '@pnpm/lifecycle'
import { ProjectManifest } from '@pnpm/types'
import existsInDir from './existsInDir'
import runRecursive, { RecursiveRunOpts } from './runRecursive'
import path = require('path')
import R = require('ramda')
@@ -144,7 +148,7 @@ so you may run "pnpm -w ${scriptName}"`,
}
throw new PnpmError('NO_SCRIPT', `Missing script: ${scriptName}`)
}
const lifecycleOpts = {
const lifecycleOpts: RunLifecycleHookOptions = {
depPath: dir,
extraBinPaths: opts.extraBinPaths,
pkgRoot: dir,
@@ -155,6 +159,12 @@ so you may run "pnpm -w ${scriptName}"`,
stdio: 'inherit',
unsafePerm: true, // when running scripts explicitly, assume that they're trusted.
}
const existsPnp = existsInDir.bind(null, '.pnp.js')
const pnpPath = (opts.workspaceDir && await existsPnp(opts.workspaceDir)) ??
await existsPnp(dir)
if (pnpPath) {
lifecycleOpts.extraEnv = makeNodeRequireOption(pnpPath)
}
if (manifest.scripts?.[`pre${scriptName}`]) {
await runLifecycleHooks(`pre${scriptName}`, manifest, lifecycleOpts)
}

View File

@@ -1,9 +1,13 @@
import { RecursiveSummary, throwOnCommandFail } from '@pnpm/cli-utils'
import { Config } from '@pnpm/config'
import PnpmError from '@pnpm/error'
import runLifecycleHooks from '@pnpm/lifecycle'
import runLifecycleHooks, {
makeNodeRequireOption,
RunLifecycleHookOptions,
} from '@pnpm/lifecycle'
import logger from '@pnpm/logger'
import sortPackages from '@pnpm/sort-packages'
import existsInDir from './existsInDir'
import path = require('path')
import pLimit = require('p-limit')
import realpathMissing = require('realpath-missing')
@@ -41,6 +45,8 @@ export default async (
opts.workspaceConcurrency === 1 ||
packageChunks.length === 1 && packageChunks[0].length === 1
) ? 'inherit' : 'pipe'
const existsPnp = existsInDir.bind(null, '.pnp.js')
const workspacePnpPath = opts.workspaceDir && await existsPnp(opts.workspaceDir)
for (const chunk of packageChunks) {
await Promise.all(chunk.map((prefix: string) =>
@@ -55,7 +61,7 @@ export default async (
}
hasCommand++
try {
const lifecycleOpts = {
const lifecycleOpts: RunLifecycleHookOptions = {
depPath: prefix,
extraBinPaths: opts.extraBinPaths,
pkgRoot: prefix,
@@ -65,6 +71,10 @@ export default async (
stdio,
unsafePerm: true, // when running scripts explicitly, assume that they're trusted.
}
const pnpPath = workspacePnpPath ?? await existsPnp(prefix)
if (pnpPath) {
lifecycleOpts.extraEnv = makeNodeRequireOption(pnpPath)
}
if (pkg.package.manifest.scripts[`pre${scriptName}`]) {
await runLifecycleHooks(`pre${scriptName}`, pkg.package.manifest, lifecycleOpts)
}

View File

@@ -9,6 +9,8 @@ import execa = require('execa')
import fs = require('mz/fs')
import test = require('tape')
const pnpmBin = path.join(__dirname, '../../pnpm/bin/pnpm.js')
test('pnpm recursive exec', async (t) => {
preparePackages(t, [
{
@@ -248,3 +250,73 @@ test('pnpm exec fails without the recursive=true option', async (t) => {
t.end()
})
test('pnpm recursive exec works with PnP', async (t) => {
preparePackages(t, [
{
name: 'project-1',
version: '1.0.0',
dependencies: {
'json-append': '1',
},
scripts: {
build: 'node -e "process.stdout.write(\'project-1\')" | json-append ../output1.json && node -e "process.stdout.write(\'project-1\')" | json-append ../output2.json',
},
},
{
name: 'project-2',
version: '1.0.0',
dependencies: {
'json-append': '1',
'project-1': '1',
},
scripts: {
build: 'node -e "process.stdout.write(\'project-2\')" | json-append ../output1.json',
postbuild: 'node -e "process.stdout.write(\'project-2-postbuild\')" | json-append ../output1.json',
prebuild: 'node -e "process.stdout.write(\'project-2-prebuild\')" | json-append ../output1.json',
},
},
{
name: 'project-3',
version: '1.0.0',
dependencies: {
'json-append': '1',
'project-1': '1',
},
scripts: {
build: 'node -e "process.stdout.write(\'project-3\')" | json-append ../output2.json',
},
},
])
const { selectedProjectsGraph } = await readProjects(process.cwd(), [])
await execa(pnpmBin, [
'install',
'-r',
'--registry',
REGISTRY,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
], {
env: {
NPM_CONFIG_NODE_LINKER: 'pnp',
NPM_CONFIG_SYMLINK: 'false',
},
})
await exec.handler({
...DEFAULT_OPTS,
recursive: true,
selectedProjectsGraph,
}, ['npm', 'run', 'build'])
const outputs1 = await import(path.resolve('output1.json')) as string[]
const outputs2 = await import(path.resolve('output2.json')) as string[]
t.deepEqual(outputs1, ['project-1', 'project-2-prebuild', 'project-2', 'project-2-postbuild'])
t.deepEqual(outputs2, ['project-1', 'project-3'])
t.end()
})

View File

@@ -366,3 +366,27 @@ test('if a script is not found but is present in the root, print an info message
t.ok(err.hint.includes('But build is present in the root'))
t.end()
})
test('scripts work with PnP', async (t) => {
prepare(t, {
scripts: {
foo: 'node -e "process.stdout.write(\'foo\')" | json-append ./output.json',
},
})
await execa(pnpmBin, ['add', 'json-append@1'], {
env: {
NPM_CONFIG_NODE_LINKER: 'pnp',
NPM_CONFIG_SYMLINK: 'false',
},
})
await run.handler({
dir: process.cwd(),
extraBinPaths: [],
rawConfig: {},
}, ['foo'])
const scriptsRan = await import(path.resolve('output.json'))
t.deepEqual(scriptsRan, ['foo'])
t.end()
})

View File

@@ -27,6 +27,7 @@
"@pnpm/lifecycle": "workspace:9.4.0",
"@pnpm/link-bins": "workspace:5.3.14",
"@pnpm/lockfile-file": "workspace:3.0.14",
"@pnpm/lockfile-to-pnp": "workspace:^0.2.0",
"@pnpm/lockfile-utils": "workspace:2.0.16",
"@pnpm/lockfile-walker": "workspace:3.0.4",
"@pnpm/manifest-utils": "workspace:1.1.1",

View File

@@ -16,6 +16,7 @@ export interface StrictInstallOptions {
forceSharedLockfile: boolean
frozenLockfile: boolean
frozenLockfileIfExists: boolean
enablePnp: boolean
extraBinPaths: string[]
useLockfile: boolean
linkWorkspacePackagesDepth: number
@@ -88,6 +89,7 @@ const defaults = async (opts: InstallOptions) => {
return {
childConcurrency: 5,
depth: 0,
enablePnp: false,
engineStrict: false,
force: false,
forceSharedLockfile: false,

View File

@@ -12,7 +12,9 @@ import PnpmError from '@pnpm/error'
import getContext, { PnpmContext, ProjectOptions } from '@pnpm/get-context'
import headless from '@pnpm/headless'
import {
makeNodeRequireOption,
runLifecycleHooksConcurrently,
RunLifecycleHooksConcurrentlyOptions,
} from '@pnpm/lifecycle'
import linkBins, { linkBinsOfPackages } from '@pnpm/link-bins'
import {
@@ -21,6 +23,7 @@ import {
writeLockfiles,
writeWantedLockfile,
} from '@pnpm/lockfile-file'
import { writePnpFile } from '@pnpm/lockfile-to-pnp'
import logger, { streamParser } from '@pnpm/logger'
import { getAllDependenciesFromManifest } from '@pnpm/manifest-utils'
import { write as writeModulesYaml } from '@pnpm/modules-yaml'
@@ -180,6 +183,7 @@ export async function mutateModules (
pnpmVersion: opts.packageManager.name === 'pnpm' ? opts.packageManager.version : '',
},
currentLockfile: ctx.currentLockfile,
enablePnp: opts.enablePnp,
engineStrict: opts.engineStrict,
extraBinPaths: opts.extraBinPaths,
force: opts.force,
@@ -232,7 +236,7 @@ export async function mutateModules (
const projectsToInstall = [] as ImporterToUpdate[]
const projectsToBeInstalled = ctx.projects.filter(({ mutation }) => mutation === 'install') as Array<{ buildIndex: number, rootDir: string, manifest: ProjectManifest, modulesDir: string }>
const scriptsOpts = {
const scriptsOpts: RunLifecycleHooksConcurrentlyOptions = {
extraBinPaths: opts.extraBinPaths,
rawConfig: opts.rawConfig,
shellEmulator: opts.shellEmulator,
@@ -402,6 +406,9 @@ export async function mutateModules (
})
if (!opts.ignoreScripts) {
if (opts.enablePnp) {
scriptsOpts.extraEnv = makeNodeRequireOption(path.join(opts.lockfileDir, '.pnp.js'))
}
await runLifecycleHooksConcurrently(['install', 'postinstall', 'prepublish', 'prepare'],
projectsToBeInstalled,
opts.childConcurrency,
@@ -682,6 +689,17 @@ async function installInContext (
}
)
await finishLockfileUpdates()
if (opts.enablePnp) {
const importerNames = R.fromPairs(
projects.map(({ manifest, id }) => [id, manifest.name ?? id])
)
await writePnpFile(result.currentLockfile, {
importerNames,
lockfileDir: ctx.lockfileDir,
virtualStoreDir: ctx.virtualStoreDir,
registries: opts.registries,
})
}
ctx.pendingBuilds = ctx.pendingBuilds
.filter((relDepPath) => !result.removedDepPaths.has(relDepPath))
@@ -698,10 +716,15 @@ async function installInContext (
const depPaths = Object.keys(dependenciesGraph)
const rootNodes = depPaths.filter((depPath) => dependenciesGraph[depPath].depth === 0)
let extraEnv: Record<string, string> | undefined
if (opts.enablePnp) {
extraEnv = makeNodeRequireOption(path.join(opts.lockfileDir, '.pnp.js'))
}
await buildModules(dependenciesGraph, rootNodes, {
childConcurrency: opts.childConcurrency,
depsToBuild: new Set(result.newDepPaths),
extraBinPaths: ctx.extraBinPaths,
extraEnv,
lockfileDir: ctx.lockfileDir,
optional: opts.include.optionalDependencies,
rawConfig: opts.rawConfig,

View File

@@ -56,6 +56,24 @@ test('run pre/postinstall scripts', async (t: tape.Test) => {
t.ok(lockfile.packages['/pre-and-postinstall-scripts-example/1.0.0'].requiresBuild, 'requiresBuild: true added to lockfile')
})
test('run pre/postinstall scripts, when PnP is used and no symlinks', async (t: tape.Test) => {
prepareEmpty(t)
await addDependenciesToPackage({},
['pre-and-postinstall-scripts-example'],
await testDefaults({
fastUnpack: false,
enablePnp: true,
symlink: false,
targetDependenciesField: 'devDependencies',
})
)
const pkgDir = 'node_modules/.pnpm/pre-and-postinstall-scripts-example@1.0.0/node_modules/pre-and-postinstall-scripts-example'
t.notOk(await exists(path.resolve(pkgDir, 'generated-by-prepare.js')))
t.ok(await exists(path.resolve(pkgDir, 'generated-by-preinstall.js')))
t.ok(await exists(path.resolve(pkgDir, 'generated-by-postinstall.js')))
})
test('testing that the bins are linked when the package with the bins was already in node_modules', async (t: tape.Test) => {
const project = prepareEmpty(t)

View File

@@ -1228,7 +1228,7 @@ test('memory consumption is under control on huge package with many peer depende
t.ok(await exists('pnpm-lock.yaml'), 'lockfile created')
})
test('installing with no symlinks', async (t) => {
test('installing with no symlinks with PnP', async (t) => {
const project = prepareEmpty(t)
await addDependenciesToPackage(
@@ -1237,7 +1237,11 @@ test('installing with no symlinks', async (t) => {
version: '0.0.0',
},
['rimraf@2.7.1'],
await testDefaults({ fastUnpack: false, symlink: false })
await testDefaults({
enablePnp: true,
fastUnpack: false,
symlink: false,
})
)
t.deepEqual(await fs.readdir(path.resolve('node_modules')), ['.bin', '.modules.yaml', '.pnpm'])
@@ -1245,6 +1249,7 @@ test('installing with no symlinks', async (t) => {
t.ok(await project.readCurrentLockfile())
t.ok(await project.readModulesManifest())
t.ok(await exists(path.resolve('.pnp.js')))
t.end()
})

View File

@@ -42,6 +42,9 @@
{
"path": "../lockfile-file"
},
{
"path": "../lockfile-to-pnp"
},
{
"path": "../lockfile-utils"
},

6
pnpm-lock.yaml generated
View File

@@ -672,6 +672,7 @@ importers:
'@pnpm/lifecycle': 'link:../lifecycle'
'@pnpm/link-bins': 'link:../link-bins'
'@pnpm/lockfile-file': 'link:../lockfile-file'
'@pnpm/lockfile-to-pnp': 'link:../lockfile-to-pnp'
'@pnpm/lockfile-utils': 'link:../lockfile-utils'
'@pnpm/modules-cleaner': 'link:../modules-cleaner'
'@pnpm/modules-yaml': 'link:../modules-yaml'
@@ -726,6 +727,7 @@ importers:
'@pnpm/lifecycle': 'workspace:9.4.0'
'@pnpm/link-bins': 'workspace:5.3.14'
'@pnpm/lockfile-file': 'workspace:3.0.14'
'@pnpm/lockfile-to-pnp': 'workspace:^0.2.0'
'@pnpm/lockfile-utils': 'workspace:2.0.16'
'@pnpm/logger': ^3.2.2
'@pnpm/modules-cleaner': 'workspace:10.0.11'
@@ -2000,6 +2002,7 @@ importers:
'@pnpm/sort-packages': 'link:../sort-packages'
'@pnpm/types': 'link:../types'
p-limit: 3.0.2
path-exists: 4.0.0
ramda: 0.27.1
realpath-missing: 1.0.0
render-help: 1.0.0
@@ -2033,6 +2036,7 @@ importers:
execa: ^4.0.3
mz: ^2.7.0
p-limit: ^3.0.2
path-exists: ^4.0.0
ramda: ^0.27.1
realpath-missing: ^1.0.0
render-help: ^1.0.0
@@ -2680,6 +2684,7 @@ importers:
'@pnpm/lifecycle': 'link:../lifecycle'
'@pnpm/link-bins': 'link:../link-bins'
'@pnpm/lockfile-file': 'link:../lockfile-file'
'@pnpm/lockfile-to-pnp': 'link:../lockfile-to-pnp'
'@pnpm/lockfile-utils': 'link:../lockfile-utils'
'@pnpm/lockfile-walker': 'link:../lockfile-walker'
'@pnpm/manifest-utils': 'link:../manifest-utils'
@@ -2776,6 +2781,7 @@ importers:
'@pnpm/lifecycle': 'workspace:9.4.0'
'@pnpm/link-bins': 'workspace:5.3.14'
'@pnpm/lockfile-file': 'workspace:3.0.14'
'@pnpm/lockfile-to-pnp': 'workspace:^0.2.0'
'@pnpm/lockfile-utils': 'workspace:2.0.16'
'@pnpm/lockfile-walker': 'workspace:3.0.4'
'@pnpm/logger': ^3.2.2