feat: install js runtime as prod dependency (#10141)

This commit is contained in:
Zoltan Kochan
2025-10-31 17:12:50 +01:00
committed by GitHub
parent d4bf2d0e60
commit efb48dcab5
22 changed files with 197 additions and 59 deletions

View File

@@ -0,0 +1,5 @@
---
"@pnpm/manifest-utils": minor
---
Added convertEnginesRuntimeToDependencies.

View File

@@ -0,0 +1,5 @@
---
"@pnpm/build-modules": major
---
Replaced fetchingBundledManifest with fetching.

View File

@@ -0,0 +1,5 @@
---
"@pnpm/types": major
---
DevEngineDependency renamed to EngineDependency.

View File

@@ -0,0 +1,27 @@
---
"@pnpm/read-project-manifest": minor
"@pnpm/resolve-dependencies": minor
"@pnpm/link-bins": minor
"@pnpm/types": minor
"pnpm": minor
---
**Node.js Runtime Installation for Dependencies.** Added support for automatic Node.js runtime installation for dependencies. pnpm will now install the Node.js version required by a dependency if that dependency declares a Node.js runtime in the "engines" field. For example:
```json
{
"engines": {
"runtime": {
"name": "node",
"version": "^24.11.0",
"onFail": "download"
}
}
}
```
If the package with the Node.js runtime dependency is a CLI app, pnpm will bind the CLI app to the required Node.js version. This ensures that, regardless of the globally installed Node.js instance, the CLI will use the compatible version of Node.js.
If the package has a `postinstall` script, that script will be executed using the specified Node.js version.
Related PR: [#10141](https://github.com/pnpm/pnpm/pull/10141)

View File

@@ -0,0 +1,5 @@
---
"@pnpm/manifest-utils": major
---
Added `@pnpm/logger` to peer dependencies.

View File

@@ -1,6 +1,7 @@
import { graphSequencer } from '@pnpm/deps.graph-sequencer'
import { type PatchInfo } from '@pnpm/patching.types'
import { type PkgIdWithPatchHash, type DepPath, type PackageManifest } from '@pnpm/types'
import { type PkgRequestFetchResult } from '@pnpm/store-controller-types'
import { type PkgIdWithPatchHash, type DepPath } from '@pnpm/types'
import { filter } from 'ramda'
export interface DependenciesGraphNode<T extends string> {
@@ -10,7 +11,7 @@ export interface DependenciesGraphNode<T extends string> {
name: string
version: string
dir: string
fetchingBundledManifest?: () => Promise<PackageManifest | undefined>
fetching?: () => Promise<PkgRequestFetchResult>
filesIndexFile?: string
hasBin: boolean
hasBundledDependencies: boolean

View File

@@ -252,7 +252,7 @@ export async function linkBinsOfDependencies<T extends string> (
const pkgs = await Promise.all(pkgNodes
.map(async (dep) => ({
location: dep.dir,
manifest: await dep.fetchingBundledManifest?.() ?? (await safeReadPackageJsonFromDir(dep.dir) as DependencyManifest) ?? {},
manifest: (await dep.fetching?.())?.bundledManifest ?? (await safeReadPackageJsonFromDir(dep.dir) as DependencyManifest) ?? {},
}))
)

View File

@@ -7,7 +7,7 @@ import { jest } from '@jest/globals'
const debug = jest.fn()
jest.unstable_mockModule('@pnpm/logger', () => {
return ({ debug, logger: () => ({ debug }) })
return ({ globalWarn: jest.fn(), debug, logger: () => ({ debug }) })
})
const { createDirectoryFetcher } = await import('@pnpm/directory-fetcher')

View File

@@ -54,19 +54,15 @@ export interface DependenciesMeta {
}
}
export interface DevEngineDependency {
export interface EngineDependency {
name: string
version?: string
onFail?: 'ignore' | 'warn' | 'error' | 'download'
}
export interface DevEngines {
os?: DevEngineDependency | DevEngineDependency[]
cpu?: DevEngineDependency | DevEngineDependency[]
libc?: DevEngineDependency | DevEngineDependency[]
runtime?: DevEngineDependency | DevEngineDependency[]
packageManager?: DevEngineDependency | DevEngineDependency[]
}
type DevEngineKey = 'os' | 'cpu' | 'libc' | 'runtime' | 'packageManager'
export type DevEngines = Partial<Record<DevEngineKey, EngineDependency | EngineDependency[]>>
export interface PublishConfig extends Record<string, unknown> {
directory?: string
@@ -114,7 +110,7 @@ export interface BaseManifest {
node?: string
npm?: string
pnpm?: string
}
} & Pick<DevEngines, 'runtime'>
devEngines?: DevEngines
cpu?: string[]
os?: string[]

View File

@@ -1,3 +1,4 @@
import fs from 'fs'
import { LOCKFILE_VERSION, WANTED_LOCKFILE } from '@pnpm/constants'
import { prepareEmpty } from '@pnpm/prepare'
import { addDependenciesToPackage, install } from '@pnpm/core'
@@ -353,3 +354,17 @@ test('installing Node.js runtime for the given supported architecture', async ()
await install(manifest, testDefaults({ frozenLockfile: true, supportedArchitectures }))
project.has(expectedBinLocation)
})
test('installing Node.js runtime, when it is set via the engines field of a dependency', async () => {
prepareEmpty()
await addDependenciesToPackage(
{},
['@pnpm.e2e/cli-with-node-engine@1.0.0'],
testDefaults({
fastUnpack: false,
onlyBuiltDependencies: ['@pnpm.e2e/cli-with-node-engine'],
neverBuiltDependencies: undefined,
})
)
expect(fs.readFileSync('node_modules/@pnpm.e2e/cli-with-node-engine/node-version', 'utf8')).toBe('v22.19.0')
})

View File

@@ -1,5 +1,5 @@
import { promises as fs, existsSync } from 'fs'
import Module from 'module'
import Module, { createRequire } from 'module'
import path from 'path'
import { getNodeBinLocationForCurrentOS, getDenoBinLocationForCurrentOS, getBunBinLocationForCurrentOS } from '@pnpm/constants'
import { PnpmError } from '@pnpm/error'
@@ -9,7 +9,7 @@ import { type Command, getBinsFromPackageManifest } from '@pnpm/package-bins'
import { readModulesDir } from '@pnpm/read-modules-dir'
import { readPackageJsonFromDir } from '@pnpm/read-package-json'
import { safeReadProjectManifestOnly } from '@pnpm/read-project-manifest'
import { type DependencyManifest, type ProjectManifest } from '@pnpm/types'
import { type EngineDependency, type DependencyManifest, type ProjectManifest } from '@pnpm/types'
import cmdShim from '@zkochan/cmd-shim'
import rimraf from '@zkochan/rimraf'
import isSubdir from 'is-subdir'
@@ -251,6 +251,17 @@ async function getPackageBins (
async function getPackageBinsFromManifest (manifest: DependencyManifest, pkgDir: string, nodeExecPath?: string): Promise<CommandInfo[]> {
const cmds = await getBinsFromPackageManifest(manifest, pkgDir)
if (manifest.engines?.runtime && runtimeHasNodeDownloaded(manifest.engines.runtime) && !nodeExecPath) {
const require = createRequire(import.meta.dirname)
// Using Node.js resolution algorithm is the most reliable way to find the Node.js
// package that comes from this CLI's dependencies, because the layout of node_modules can vary.
// In an isolated layout, it will be located in the same node_modules directory as the CLI.
// In a hoisted layout, it may be in one of the parent node_modules directories.
const nodeDir = path.dirname(require.resolve('node/CHANGELOG.md', { paths: [pkgDir] }))
if (nodeDir) {
nodeExecPath = path.join(nodeDir, IS_WINDOWS ? 'node.exe' : 'bin/node')
}
}
return cmds.map((cmd) => ({
...cmd,
ownName: cmd.name === manifest.name,
@@ -261,6 +272,13 @@ async function getPackageBinsFromManifest (manifest: DependencyManifest, pkgDir:
}))
}
function runtimeHasNodeDownloaded (runtime: EngineDependency | EngineDependency[]): boolean {
if (!Array.isArray(runtime)) {
return runtime.name === 'node' && runtime.onFail === 'download'
}
return runtime.find(({ name }) => name === 'node')?.onFail === 'download'
}
export interface LinkBinOptions {
extraNodePaths?: string[]
preferSymlinkedExecutables?: boolean

View File

@@ -43,6 +43,7 @@ import {
} from '@pnpm/types'
import * as dp from '@pnpm/dependency-path'
import { getPreferredVersionsFromLockfileAndManifests } from '@pnpm/lockfile.preferred-versions'
import { convertEnginesRuntimeToDependencies } from '@pnpm/manifest-utils'
import { type PatchInfo } from '@pnpm/patching.types'
import normalizePath from 'normalize-path'
import { pathExists } from 'path-exists'
@@ -1436,6 +1437,9 @@ async function resolveDependency (
}
}
}
if (pkg.engines?.runtime != null) {
convertEnginesRuntimeToDependencies(pkg, 'engines', 'dependencies')
}
if (!pkg.name) { // TODO: don't fail on optional dependencies
throw new PnpmError('MISSING_PACKAGE_NAME', `Can't install ${wantedDependency.bareSpecifier}: Missing package name`)
}

View File

@@ -36,7 +36,11 @@
"@pnpm/error": "workspace:*",
"@pnpm/types": "workspace:*"
},
"peerDependencies": {
"@pnpm/logger": "catalog:"
},
"devDependencies": {
"@pnpm/logger": "workspace:*",
"@pnpm/manifest-utils": "workspace:*"
},
"engines": {

View File

@@ -0,0 +1,30 @@
import { globalWarn } from '@pnpm/logger'
import {
type DependenciesField,
type EngineDependency,
type ProjectManifest,
} from '@pnpm/types'
export function convertEnginesRuntimeToDependencies (
manifest: ProjectManifest,
enginesFieldName: 'devEngines' | 'engines',
dependenciesFieldName: DependenciesField
): void {
for (const runtimeName of ['node', 'deno', 'bun']) {
const enginesFieldRuntime = manifest[enginesFieldName]?.runtime
if (enginesFieldRuntime == null || manifest[dependenciesFieldName]?.[runtimeName]) {
continue
}
const runtimes: EngineDependency[] = Array.isArray(enginesFieldRuntime) ? enginesFieldRuntime : [enginesFieldRuntime]
const runtime = runtimes.find((runtime) => runtime.name === runtimeName)
if (runtime?.onFail !== 'download') {
continue
}
if ('webcontainer' in process.versions) {
globalWarn(`Installation of ${runtimeName} versions is not supported in WebContainer`)
} else {
manifest[dependenciesFieldName] ??= {}
manifest[dependenciesFieldName]![runtimeName] = `runtime:${runtime.version}`
}
}
}

View File

@@ -6,6 +6,7 @@ import {
import { getAllUniqueSpecs } from './getAllUniqueSpecs.js'
import { getSpecFromPackageManifest } from './getSpecFromPackageManifest.js'
export * from './convertEnginesRuntimeToDependencies.js'
export * from './updateProjectManifestObject.js'
export * from './getDependencyTypeFromManifest.js'

View File

@@ -15,6 +15,9 @@
{
"path": "../../packages/error"
},
{
"path": "../../packages/logger"
},
{
"path": "../../packages/types"
}

View File

@@ -33,6 +33,7 @@
"dependencies": {
"@pnpm/error": "workspace:*",
"@pnpm/graceful-fs": "workspace:*",
"@pnpm/manifest-utils": "workspace:*",
"@pnpm/text.comments-parser": "workspace:*",
"@pnpm/types": "workspace:*",
"@pnpm/write-project-manifest": "workspace:*",

View File

@@ -1,8 +1,8 @@
import { promises as fs, type Stats } from 'fs'
import path from 'path'
import { PnpmError } from '@pnpm/error'
import { globalWarn } from '@pnpm/logger'
import { type ProjectManifest, type DevEngineDependency } from '@pnpm/types'
import { type ProjectManifest, type EngineDependency } from '@pnpm/types'
import { convertEnginesRuntimeToDependencies } from '@pnpm/manifest-utils'
import { extractComments, type CommentSpecifier } from '@pnpm/text.comments-parser'
import { writeProjectManifest } from '@pnpm/write-project-manifest'
import readYamlFile from 'read-yaml-file'
@@ -223,20 +223,8 @@ function createManifestWriter (
}
function convertManifestAfterRead (manifest: ProjectManifest): ProjectManifest {
for (const runtimeName of ['node', 'deno', 'bun']) {
if (manifest.devEngines?.runtime && !manifest.devDependencies?.[runtimeName]) {
const runtimes = Array.isArray(manifest.devEngines.runtime) ? manifest.devEngines.runtime : [manifest.devEngines.runtime]
const runtime = runtimes.find((runtime) => runtime.name === runtimeName)
if (runtime && runtime.onFail === 'download') {
if ('webcontainer' in process.versions) {
globalWarn(`Installation of ${runtimeName} versions is not supported in WebContainer`)
} else {
manifest.devDependencies ??= {}
manifest.devDependencies[runtimeName] = `runtime:${runtime.version}`
}
}
}
}
convertEnginesRuntimeToDependencies(manifest, 'devEngines', 'devDependencies')
convertEnginesRuntimeToDependencies(manifest, 'engines', 'dependencies')
return manifest
}
@@ -247,7 +235,7 @@ function convertManifestBeforeWrite (manifest: ProjectManifest): ProjectManifest
const version = nodeDep.replace(/^runtime:/, '')
manifest.devEngines ??= {}
const nodeRuntimeEntry: DevEngineDependency = {
const nodeRuntimeEntry: EngineDependency = {
name: runtimeName,
version,
onFail: 'download',

View File

@@ -24,6 +24,9 @@
{
"path": "../../text/comments-parser"
},
{
"path": "../manifest-utils"
},
{
"path": "../write-project-manifest"
}

68
pnpm-lock.yaml generated
View File

@@ -85,8 +85,8 @@ catalogs:
specifier: 0.0.1
version: 0.0.1
'@pnpm/registry-mock':
specifier: 5.0.0
version: 5.0.0
specifier: 5.1.0
version: 5.1.0
'@pnpm/semver-diff':
specifier: ^1.1.0
version: 1.1.0
@@ -998,7 +998,7 @@ importers:
version: link:../../pkg-manager/modules-yaml
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/types':
specifier: workspace:*
version: link:../../packages/types
@@ -1032,7 +1032,7 @@ importers:
dependencies:
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/store.cafs':
specifier: workspace:*
version: link:../../store/cafs
@@ -1110,7 +1110,7 @@ importers:
dependencies:
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/worker':
specifier: workspace:*
version: link:../../worker
@@ -1312,7 +1312,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@types/ramda':
specifier: 'catalog:'
version: 0.29.12
@@ -1821,7 +1821,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/testing.temp-store':
specifier: workspace:*
version: link:../../testing/temp-store
@@ -2525,7 +2525,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/types':
specifier: workspace:*
version: link:../../packages/types
@@ -2811,7 +2811,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/test-fixtures':
specifier: workspace:*
version: link:../../__utils__/test-fixtures
@@ -2968,7 +2968,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/test-ipc-server':
specifier: workspace:*
version: link:../../__utils__/test-ipc-server
@@ -4762,7 +4762,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/test-fixtures':
specifier: workspace:*
version: link:../../__utils__/test-fixtures
@@ -5058,7 +5058,7 @@ importers:
version: link:../../pkg-manifest/read-package-json
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/store-path':
specifier: workspace:*
version: link:../../store/store-path
@@ -5334,7 +5334,7 @@ importers:
version: link:../read-projects-context
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/store-path':
specifier: workspace:*
version: link:../../store/store-path
@@ -5694,7 +5694,7 @@ importers:
version: 'link:'
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/test-fixtures':
specifier: workspace:*
version: link:../../__utils__/test-fixtures
@@ -5923,7 +5923,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/test-fixtures':
specifier: workspace:*
version: link:../../__utils__/test-fixtures
@@ -6281,6 +6281,9 @@ importers:
specifier: workspace:*
version: link:../../packages/types
devDependencies:
'@pnpm/logger':
specifier: workspace:*
version: link:../../packages/logger
'@pnpm/manifest-utils':
specifier: workspace:*
version: 'link:'
@@ -6318,6 +6321,9 @@ importers:
'@pnpm/logger':
specifier: 'catalog:'
version: 1001.0.0
'@pnpm/manifest-utils':
specifier: workspace:*
version: link:../manifest-utils
'@pnpm/text.comments-parser':
specifier: workspace:*
version: link:../../text/comments-parser
@@ -6542,7 +6548,7 @@ importers:
version: link:../pkg-manifest/read-project-manifest
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/run-npm':
specifier: workspace:*
version: link:../exec/run-npm
@@ -6893,7 +6899,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/test-fixtures':
specifier: workspace:*
version: link:../../__utils__/test-fixtures
@@ -7023,7 +7029,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/test-ipc-server':
specifier: workspace:*
version: link:../../__utils__/test-ipc-server
@@ -7760,7 +7766,7 @@ importers:
version: link:../../pkg-manifest/read-package-json
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/test-fixtures':
specifier: workspace:*
version: link:../../__utils__/test-fixtures
@@ -7827,7 +7833,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/workspace.filter-packages-from-dir':
specifier: workspace:*
version: link:../../workspace/filter-packages-from-dir
@@ -7912,7 +7918,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/test-fixtures':
specifier: workspace:*
version: link:../../__utils__/test-fixtures
@@ -8269,7 +8275,7 @@ importers:
version: link:../../__utils__/prepare
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@types/archy':
specifier: 'catalog:'
version: 0.0.33
@@ -8526,7 +8532,7 @@ importers:
version: link:../../store/package-store
'@pnpm/registry-mock':
specifier: 'catalog:'
version: 5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
version: 5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))
'@pnpm/store-controller-types':
specifier: workspace:*
version: link:../../store/store-controller-types
@@ -10464,8 +10470,8 @@ packages:
resolution: {integrity: sha512-UY5ZFl8jTgWpPMp3qwVt1z455gDLGh4aAna7ufqsJP9qhI6lr9scFpnEamjpA51Y3MJMBtnML8KATmH6RY+NHQ==}
engines: {node: '>=18.12'}
'@pnpm/registry-mock@5.0.0':
resolution: {integrity: sha512-ZARk5IXPQumdF6K+TYZABuFZSruYvRy2W5+iyFqP9lbQOYfGNry4W64zNnHIs7RHfvponlFS88tZnAGmU/7Kow==}
'@pnpm/registry-mock@5.1.0':
resolution: {integrity: sha512-XHJmKZG296Nk86WCnmz1hBHcj8Yp8EWNsSz+iY9Ludm5L8S2l0xRYmz8TzyIxpsb5o9q8jahZ781bpW7NAuQFQ==}
engines: {node: '>=18.12'}
hasBin: true
peerDependencies:
@@ -11091,41 +11097,49 @@ packages:
resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-arm64-musl@1.11.1':
resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==}
cpu: [riscv64]
os: [linux]
libc: [musl]
'@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-x64-gnu@1.11.1':
resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@unrs/resolver-binding-linux-x64-musl@1.11.1':
resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==}
cpu: [x64]
os: [linux]
libc: [musl]
'@unrs/resolver-binding-wasm32-wasi@1.11.1':
resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==}
@@ -14000,9 +14014,11 @@ packages:
lodash.clone@4.3.2:
resolution: {integrity: sha512-Yc/0UmZvWkFsbx7NB4feSX5bSX03SR0ft8CTkI8RCb3w/TzT71HXew2iNDm0aml93P49tIR/NJHOIoE+XEKz9A==}
deprecated: This package is deprecated. Use structuredClone instead.
lodash.clone@4.5.0:
resolution: {integrity: sha512-GhrVeweiTD6uTmmn5hV/lzgCQhccwReIVRLHp7LT4SopOjqEZ5BbX8b5WWEtAKasjmy8hR7ZPwsYlxRCku5odg==}
deprecated: This package is deprecated. Use structuredClone instead.
lodash.deburr@4.1.0:
resolution: {integrity: sha512-m/M1U1f3ddMCs6Hq2tAsYThTBDaAKFDX3dwDo97GEYzamXi9SqUpjWi/Rrj/gf3X2n8ktwgZrlP1z6E3v/IExQ==}
@@ -18684,7 +18700,7 @@ snapshots:
read-yaml-file: 2.1.0
strip-bom: 4.0.0
'@pnpm/registry-mock@5.0.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))':
'@pnpm/registry-mock@5.1.0(verdaccio@6.1.6(encoding@0.1.13)(typanion@3.14.0))':
dependencies:
anonymous-npm-registry-client: 0.3.2
execa: 5.1.1

View File

@@ -78,7 +78,7 @@ catalog:
'@pnpm/npm-package-arg': ^2.0.0
'@pnpm/os.env.path-extender': ^2.0.3
'@pnpm/patch-package': 0.0.1
'@pnpm/registry-mock': 5.0.0
'@pnpm/registry-mock': 5.1.0
'@pnpm/semver-diff': ^1.1.0
'@pnpm/tabtab': ^0.5.4
'@pnpm/tgz-fixtures': 0.0.0

View File

@@ -0,0 +1,11 @@
import fs from 'fs'
import { prepare } from '@pnpm/prepare'
import { execPnpm } from '../utils/index.js'
test('installing a CLI tool that requires a specific version of Node.js to be installed alongside it', async () => {
prepare()
await execPnpm(['add', '@pnpm.e2e/cli-with-node-engine@1.0.0'])
await execPnpm(['exec', 'cli-with-node-engine'])
expect(fs.readFileSync('node-version', 'utf8')).toBe('v22.19.0')
})