Skip to content

Commit eae9848

Browse files
jycouetbenmccannmanuel3108
authored
feat(add): Add minimum Node.js version warning if below 16. (#625)
* feat(add): Add minimum Node.js version warning if below 16. * new line* * add version helper in code to be used everywhere (+ tests) * rmv semver in cli * using minimumRequirement 18.3 for node * Update .changeset with 18.3 Co-authored-by: Ben McCann <[email protected]> * minor improvements --------- Co-authored-by: Ben McCann <[email protected]> Co-authored-by: Manuel Serret <[email protected]>
1 parent ca3c8b5 commit eae9848

File tree

5 files changed

+112
-0
lines changed

5 files changed

+112
-0
lines changed

.changeset/great-bags-smoke.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'sv': patch
3+
---
4+
5+
feat: print warning if using Node.js version below 18.3

packages/cli/utils/common.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as p from '@clack/prompts';
44
import type { Argument, HelpConfiguration, Option } from 'commander';
55
import { UnsupportedError } from './errors.ts';
66
import process from 'node:process';
7+
import { isVersionUnsupportedBelow } from '@sveltejs/cli-core';
78

89
const NO_PREFIX = '--no-';
910
let options: readonly Option[] = [];
@@ -75,6 +76,15 @@ type MaybePromise = () => Promise<void> | void;
7576
export async function runCommand(action: MaybePromise): Promise<void> {
7677
try {
7778
p.intro(`Welcome to the Svelte CLI! ${pc.gray(`(v${pkg.version})`)}`);
79+
80+
const minimumVersion = '18.3.0';
81+
const unsupported = isVersionUnsupportedBelow(process.versions.node, minimumVersion);
82+
if (unsupported) {
83+
p.log.warn(
84+
`You are using Node.js ${pc.red(process.versions.node)}, please upgrade to Node.js ${pc.green(minimumVersion)} or higher.`
85+
);
86+
}
87+
7888
await action();
7989
p.outro("You're all set!");
8090
} catch (e) {

packages/core/common.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
type Version = {
2+
major?: number;
3+
minor?: number;
4+
patch?: number;
5+
};
6+
7+
export function splitVersion(str: string): Version {
8+
const [major, minor, patch] = str?.split('.') ?? [];
9+
10+
function toVersionNumber(val: string | undefined): number | undefined {
11+
return val !== undefined && val !== '' && !isNaN(Number(val)) ? Number(val) : undefined;
12+
}
13+
14+
return {
15+
major: toVersionNumber(major),
16+
minor: toVersionNumber(minor),
17+
patch: toVersionNumber(patch)
18+
};
19+
}
20+
21+
export function isVersionUnsupportedBelow(
22+
versionStr: string,
23+
belowStr: string
24+
): boolean | undefined {
25+
const version = splitVersion(versionStr);
26+
const below = splitVersion(belowStr);
27+
28+
if (version.major === undefined || below.major === undefined) return undefined;
29+
if (version.major < below.major) return true;
30+
if (version.major > below.major) return false;
31+
32+
if (version.minor === undefined || below.minor === undefined) {
33+
if (version.major === below.major) return false;
34+
else return true;
35+
}
36+
if (version.minor < below.minor) return true;
37+
if (version.minor > below.minor) return false;
38+
39+
if (version.patch === undefined || below.patch === undefined) {
40+
if (version.minor === below.minor) return false;
41+
else return true;
42+
}
43+
if (version.patch < below.patch) return true;
44+
if (version.patch > below.patch) return false;
45+
if (version.patch === below.patch) return false;
46+
47+
return undefined;
48+
}

packages/core/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export { log } from '@clack/prompts';
33
export { default as colors } from 'picocolors';
44
export { default as dedent } from 'dedent';
55
export * as utils from './utils.ts';
6+
export { isVersionUnsupportedBelow, splitVersion } from './common.ts';
67

78
export type * from './addon/processors.ts';
89
export type * from './addon/options.ts';

packages/core/tests/common.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { expect, describe, it } from 'vitest';
2+
import { splitVersion, isVersionUnsupportedBelow } from '../common.ts';
3+
4+
describe('versionSplit', () => {
5+
const combinationsVersionSplit = [
6+
{ version: '18.13.0', expected: { major: 18, minor: 13, patch: 0 } },
7+
{ version: 'x.13.0', expected: { major: undefined, minor: 13, patch: 0 } },
8+
{ version: '18.y.0', expected: { major: 18, minor: undefined, patch: 0 } },
9+
{ version: '18.13.z', expected: { major: 18, minor: 13, patch: undefined } },
10+
{ version: '18', expected: { major: 18, minor: undefined, patch: undefined } },
11+
{ version: '18.13', expected: { major: 18, minor: 13, patch: undefined } },
12+
{ version: 'invalid', expected: { major: undefined, minor: undefined, patch: undefined } }
13+
];
14+
it.each(combinationsVersionSplit)(
15+
'should return the correct version for $version',
16+
({ version, expected }) => {
17+
expect(splitVersion(version)).toEqual(expected);
18+
}
19+
);
20+
});
21+
22+
describe('minimumRequirement', () => {
23+
const combinationsMinimumRequirement = [
24+
{ version: '17', below: '18.3.0', expected: true },
25+
{ version: '18.2', below: '18.3.0', expected: true },
26+
{ version: '18.3.0', below: '18.3.1', expected: true },
27+
{ version: '18.3.1', below: '18.3.0', expected: false },
28+
{ version: '18.3.0', below: '18.3.0', expected: false },
29+
{ version: '18.3.0', below: '18.3', expected: false },
30+
{ version: '18.3.1', below: '18.3', expected: false },
31+
{ version: '18.3.1', below: '18', expected: false },
32+
{ version: '18', below: '18', expected: false },
33+
{ version: 'a', below: 'b', expected: undefined },
34+
{ version: '18.3', below: '18.3', expected: false },
35+
{ version: '18.4', below: '18.3', expected: false },
36+
{ version: '18.2', below: '18.3', expected: true },
37+
38+
// if it's undefined, we can't say anything...
39+
{ version: undefined!, below: '18.3', expected: undefined },
40+
{ version: '', below: '18.3', expected: undefined }
41+
] as const;
42+
it.each(combinationsMinimumRequirement)(
43+
'($version below $below) should be $expected',
44+
({ version, below, expected }) => {
45+
expect(isVersionUnsupportedBelow(version, below)).toEqual(expected);
46+
}
47+
);
48+
});

0 commit comments

Comments
 (0)