mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-23 23:29:17 -05:00
fix: node runtime is not moved to dependencies on pnpm add (#10210)
close #10209
This commit is contained in:
6
.changeset/large-suits-scream.md
Normal file
6
.changeset/large-suits-scream.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/read-project-manifest": patch
|
||||
"pnpm": patch
|
||||
---
|
||||
|
||||
Node.js runtime is not added to "dependencies" on `pnpm add`, if there's a `engines.runtime` setting declared in `package.json` [#10209](https://github.com/pnpm/pnpm/issues/10209).
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"engines": {
|
||||
"runtime": {
|
||||
"name": "node",
|
||||
"version": "24",
|
||||
"onFail": "download"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -229,41 +229,51 @@ function convertManifestAfterRead (manifest: ProjectManifest): ProjectManifest {
|
||||
}
|
||||
|
||||
function convertManifestBeforeWrite (manifest: ProjectManifest): ProjectManifest {
|
||||
for (const runtimeName of ['node', 'deno', 'bun']) {
|
||||
const nodeDep = manifest.devDependencies?.[runtimeName]
|
||||
if (typeof nodeDep === 'string' && nodeDep.startsWith('runtime:')) {
|
||||
const version = nodeDep.replace(/^runtime:/, '')
|
||||
manifest.devEngines ??= {}
|
||||
convertDependenciesToEnginesRuntime(manifest, 'devDependencies', 'devEngines')
|
||||
convertDependenciesToEnginesRuntime(manifest, 'dependencies', 'engines')
|
||||
return manifest
|
||||
}
|
||||
|
||||
const nodeRuntimeEntry: EngineDependency = {
|
||||
function convertDependenciesToEnginesRuntime (
|
||||
manifest: ProjectManifest,
|
||||
dependenciesFieldName: 'dependencies' | 'devDependencies',
|
||||
enginesFieldName: 'engines' | 'devEngines'
|
||||
): void {
|
||||
for (const runtimeName of ['node', 'deno', 'bun']) {
|
||||
const dep = manifest[dependenciesFieldName]?.[runtimeName]
|
||||
if (typeof dep === 'string' && dep.startsWith('runtime:')) {
|
||||
const version = dep.replace(/^runtime:/, '')
|
||||
manifest[enginesFieldName] ??= {}
|
||||
|
||||
const runtimeEntry: EngineDependency = {
|
||||
name: runtimeName,
|
||||
version,
|
||||
onFail: 'download',
|
||||
}
|
||||
|
||||
if (!manifest.devEngines.runtime) {
|
||||
manifest.devEngines.runtime = nodeRuntimeEntry
|
||||
} else if (Array.isArray(manifest.devEngines.runtime)) {
|
||||
const existing = manifest.devEngines.runtime.find(({ name }) => name === runtimeName)
|
||||
const enginesField = manifest[enginesFieldName]!
|
||||
if (!enginesField.runtime) {
|
||||
enginesField.runtime = runtimeEntry
|
||||
} else if (Array.isArray(enginesField.runtime)) {
|
||||
const existing = enginesField.runtime.find(({ name }) => name === runtimeName)
|
||||
if (existing) {
|
||||
Object.assign(existing, nodeRuntimeEntry)
|
||||
Object.assign(existing, runtimeEntry)
|
||||
} else {
|
||||
manifest.devEngines.runtime.push(nodeRuntimeEntry)
|
||||
enginesField.runtime.push(runtimeEntry)
|
||||
}
|
||||
} else if (manifest.devEngines.runtime.name === runtimeName) {
|
||||
Object.assign(manifest.devEngines.runtime, nodeRuntimeEntry)
|
||||
} else if (enginesField.runtime.name === runtimeName) {
|
||||
Object.assign(enginesField.runtime, runtimeEntry)
|
||||
} else {
|
||||
manifest.devEngines.runtime = [
|
||||
manifest.devEngines.runtime,
|
||||
nodeRuntimeEntry,
|
||||
enginesField.runtime = [
|
||||
enginesField.runtime,
|
||||
runtimeEntry,
|
||||
]
|
||||
}
|
||||
if (manifest.devDependencies) {
|
||||
delete manifest.devDependencies[runtimeName]
|
||||
if (manifest[dependenciesFieldName]) {
|
||||
delete manifest[dependenciesFieldName][runtimeName]
|
||||
}
|
||||
}
|
||||
}
|
||||
return manifest
|
||||
}
|
||||
|
||||
const dependencyKeys = new Set([
|
||||
|
||||
@@ -63,6 +63,37 @@ test('readProjectManifest() converts devEngines runtime to devDependencies', asy
|
||||
})
|
||||
})
|
||||
|
||||
test('readProjectManifest() converts engines runtime to dependencies', async () => {
|
||||
const dir = f.prepare('package-json-with-engines')
|
||||
const { manifest, writeProjectManifest } = await tryReadProjectManifest(dir)
|
||||
expect(manifest).toStrictEqual(
|
||||
{
|
||||
dependencies: {
|
||||
node: 'runtime:24',
|
||||
},
|
||||
engines: {
|
||||
runtime: {
|
||||
name: 'node',
|
||||
version: '24',
|
||||
onFail: 'download',
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
await writeProjectManifest(manifest!)
|
||||
const pkgJson = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8'))
|
||||
expect(pkgJson).toStrictEqual({
|
||||
dependencies: {},
|
||||
engines: {
|
||||
runtime: {
|
||||
name: 'node',
|
||||
version: '24',
|
||||
onFail: 'download',
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test.each([
|
||||
{
|
||||
name: 'creates devEngines when it is missing',
|
||||
|
||||
Reference in New Issue
Block a user