Skip to content

Commit 3c5e902

Browse files
committed
refactor(@angular/cli): centralize Node.js version checks into a new utility
Makes it effort less to update a supported Node.js version
1 parent 15794dc commit 3c5e902

File tree

5 files changed

+89
-27
lines changed

5 files changed

+89
-27
lines changed

packages/angular/cli/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ npm_package(
172172
],
173173
stamp_files = [
174174
"src/utilities/version.js",
175+
"src/utilities/node-version.js",
175176
],
176177
tags = ["release-package"],
177178
deps = RUNTIME_ASSETS + [

packages/angular/cli/bin/ng.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
'use strict';
1313

1414
const path = require('path');
15+
const nodeUtils = require('../src/utilities/node-version');
1516

1617
// Error if the external CLI appears to be used inside a google3 context.
1718
if (process.cwd().split(path.sep).includes('google3')) {
@@ -42,10 +43,10 @@ if (rawCommandName === '--get-yargs-completions' || rawCommandName === 'completi
4243
// This node version check ensures that extremely old versions of node are not used.
4344
// These may not support ES2015 features such as const/let/async/await/etc.
4445
// These would then crash with a hard to diagnose error message.
45-
const [major, minor, patch] = process.versions.node.split('.', 3).map((part) => Number(part));
46+
const [major] = process.versions.node.split('.', 1).map((part) => Number(part));
4647

4748
if (major % 2 === 1) {
48-
// Allow new odd numbered releases with a warning (currently v17+)
49+
// Allow new odd numbered releases with a warning.
4950
console.warn(
5051
'Node.js version ' +
5152
process.version +
@@ -55,17 +56,15 @@ if (major % 2 === 1) {
5556
);
5657

5758
require('./bootstrap');
58-
} else if (
59-
major < 22 ||
60-
(major === 22 && minor < 22) ||
61-
(major === 24 && minor < 13 && patch < 1)
62-
) {
59+
} else if (!nodeUtils.isNodeVersionSupported()) {
6360
// Error and exit if less than 22.22 or 24.13.1
6461
console.error(
6562
'Node.js version ' +
6663
process.version +
6764
' detected.\n' +
68-
'The Angular CLI requires a minimum Node.js version of v22.22 or v24.13.1.\n\n' +
65+
'The Angular CLI requires a minimum Node.js version of ' +
66+
nodeUtils.supportedNodeVersions.map((v) => 'v' + v).join(' or ') +
67+
'.\n\n' +
6968
'Please update your Node.js version or visit https://nodejs.org/ for additional instructions.\n',
7069
);
7170

packages/angular/cli/lib/cli/index.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,18 @@ import { runCommand } from '../../src/command-builder/command-runner';
1313
import { colors, supportColor } from '../../src/utilities/color';
1414
import { ngDebug } from '../../src/utilities/environment-options';
1515
import { writeErrorToLogFile } from '../../src/utilities/log-file';
16+
import { isNodeVersionMinSupported, supportedNodeVersions } from '../../src/utilities/node-version';
1617

1718
export { VERSION } from '../../src/utilities/version';
1819

19-
const MIN_NODEJS_VERSION = [22, 22] as const;
20-
2120
/* eslint-disable no-console */
2221
export default async function (options: { cliArgs: string[] }) {
2322
// This node version check ensures that the requirements of the project instance of the CLI are met
24-
const [major, minor] = process.versions.node.split('.').map((part) => Number(part));
25-
if (
26-
major < MIN_NODEJS_VERSION[0] ||
27-
(major === MIN_NODEJS_VERSION[0] && minor < MIN_NODEJS_VERSION[1])
28-
) {
23+
24+
if (!isNodeVersionMinSupported()) {
2925
process.stderr.write(
3026
`Node.js version ${process.version} detected.\n` +
31-
`The Angular CLI requires a minimum of v${MIN_NODEJS_VERSION[0]}.${MIN_NODEJS_VERSION[1]}.\n\n` +
27+
`The Angular CLI requires a minimum of v${supportedNodeVersions[0]}.\n\n` +
3228
'Please update your Node.js version or visit https://nodejs.org/ for additional instructions.\n',
3329
);
3430

packages/angular/cli/src/commands/version/version-info.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import { createRequire } from 'node:module';
1010
import { CommandContext } from '../../command-builder/definitions';
11-
import { PackageManager } from '../../package-managers';
11+
import { isNodeVersionSupported } from '../../utilities/node-version';
1212
import { VERSION } from '../../utilities/version';
1313

1414
/**
@@ -56,12 +56,6 @@ export interface VersionInfo {
5656
packages: Record<string, PackageVersionInfo>;
5757
}
5858

59-
/**
60-
* Major versions of Node.js that are officially supported by Angular.
61-
* @see https://angular.dev/reference/versions#supported-node-js-versions
62-
*/
63-
const SUPPORTED_NODE_MAJORS = [22, 24];
64-
6559
/**
6660
* A list of regular expression patterns that match package names that should be included in the
6761
* version output.
@@ -92,9 +86,6 @@ export async function gatherVersionInfo(context: CommandContext): Promise<Versio
9286
workspacePackage = workspaceRequire('./package.json');
9387
} catch {}
9488

95-
const [nodeMajor] = process.versions.node.split('.').map((part) => Number(part));
96-
const unsupportedNodeVersion = !SUPPORTED_NODE_MAJORS.includes(nodeMajor);
97-
9889
const allDependencies = {
9990
...workspacePackage?.dependencies,
10091
...workspacePackage?.devDependencies,
@@ -123,7 +114,7 @@ export async function gatherVersionInfo(context: CommandContext): Promise<Versio
123114
system: {
124115
node: {
125116
version: process.versions.node,
126-
unsupported: unsupportedNodeVersion,
117+
unsupported: !isNodeVersionSupported(),
127118
},
128119
os: {
129120
platform: process.platform,
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
/**
10+
* @fileoverview This file contains the supported Node.js version for the Angular CLI.
11+
* @important This file must not import any other modules.
12+
*/
13+
14+
/**
15+
* The supported Node.js version for the Angular CLI.
16+
* @type {[string, number]} The supported Node.js version.
17+
*/
18+
19+
const SUPPORTED_NODE_VERSIONS = '0.0.0-ENGINES-NODE';
20+
21+
/**
22+
* The supported Node.js versions.
23+
*/
24+
export const supportedNodeVersions = SUPPORTED_NODE_VERSIONS.replace(/[\^~<>=]/g, '')
25+
.split('||')
26+
.map((v) => v.trim());
27+
28+
/**
29+
* Checks if the current Node.js version is supported.
30+
* @returns `true` if the current Node.js version is supported, `false` otherwise.
31+
*/
32+
export function isNodeVersionSupported(): boolean {
33+
if (SUPPORTED_NODE_VERSIONS.charAt(0) === '0') {
34+
// Unlike `pkg_npm`, `ts_library` which is used to run unit tests does not support substitutions.
35+
return true;
36+
}
37+
38+
const [processMajor, processMinor, processPatch] = process.versions.node
39+
.split('.', 3)
40+
.map((part) => Number(part));
41+
42+
for (const version of supportedNodeVersions) {
43+
const [major, minor, patch] = version.split('.', 3).map((part) => Number(part));
44+
if (
45+
(major === processMajor && processMinor === minor && processPatch >= patch) ||
46+
(major === processMajor && processMinor > minor)
47+
) {
48+
return true;
49+
}
50+
}
51+
52+
return false;
53+
}
54+
55+
/**
56+
* Checks if the current Node.js version is the minimum supported version.
57+
* @returns `true` if the current Node.js version is the minimum supported version, `false` otherwise.
58+
*/
59+
export function isNodeVersionMinSupported(): boolean {
60+
if (SUPPORTED_NODE_VERSIONS.charAt(0) === '0') {
61+
// Unlike `pkg_npm`, `ts_library` which is used to run unit tests does not support substitutions.
62+
return true;
63+
}
64+
65+
const [processMajor, processMinor, processPatch] = process.versions.node
66+
.split('.', 3)
67+
.map((part) => Number(part));
68+
const [major, minor, patch] = supportedNodeVersions[0].split('.', 3).map((part) => Number(part));
69+
70+
return (
71+
processMajor > major ||
72+
(processMajor === major && processMinor > minor) ||
73+
(processMajor === major && processMinor === minor && processPatch >= patch)
74+
);
75+
}

0 commit comments

Comments
 (0)