Skip to content

Commit 0485f58

Browse files
feat: support devEngines.runtime filed in package.json
1 parent bc4d19a commit 0485f58

16 files changed

Lines changed: 506 additions & 37 deletions

File tree

‎.changeset/sour-moments-grab.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"fnm": minor
3+
---
4+
5+
Support resolving `devEngines.runtime` field via `--resolve-dev-engines` flag

‎docs/commands.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,9 @@ Options:
255255
[default: auto]
256256
[possible values: auto, never, always]
257257
258+
--default
259+
Set the installed version as the default version
260+
258261
--log-level <LOG_LEVEL>
259262
The log level of fnm commands
260263

‎docs/configuration.md‎

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Here’s a list of these features and capabilities:
1010

1111
**✅ Highly recommended**
1212

13-
`--use-on-cd` appends output to `fnm env`'s output that will hook into your shell upon changing directories, and will switch the Node.js version based on the requirements of the current directory, based on `.node-version` or `.nvmrc` (or `packages.json#engines#node` if `--resolve-engines` was enabled).
13+
`--use-on-cd` appends output to `fnm env`'s output that will hook into your shell upon changing directories, and will switch the Node.js version based on the requirements of the current directory, based on `.node-version` or `.nvmrc` (or `packages.json#devEngines#runtime` if `--resolve-dev-engines` was enabled and `packages.json#engines#node` if `--resolve-engines` was enabled).
1414

1515
This allows you do avoid thinking about `fnm use`, and only `cd <DIR>` to make it work.
1616

@@ -52,6 +52,41 @@ error: Can't find version in dotfiles. Please provide a version manually to the
5252

5353
Runs [`corepack enable`](https://nodejs.org/api/corepack.html#enabling-the-feature) when a new version of Node.js is installed. Experimental due to the fact Corepack itself is experimental.
5454

55+
### `--resolve-dev-engines`
56+
57+
Treats Node version in `packages.json#devEngines#runtime` as a valid Node.js version file ("dotfile"). So, if you have a package.json with the following content:
58+
59+
```json
60+
{
61+
"devEngines": {
62+
"runtime": {
63+
"name": "node",
64+
"version": ">=20 <21"
65+
}
66+
}
67+
}
68+
```
69+
70+
or:
71+
72+
```json
73+
{
74+
"devEngines": {
75+
"runtime": [
76+
{
77+
"name": "node",
78+
"version": ">=20 <21"
79+
}
80+
]
81+
}
82+
}
83+
```
84+
85+
Then:
86+
87+
- `fnm install` will install the latest satisfying Node.js 20.x version available in the Node.js dist server
88+
- `fnm use` will use the latest satisfying Node.js 20.x version available on your system, or prompt to install if no version matched.
89+
5590
### `--resolve-engines`
5691

5792
**🧪 Experimental**

‎e2e/__snapshots__/basic.test.ts.snap‎

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,61 @@ if [ "$(node --version)" != "v8.11.3" ]; then
4242
fi"
4343
`;
4444

45+
exports[`Bash package.json devEngines.runtime (array): Bash 1`] = `
46+
"set -e
47+
eval "$(fnm env --resolve-dev-engines)"
48+
fnm install
49+
fnm use
50+
if [ "$(node --version)" != "v8.11.3" ]; then
51+
echo "Expected node version to be v8.11.3. Got $(node --version)"
52+
exit 1
53+
fi"
54+
`;
55+
56+
exports[`Bash package.json devEngines.runtime with semver range (array): Bash 1`] = `
57+
"set -e
58+
eval "$(fnm env --resolve-dev-engines)"
59+
fnm install
60+
fnm use
61+
if [ "$(node --version)" != "v6.17.0" ]; then
62+
echo "Expected node version to be v6.17.0. Got $(node --version)"
63+
exit 1
64+
fi"
65+
`;
66+
67+
exports[`Bash package.json devEngines.runtime with semver range: Bash 1`] = `
68+
"set -e
69+
eval "$(fnm env --resolve-dev-engines)"
70+
fnm install
71+
fnm use
72+
if [ "$(node --version)" != "v6.17.0" ]; then
73+
echo "Expected node version to be v6.17.0. Got $(node --version)"
74+
exit 1
75+
fi"
76+
`;
77+
78+
exports[`Bash package.json devEngines.runtime: Bash 1`] = `
79+
"set -e
80+
eval "$(fnm env --resolve-dev-engines)"
81+
fnm install
82+
fnm use
83+
if [ "$(node --version)" != "v8.11.3" ]; then
84+
echo "Expected node version to be v8.11.3. Got $(node --version)"
85+
exit 1
86+
fi"
87+
`;
88+
89+
exports[`Bash package.json engines.node & devEngines.runtime: Bash 1`] = `
90+
"set -e
91+
eval "$(fnm env --resolve-dev-engines --resolve-engines)"
92+
fnm install
93+
fnm use
94+
if [ "$(node --version)" != "v8.11.3" ]; then
95+
echo "Expected node version to be v8.11.3. Got $(node --version)"
96+
exit 1
97+
fi"
98+
`;
99+
45100
exports[`Bash package.json engines.node with semver range: Bash 1`] = `
46101
"set -e
47102
eval "$(fnm env --resolve-engines)"
@@ -128,6 +183,61 @@ if test "$____test____" != "v8.11.3"
128183
end"
129184
`;
130185

186+
exports[`Fish package.json devEngines.runtime (array): Fish 1`] = `
187+
"fnm env --resolve-dev-engines | source
188+
fnm install
189+
fnm use
190+
set ____test____ (node --version)
191+
if test "$____test____" != "v8.11.3"
192+
echo "Expected node version to be v8.11.3. Got $____test____"
193+
exit 1
194+
end"
195+
`;
196+
197+
exports[`Fish package.json devEngines.runtime with semver range (array): Fish 1`] = `
198+
"fnm env --resolve-dev-engines | source
199+
fnm install
200+
fnm use
201+
set ____test____ (node --version)
202+
if test "$____test____" != "v6.17.0"
203+
echo "Expected node version to be v6.17.0. Got $____test____"
204+
exit 1
205+
end"
206+
`;
207+
208+
exports[`Fish package.json devEngines.runtime with semver range: Fish 1`] = `
209+
"fnm env --resolve-dev-engines | source
210+
fnm install
211+
fnm use
212+
set ____test____ (node --version)
213+
if test "$____test____" != "v6.17.0"
214+
echo "Expected node version to be v6.17.0. Got $____test____"
215+
exit 1
216+
end"
217+
`;
218+
219+
exports[`Fish package.json devEngines.runtime: Fish 1`] = `
220+
"fnm env --resolve-dev-engines | source
221+
fnm install
222+
fnm use
223+
set ____test____ (node --version)
224+
if test "$____test____" != "v8.11.3"
225+
echo "Expected node version to be v8.11.3. Got $____test____"
226+
exit 1
227+
end"
228+
`;
229+
230+
exports[`Fish package.json engines.node & devEngines.runtime: Fish 1`] = `
231+
"fnm env --resolve-dev-engines --resolve-engines | source
232+
fnm install
233+
fnm use
234+
set ____test____ (node --version)
235+
if test "$____test____" != "v8.11.3"
236+
echo "Expected node version to be v8.11.3. Got $____test____"
237+
exit 1
238+
end"
239+
`;
240+
131241
exports[`Fish package.json engines.node with semver range: Fish 1`] = `
132242
"fnm env --resolve-engines | source
133243
fnm install
@@ -202,6 +312,46 @@ fnm use v8.11.3
202312
if ( "$(node --version)" -ne "v8.11.3" ) { echo "Expected node version to be v8.11.3. Got $(node --version)"; exit 1 }"
203313
`;
204314

315+
exports[`PowerShell package.json devEngines.runtime (array): PowerShell 1`] = `
316+
"$ErrorActionPreference = "Stop"
317+
fnm env --resolve-dev-engines | Out-String | Invoke-Expression
318+
fnm install
319+
fnm use
320+
if ( "$(node --version)" -ne "v8.11.3" ) { echo "Expected node version to be v8.11.3. Got $(node --version)"; exit 1 }"
321+
`;
322+
323+
exports[`PowerShell package.json devEngines.runtime with semver range (array): PowerShell 1`] = `
324+
"$ErrorActionPreference = "Stop"
325+
fnm env --resolve-dev-engines | Out-String | Invoke-Expression
326+
fnm install
327+
fnm use
328+
if ( "$(node --version)" -ne "v6.17.0" ) { echo "Expected node version to be v6.17.0. Got $(node --version)"; exit 1 }"
329+
`;
330+
331+
exports[`PowerShell package.json devEngines.runtime with semver range: PowerShell 1`] = `
332+
"$ErrorActionPreference = "Stop"
333+
fnm env --resolve-dev-engines | Out-String | Invoke-Expression
334+
fnm install
335+
fnm use
336+
if ( "$(node --version)" -ne "v6.17.0" ) { echo "Expected node version to be v6.17.0. Got $(node --version)"; exit 1 }"
337+
`;
338+
339+
exports[`PowerShell package.json devEngines.runtime: PowerShell 1`] = `
340+
"$ErrorActionPreference = "Stop"
341+
fnm env --resolve-dev-engines | Out-String | Invoke-Expression
342+
fnm install
343+
fnm use
344+
if ( "$(node --version)" -ne "v8.11.3" ) { echo "Expected node version to be v8.11.3. Got $(node --version)"; exit 1 }"
345+
`;
346+
347+
exports[`PowerShell package.json engines.node & devEngines.runtime: PowerShell 1`] = `
348+
"$ErrorActionPreference = "Stop"
349+
fnm env --resolve-dev-engines --resolve-engines | Out-String | Invoke-Expression
350+
fnm install
351+
fnm use
352+
if ( "$(node --version)" -ne "v8.11.3" ) { echo "Expected node version to be v8.11.3. Got $(node --version)"; exit 1 }"
353+
`;
354+
205355
exports[`PowerShell package.json engines.node with semver range: PowerShell 1`] = `
206356
"$ErrorActionPreference = "Stop"
207357
fnm env --resolve-engines | Out-String | Invoke-Expression
@@ -276,6 +426,61 @@ if [ "$(node --version)" != "v8.11.3" ]; then
276426
fi"
277427
`;
278428

429+
exports[`Zsh package.json devEngines.runtime (array): Zsh 1`] = `
430+
"set -e
431+
eval "$(fnm env --resolve-dev-engines)"
432+
fnm install
433+
fnm use
434+
if [ "$(node --version)" != "v8.11.3" ]; then
435+
echo "Expected node version to be v8.11.3. Got $(node --version)"
436+
exit 1
437+
fi"
438+
`;
439+
440+
exports[`Zsh package.json devEngines.runtime with semver range (array): Zsh 1`] = `
441+
"set -e
442+
eval "$(fnm env --resolve-dev-engines)"
443+
fnm install
444+
fnm use
445+
if [ "$(node --version)" != "v6.17.0" ]; then
446+
echo "Expected node version to be v6.17.0. Got $(node --version)"
447+
exit 1
448+
fi"
449+
`;
450+
451+
exports[`Zsh package.json devEngines.runtime with semver range: Zsh 1`] = `
452+
"set -e
453+
eval "$(fnm env --resolve-dev-engines)"
454+
fnm install
455+
fnm use
456+
if [ "$(node --version)" != "v6.17.0" ]; then
457+
echo "Expected node version to be v6.17.0. Got $(node --version)"
458+
exit 1
459+
fi"
460+
`;
461+
462+
exports[`Zsh package.json devEngines.runtime: Zsh 1`] = `
463+
"set -e
464+
eval "$(fnm env --resolve-dev-engines)"
465+
fnm install
466+
fnm use
467+
if [ "$(node --version)" != "v8.11.3" ]; then
468+
echo "Expected node version to be v8.11.3. Got $(node --version)"
469+
exit 1
470+
fi"
471+
`;
472+
473+
exports[`Zsh package.json engines.node & devEngines.runtime: Zsh 1`] = `
474+
"set -e
475+
eval "$(fnm env --resolve-dev-engines --resolve-engines)"
476+
fnm install
477+
fnm use
478+
if [ "$(node --version)" != "v8.11.3" ]; then
479+
echo "Expected node version to be v8.11.3. Got $(node --version)"
480+
exit 1
481+
fi"
482+
`;
483+
279484
exports[`Zsh package.json engines.node with semver range: Zsh 1`] = `
280485
"set -e
281486
eval "$(fnm env --resolve-engines)"

‎e2e/basic.test.ts‎

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,97 @@ for (const shell of [Bash, Zsh, Fish, PowerShell, WinCmd]) {
6868
.execute(shell)
6969
})
7070

71+
test(`package.json devEngines.runtime`, async () => {
72+
await writeFile(
73+
join(testCwd(), "package.json"),
74+
JSON.stringify({
75+
devEngines: { runtime: { name: "node", version: "8.11.3" } },
76+
}),
77+
)
78+
await script(shell)
79+
.then(shell.env({ resolveDevEngines: true }))
80+
.then(shell.call("fnm", ["install"]))
81+
.then(shell.call("fnm", ["use"]))
82+
.then(testNodeVersion(shell, "v8.11.3"))
83+
.takeSnapshot(shell)
84+
.execute(shell)
85+
})
86+
87+
test(`package.json devEngines.runtime with semver range`, async () => {
88+
await writeFile(
89+
join(testCwd(), "package.json"),
90+
JSON.stringify({
91+
devEngines: { runtime: { name: "node", version: "^6 < 6.17.1" } },
92+
}),
93+
)
94+
await script(shell)
95+
.then(shell.env({ resolveDevEngines: true }))
96+
.then(shell.call("fnm", ["install"]))
97+
.then(shell.call("fnm", ["use"]))
98+
.then(testNodeVersion(shell, "v6.17.0"))
99+
.takeSnapshot(shell)
100+
.execute(shell)
101+
})
102+
103+
test(`package.json devEngines.runtime (array)`, async () => {
104+
await writeFile(
105+
join(testCwd(), "package.json"),
106+
JSON.stringify({
107+
devEngines: {
108+
runtime: [
109+
{ name: "bun", version: "1.0.0" },
110+
{ name: "node", version: "8.11.3" },
111+
],
112+
},
113+
}),
114+
)
115+
await script(shell)
116+
.then(shell.env({ resolveDevEngines: true }))
117+
.then(shell.call("fnm", ["install"]))
118+
.then(shell.call("fnm", ["use"]))
119+
.then(testNodeVersion(shell, "v8.11.3"))
120+
.takeSnapshot(shell)
121+
.execute(shell)
122+
})
123+
124+
test(`package.json devEngines.runtime with semver range (array)`, async () => {
125+
await writeFile(
126+
join(testCwd(), "package.json"),
127+
JSON.stringify({
128+
devEngines: {
129+
runtime: [
130+
{ name: "bun", version: "1.0.0" },
131+
{ name: "node", version: "^6 < 6.17.1" },
132+
],
133+
},
134+
}),
135+
)
136+
await script(shell)
137+
.then(shell.env({ resolveDevEngines: true }))
138+
.then(shell.call("fnm", ["install"]))
139+
.then(shell.call("fnm", ["use"]))
140+
.then(testNodeVersion(shell, "v6.17.0"))
141+
.takeSnapshot(shell)
142+
.execute(shell)
143+
})
144+
145+
test(`package.json engines.node & devEngines.runtime`, async () => {
146+
await writeFile(
147+
join(testCwd(), "package.json"),
148+
JSON.stringify({
149+
engines: { node: "1.0.0" },
150+
devEngines: { runtime: { name: "node", version: "8.11.3" } },
151+
}),
152+
)
153+
await script(shell)
154+
.then(shell.env({ resolveDevEngines: true, resolveEngines: true }))
155+
.then(shell.call("fnm", ["install"]))
156+
.then(shell.call("fnm", ["use"]))
157+
.then(testNodeVersion(shell, "v8.11.3"))
158+
.takeSnapshot(shell)
159+
.execute(shell)
160+
})
161+
71162
test(`resolves partial semver`, async () => {
72163
await script(shell)
73164
.then(shell.env({}))

0 commit comments

Comments
 (0)