nx 21.1.1 → 21.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <p style="text-align: center;">
2
2
  <picture>
3
3
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-dark.svg">
4
- <img alt="Nx - Smart Monorepos · Fast CI" src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-light.svg" width="100%">
4
+ <img alt="Nx - Smart Repos · Fast Builds" src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-light.svg" width="100%">
5
5
  </picture>
6
6
  </p>
7
7
 
@@ -20,9 +20,9 @@
20
20
 
21
21
  <hr>
22
22
 
23
- # Nx: Smart Monorepos · Fast CI
23
+ # Nx: Smart Repos · Fast Builds
24
24
 
25
- Nx is a build system, optimized for monorepos, with plugins for popular frameworks and tools and advanced CI capabilities including caching and distribution.
25
+ An AI-first build platform that connects everything from your editor to CI. Helping you deliver fast, without breaking things.
26
26
 
27
27
  ## Getting Started
28
28
 
@@ -62,5 +62,5 @@ npx nx@latest init
62
62
  - [Blog Posts About Nx](https://nx.dev/blog)
63
63
 
64
64
  <p style="text-align: center;"><a href="https://nx.dev/#learning-materials" target="_blank" rel="noreferrer"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-courses-and-videos.svg"
65
- width="100%" alt="Nx - Smart Monorepos · Fast CI"></a></p>
65
+ width="100%" alt="Nx - Smart Repos · Fast Builds"></a></p>
66
66
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nx",
3
- "version": "21.1.1",
3
+ "version": "21.1.3",
4
4
  "private": false,
5
5
  "description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.",
6
6
  "repository": {
@@ -83,16 +83,16 @@
83
83
  }
84
84
  },
85
85
  "optionalDependencies": {
86
- "@nx/nx-darwin-arm64": "21.1.1",
87
- "@nx/nx-darwin-x64": "21.1.1",
88
- "@nx/nx-freebsd-x64": "21.1.1",
89
- "@nx/nx-linux-arm-gnueabihf": "21.1.1",
90
- "@nx/nx-linux-arm64-gnu": "21.1.1",
91
- "@nx/nx-linux-arm64-musl": "21.1.1",
92
- "@nx/nx-linux-x64-gnu": "21.1.1",
93
- "@nx/nx-linux-x64-musl": "21.1.1",
94
- "@nx/nx-win32-arm64-msvc": "21.1.1",
95
- "@nx/nx-win32-x64-msvc": "21.1.1"
86
+ "@nx/nx-darwin-arm64": "21.1.3",
87
+ "@nx/nx-darwin-x64": "21.1.3",
88
+ "@nx/nx-freebsd-x64": "21.1.3",
89
+ "@nx/nx-linux-arm-gnueabihf": "21.1.3",
90
+ "@nx/nx-linux-arm64-gnu": "21.1.3",
91
+ "@nx/nx-linux-arm64-musl": "21.1.3",
92
+ "@nx/nx-linux-x64-gnu": "21.1.3",
93
+ "@nx/nx-linux-x64-musl": "21.1.3",
94
+ "@nx/nx-win32-arm64-msvc": "21.1.3",
95
+ "@nx/nx-win32-x64-msvc": "21.1.3"
96
96
  },
97
97
  "nx-migrations": {
98
98
  "migrations": "./migrations.json",
@@ -6,7 +6,7 @@ const documentation_1 = require("../yargs-utils/documentation");
6
6
  const shared_options_1 = require("../yargs-utils/shared-options");
7
7
  exports.yargsAffectedCommand = {
8
8
  command: 'affected',
9
- describe: 'Run target for affected projects. See https://nx.dev/ci/features/affected for more details.',
9
+ describe: 'Run target for affected projects. Affected projects are projects that have been changed and projects that depend on the changed projects. See https://nx.dev/ci/features/affected for more details.',
10
10
  builder: (yargs) => (0, documentation_1.linkToNxDevAndExamples)((0, shared_options_1.withAffectedOptions)((0, shared_options_1.withTuiOptions)((0, shared_options_1.withRunOptions)((0, shared_options_1.withOutputStyleOption)((0, shared_options_1.withTargetAndConfigurationOption)((0, shared_options_1.withBatch)(yargs))))))
11
11
  .option('all', {
12
12
  type: 'boolean',
@@ -36,6 +36,7 @@ export interface ExpandedTaskInputsReponse {
36
36
  }
37
37
  export declare function generateGraph(args: {
38
38
  file?: string;
39
+ print?: boolean;
39
40
  host?: string;
40
41
  port?: number;
41
42
  groupByFolder?: boolean;
@@ -9,6 +9,7 @@ const minimatch_1 = require("minimatch");
9
9
  const node_url_1 = require("node:url");
10
10
  const open = require("open");
11
11
  const path_1 = require("path");
12
+ const net = require("net");
12
13
  const perf_hooks_1 = require("perf_hooks");
13
14
  const configuration_1 = require("../../config/configuration");
14
15
  const fileutils_1 = require("../../utils/fileutils");
@@ -207,7 +208,7 @@ async function generateGraph(args, affectedProjects) {
207
208
  }
208
209
  }
209
210
  if (args.affected) {
210
- affectedProjects = (await (0, affected_1.getAffectedGraphNodes)((0, command_line_utils_1.splitArgsIntoNxArgsAndOverrides)(args, 'affected', { printWarnings: args.file !== 'stdout' }, (0, configuration_1.readNxJson)()).nxArgs, rawGraph)).map((n) => n.name);
211
+ affectedProjects = (await (0, affected_1.getAffectedGraphNodes)((0, command_line_utils_1.splitArgsIntoNxArgsAndOverrides)(args, 'affected', { printWarnings: !args.print && args.file !== 'stdout' }, (0, configuration_1.readNxJson)()).nxArgs, rawGraph)).map((n) => n.name);
211
212
  }
212
213
  if (args.exclude) {
213
214
  const invalidExcludes = [];
@@ -226,13 +227,12 @@ async function generateGraph(args, affectedProjects) {
226
227
  }
227
228
  let html = (0, node_fs_1.readFileSync)((0, path_1.join)(__dirname, '../../core/graph/index.html'), 'utf-8');
228
229
  prunedGraph = filterGraph(prunedGraph, args.focus || null, args.exclude || []);
230
+ if (args.print || args.file === 'stdout') {
231
+ console.log(JSON.stringify(await createJsonOutput(prunedGraph, rawGraph, args.projects, args.targets), null, 2));
232
+ await output_1.output.drain();
233
+ process.exit(0);
234
+ }
229
235
  if (args.file) {
230
- // stdout is a magical constant that doesn't actually write a file
231
- if (args.file === 'stdout') {
232
- console.log(JSON.stringify(await createJsonOutput(prunedGraph, rawGraph, args.projects, args.targets), null, 2));
233
- await output_1.output.drain();
234
- process.exit(0);
235
- }
236
236
  const workspaceFolder = workspace_root_1.workspaceRoot;
237
237
  const ext = (0, path_1.extname)(args.file);
238
238
  const fullFilePath = (0, path_1.isAbsolute)(args.file)
@@ -287,7 +287,20 @@ async function generateGraph(args, affectedProjects) {
287
287
  }
288
288
  else {
289
289
  const environmentJs = buildEnvironmentJs(args.exclude || [], args.watch, !!args.file && args.file.endsWith('html') ? 'build' : 'serve');
290
- const { app, url } = await startServer(html, environmentJs, args.host || '127.0.0.1', args.port || 4211, args.watch, affectedProjects, args.focus, args.groupByFolder, args.exclude);
290
+ let app;
291
+ let url;
292
+ try {
293
+ const result = await startServer(html, environmentJs, args.host || '127.0.0.1', args.port || 4211, args.watch, affectedProjects, args.focus, args.groupByFolder, args.exclude);
294
+ app = result.app;
295
+ url = result.url;
296
+ }
297
+ catch (err) {
298
+ output_1.output.error({
299
+ title: 'Failed to start graph server',
300
+ bodyLines: [err.message],
301
+ });
302
+ process.exit(1);
303
+ }
291
304
  url.pathname = args.view;
292
305
  if (args.focus) {
293
306
  url.pathname += '/' + encodeURIComponent(args.focus);
@@ -318,6 +331,28 @@ async function generateGraph(args, affectedProjects) {
318
331
  });
319
332
  }
320
333
  }
334
+ function findAvailablePort(startPort, host = '127.0.0.1') {
335
+ return new Promise((resolve, reject) => {
336
+ const server = net.createServer();
337
+ server.listen(startPort, host, () => {
338
+ const port = server.address().port;
339
+ server.close(() => {
340
+ resolve(port);
341
+ });
342
+ });
343
+ server.on('error', (err) => {
344
+ if (err.code === 'EADDRINUSE') {
345
+ // Port is in use, try the next one
346
+ findAvailablePort(startPort + 1, host)
347
+ .then(resolve)
348
+ .catch(reject);
349
+ }
350
+ else {
351
+ reject(err);
352
+ }
353
+ });
354
+ });
355
+ }
321
356
  async function startServer(html, environmentJs, host, port = 4211, watchForChanges = true, affected = [], focus = null, groupByFolder = false, exclude = []) {
322
357
  let unregisterFileWatcher;
323
358
  if (watchForChanges && !client_1.daemonClient.enabled()) {
@@ -418,9 +453,19 @@ async function startServer(html, environmentJs, host, port = 4211, watchForChang
418
453
  };
419
454
  process.on('SIGINT', () => handleTermination(128 + 2));
420
455
  process.on('SIGTERM', () => handleTermination(128 + 15));
421
- return new Promise((res) => {
422
- app.listen(port, host, () => {
423
- res({ app, url: new node_url_1.URL(`http://${host}:${port}`) });
456
+ // Find an available port starting from the requested port
457
+ const availablePort = await findAvailablePort(port, host);
458
+ return new Promise((res, rej) => {
459
+ app.on('error', (err) => {
460
+ rej(err);
461
+ });
462
+ app.listen(availablePort, host, () => {
463
+ if (availablePort !== port) {
464
+ output_1.output.note({
465
+ title: `Port ${port} was already in use, using port ${availablePort} instead`,
466
+ });
467
+ }
468
+ res({ app, url: new node_url_1.URL(`http://${host}:${availablePort}`) });
424
469
  });
425
470
  });
426
471
  }
@@ -5,12 +5,13 @@ const child_process_1 = require("child_process");
5
5
  const path_1 = require("path");
6
6
  const semver_1 = require("semver");
7
7
  const fileutils_1 = require("../../../../utils/fileutils");
8
+ const installation_directory_1 = require("../../../../utils/installation-directory");
8
9
  const object_sort_1 = require("../../../../utils/object-sort");
9
10
  const output_1 = require("../../../../utils/output");
10
11
  const package_json_1 = require("../../../../utils/package-json");
11
12
  const package_manager_1 = require("../../../../utils/package-manager");
12
- const utils_1 = require("../utils");
13
13
  const connect_to_nx_cloud_1 = require("../../../connect/connect-to-nx-cloud");
14
+ const utils_1 = require("../utils");
14
15
  // map of Angular major versions to Nx versions to use for legacy `nx init` migrations,
15
16
  // key is major Angular version and value is Nx version to use
16
17
  const nxAngularLegacyVersionMap = {
@@ -25,8 +26,25 @@ const versionWithConsolidatedPackages = '13.9.0';
25
26
  // version when packages were rescoped from @nrwl/* to @nx/*
26
27
  const versionWithRescopeToNx = '16.0.0-beta.2';
27
28
  async function getLegacyMigrationFunctionIfApplicable(repoRoot, options) {
28
- const angularVersion = (0, package_json_1.readModulePackageJson)('@angular/core').packageJson.version;
29
- const majorAngularVersion = (0, semver_1.major)(angularVersion);
29
+ let majorAngularVersion;
30
+ try {
31
+ const angularVersion = (0, package_json_1.readModulePackageJson)('@angular/core', [
32
+ repoRoot,
33
+ ...(0, installation_directory_1.getNxRequirePaths)(),
34
+ ]).packageJson.version;
35
+ majorAngularVersion = (0, semver_1.major)(angularVersion);
36
+ }
37
+ catch {
38
+ output_1.output.error({
39
+ title: 'Could not determine the existing Angular version',
40
+ bodyLines: [
41
+ 'Please ensure "@angular/core" is installed in the workspace and you are running this command from the root of the workspace.',
42
+ ],
43
+ });
44
+ // errors are caught in the initHandler and not logged to the user, so we
45
+ // log it first and then throw to ensure it is logged to the user
46
+ throw new Error('Could not determine the existing Angular version');
47
+ }
30
48
  if (majorAngularVersion >= minMajorAngularVersionSupported) {
31
49
  // non-legacy
32
50
  return null;
@@ -1175,6 +1175,7 @@ function getImplementationPath(collection, collectionPath, name) {
1175
1175
  }
1176
1176
  function nxCliPath(nxWorkspaceRoot) {
1177
1177
  const version = process.env.NX_MIGRATE_CLI_VERSION || 'latest';
1178
+ const isVerbose = process.env.NX_VERBOSE_LOGGING === 'true';
1178
1179
  try {
1179
1180
  const packageManager = (0, package_manager_1.detectPackageManager)();
1180
1181
  const pmc = (0, package_manager_1.getPackageManagerCommand)(packageManager);
@@ -1187,25 +1188,30 @@ function nxCliPath(nxWorkspaceRoot) {
1187
1188
  license: 'MIT',
1188
1189
  });
1189
1190
  (0, package_manager_1.copyPackageManagerConfigurationFiles)(nxWorkspaceRoot ?? workspace_root_1.workspaceRoot, tmpDir);
1191
+ // Let's print the output of the install process to the console when verbose
1192
+ // is enabled, so it's easier to debug issues with the installation process
1193
+ const stdio = isVerbose
1194
+ ? ['ignore', 'inherit', 'inherit']
1195
+ : 'ignore';
1190
1196
  if (pmc.preInstall) {
1191
1197
  // ensure package.json and repo in tmp folder is set to a proper package manager state
1192
1198
  (0, child_process_1.execSync)(pmc.preInstall, {
1193
1199
  cwd: tmpDir,
1194
- stdio: ['ignore', 'ignore', 'ignore'],
1200
+ stdio,
1195
1201
  windowsHide: false,
1196
1202
  });
1197
1203
  // if it's berry ensure we set the node_linker to node-modules
1198
1204
  if (packageManager === 'yarn' && pmc.ciInstall.includes('immutable')) {
1199
1205
  (0, child_process_1.execSync)('yarn config set nodeLinker node-modules', {
1200
1206
  cwd: tmpDir,
1201
- stdio: ['ignore', 'ignore', 'ignore'],
1207
+ stdio,
1202
1208
  windowsHide: false,
1203
1209
  });
1204
1210
  }
1205
1211
  }
1206
1212
  (0, child_process_1.execSync)(pmc.install, {
1207
1213
  cwd: tmpDir,
1208
- stdio: ['ignore', 'ignore', 'ignore'],
1214
+ stdio,
1209
1215
  windowsHide: false,
1210
1216
  });
1211
1217
  // Set NODE_PATH so that these modules can be used for module resolution
@@ -1215,7 +1221,7 @@ function nxCliPath(nxWorkspaceRoot) {
1215
1221
  }
1216
1222
  catch (e) {
1217
1223
  console.error(`Failed to install the ${version} version of the migration script. Using the current version.`);
1218
- if (process.env.NX_VERBOSE_LOGGING === 'true') {
1224
+ if (isVerbose) {
1219
1225
  console.error(e);
1220
1226
  }
1221
1227
  return null;
@@ -44,7 +44,7 @@ exports.parserConfiguration = {
44
44
  */
45
45
  exports.commandsObject = yargs
46
46
  .parserConfiguration(exports.parserConfiguration)
47
- .usage(chalk.bold('Smart Monorepos · Fast CI'))
47
+ .usage(chalk.bold('Smart Repos · Fast Builds'))
48
48
  .demandCommand(1, '')
49
49
  .command(command_object_1.yargsRegisterCommand)
50
50
  .command(command_object_22.yargsAddCommand)
@@ -956,7 +956,7 @@ Valid values are: ${version_1.validReleaseVersionPrefixes
956
956
  let bumpType = 'none';
957
957
  if (releaseGroup.projectsRelationship === 'fixed') {
958
958
  // For fixed groups, we only need to check one project
959
- const project = releaseGroupFilteredProjects[0];
959
+ const project = releaseGroupFilteredProjects.values().next().value;
960
960
  const dependencies = this.projectGraph.dependencies[project] || [];
961
961
  const hasDependencyInChangedGroup = dependencies.some((dep) => this.getReleaseGroupNameForProject(dep.target) ===
962
962
  changedDependencyGroup);
@@ -37,5 +37,5 @@ function topologicalSort(nodes, getEdges) {
37
37
  visit(node);
38
38
  }
39
39
  }
40
- return result.reverse();
40
+ return result;
41
41
  }
@@ -1,4 +1,5 @@
1
1
  import { ExecutorContext } from '../../config/misc-interfaces';
2
+ import { NoopChildProcess } from '../../tasks-runner/running-tasks/noop-child-process';
2
3
  import { ParallelRunningTasks, SeriallyRunningTasks } from './running-tasks';
3
4
  export declare const LARGE_BUFFER: number;
4
5
  export type Json = {
@@ -54,5 +55,5 @@ export default function (options: RunCommandsOptions, context: ExecutorContext):
54
55
  success: boolean;
55
56
  terminalOutput: string;
56
57
  }>;
57
- export declare function runCommands(options: RunCommandsOptions, context: ExecutorContext): Promise<import("../../tasks-runner/pseudo-terminal").PseudoTtyProcess | ParallelRunningTasks | SeriallyRunningTasks>;
58
+ export declare function runCommands(options: RunCommandsOptions, context: ExecutorContext): Promise<import("../../tasks-runner/pseudo-terminal").PseudoTtyProcess | NoopChildProcess | ParallelRunningTasks | SeriallyRunningTasks>;
58
59
  export declare function interpolateArgsIntoCommand(command: string, opts: Pick<NormalizedRunCommandsOptions, 'args' | 'parsedArgs' | '__unparsed__' | 'unknownOptions' | 'unparsedCommandArgs'>, forwardAllArgs: boolean): string;
@@ -7,6 +7,7 @@ exports.interpolateArgsIntoCommand = interpolateArgsIntoCommand;
7
7
  const yargsParser = require("yargs-parser");
8
8
  const is_tui_enabled_1 = require("../../tasks-runner/is-tui-enabled");
9
9
  const pseudo_terminal_1 = require("../../tasks-runner/pseudo-terminal");
10
+ const noop_child_process_1 = require("../../tasks-runner/running-tasks/noop-child-process");
10
11
  const running_tasks_1 = require("./running-tasks");
11
12
  exports.LARGE_BUFFER = 1024 * 1000000;
12
13
  const propKeys = [
@@ -45,6 +46,10 @@ async function runCommands(options, context) {
45
46
  !options.parallel) {
46
47
  throw new Error('ERROR: Bad executor config for run-commands - "prefix", "prefixColor", "color" and "bgColor" can only be set when "parallel=true".');
47
48
  }
49
+ // Handle empty commands array - return immediately with success
50
+ if (normalized.commands.length === 0) {
51
+ return new noop_child_process_1.NoopChildProcess({ code: 0, terminalOutput: '' });
52
+ }
48
53
  const isSingleCommand = normalized.commands.length === 1;
49
54
  const usePseudoTerminal = (isSingleCommand || !options.parallel) && pseudo_terminal_1.PseudoTerminal.isSupported();
50
55
  const isSingleCommandAndCanUsePseudoTerminal = isSingleCommand &&
@@ -231,24 +231,16 @@ class RunningNodeProcess {
231
231
  }
232
232
  kill(signal) {
233
233
  return new Promise((res, rej) => {
234
- if (process.platform === 'win32') {
235
- if (this.childProcess.kill(signal)) {
236
- res();
234
+ treeKill(this.childProcess.pid, signal, (err) => {
235
+ // On Windows, tree-kill (which uses taskkill) may fail when the process or its child process is already terminated.
236
+ // Ignore the errors, otherwise we will log them unnecessarily.
237
+ if (err && process.platform !== 'win32') {
238
+ rej(err);
237
239
  }
238
240
  else {
239
- rej('Unable to kill process');
241
+ res();
240
242
  }
241
- }
242
- else {
243
- treeKill(this.childProcess.pid, signal, (err) => {
244
- if (err) {
245
- rej(err);
246
- }
247
- else {
248
- res();
249
- }
250
- });
251
- }
243
+ });
252
244
  });
253
245
  }
254
246
  triggerOutputListeners(output) {
Binary file
@@ -7,4 +7,4 @@ export declare function getURLifShortenFailed(usesGithub: boolean, githubSlug: s
7
7
  export declare function getNxCloudVersion(apiUrl: string): Promise<string | null>;
8
8
  export declare function removeVersionModifier(versionString: string): string;
9
9
  export declare function versionIsValid(version: string): boolean;
10
- export declare function compareCleanCloudVersions(version1: string, version2: string): number;
10
+ export declare function isOldNxCloudVersion(version: string): boolean;
@@ -6,7 +6,7 @@ exports.getURLifShortenFailed = getURLifShortenFailed;
6
6
  exports.getNxCloudVersion = getNxCloudVersion;
7
7
  exports.removeVersionModifier = removeVersionModifier;
8
8
  exports.versionIsValid = versionIsValid;
9
- exports.compareCleanCloudVersions = compareCleanCloudVersions;
9
+ exports.isOldNxCloudVersion = isOldNxCloudVersion;
10
10
  const logger_1 = require("../../utils/logger");
11
11
  const git_utils_1 = require("../../utils/git-utils");
12
12
  const get_cloud_options_1 = require("./get-cloud-options");
@@ -21,8 +21,7 @@ async function createNxCloudOnboardingURL(onboardingSource, accessToken, usesGit
21
21
  }
22
22
  try {
23
23
  const version = await getNxCloudVersion(apiUrl);
24
- if ((version && compareCleanCloudVersions(version, '2406.11.5') < 0) ||
25
- !version) {
24
+ if (!version || isOldNxCloudVersion(version)) {
26
25
  return apiUrl;
27
26
  }
28
27
  }
@@ -96,7 +95,7 @@ async function getInstallationSupportsGitHub(apiUrl) {
96
95
  }
97
96
  catch (e) {
98
97
  if (process.env.NX_VERBOSE_LOGGING === 'true') {
99
- logger_1.logger.warn(`Failed to access system features. GitHub integration assumed to be disabled.
98
+ logger_1.logger.warn(`Failed to access system features. GitHub integration assumed to be disabled.
100
99
  ${e}`);
101
100
  }
102
101
  return false;
@@ -131,26 +130,28 @@ function versionIsValid(version) {
131
130
  const pattern = /^\d{4}\.\d{2}\.\d+$/;
132
131
  return pattern.test(version);
133
132
  }
134
- function compareCleanCloudVersions(version1, version2) {
135
- const parseVersion = (version) => {
136
- // The format we're using is YYMM.DD.BuildNumber
137
- const parts = version.split('.').map((part) => parseInt(part, 10));
138
- return {
139
- yearMonth: parts[0],
140
- day: parts[1],
141
- buildNumber: parts[2],
142
- };
143
- };
144
- const v1 = parseVersion(version1);
145
- const v2 = parseVersion(version2);
146
- if (v1.yearMonth !== v2.yearMonth) {
147
- return v1.yearMonth > v2.yearMonth ? 1 : -1;
148
- }
149
- if (v1.day !== v2.day) {
150
- return v1.day > v2.day ? 1 : -1;
151
- }
152
- if (v1.buildNumber !== v2.buildNumber) {
153
- return v1.buildNumber > v2.buildNumber ? 1 : -1;
154
- }
155
- return 0;
133
+ function isOldNxCloudVersion(version) {
134
+ const [major, minor, buildNumber] = version
135
+ .split('.')
136
+ .map((part) => parseInt(part, 10));
137
+ // for on-prem images we are using YYYY.MM.BuildNumber format
138
+ // the first year is 2025
139
+ if (major >= 2025 && major < 2300) {
140
+ return false;
141
+ }
142
+ // Previously we used YYMM.DD.BuildNumber
143
+ // All versions before '2406.11.5' had different URL shortening logic
144
+ const newVersionMajor = 2406;
145
+ const newVersionMinor = 11;
146
+ const newVersionBuildNumber = 5;
147
+ if (major !== newVersionMajor) {
148
+ return major < newVersionMajor;
149
+ }
150
+ if (minor !== newVersionMinor) {
151
+ return minor < newVersionMinor;
152
+ }
153
+ if (buildNumber !== newVersionBuildNumber) {
154
+ return buildNumber < newVersionBuildNumber;
155
+ }
156
+ return false;
156
157
  }
@@ -51,10 +51,13 @@ const getProjectPathsAffectedByDependencyUpdates = (changedLockFile) => {
51
51
  return Array.from(changedProjectPaths);
52
52
  };
53
53
  const getProjectsNamesFromPaths = (projectGraphNodes, projectPaths) => {
54
+ if (!projectPaths.length) {
55
+ return [];
56
+ }
54
57
  const lookup = new RootPathLookup(projectGraphNodes);
55
- return projectPaths.map((path) => {
56
- return lookup.findNodeNameByRoot(path);
57
- });
58
+ return projectPaths
59
+ .map((path) => lookup.findNodeNameByRoot(path))
60
+ .filter(Boolean);
58
61
  };
59
62
  class RootPathLookup {
60
63
  constructor(nodes) {
@@ -1,3 +1,4 @@
1
+ import type { TsConfigOptions } from 'ts-node';
1
2
  import type { CompilerOptions } from 'typescript';
2
3
  /**
3
4
  * Optionally, if swc-node and tsconfig-paths are available in the current workspace, apply the require
@@ -23,7 +24,7 @@ export declare function registerTsProject(tsConfigPath: string): () => void;
23
24
  */
24
25
  export declare function registerTsProject(path: string, configFilename: string): any;
25
26
  export declare function getSwcTranspiler(compilerOptions: CompilerOptions): (...args: unknown[]) => unknown;
26
- export declare function getTsNodeTranspiler(compilerOptions: CompilerOptions): (...args: unknown[]) => unknown;
27
+ export declare function getTsNodeTranspiler(compilerOptions: CompilerOptions, tsNodeOptions?: TsConfigOptions): (...args: unknown[]) => unknown;
27
28
  export declare function getTranspiler(compilerOptions: CompilerOptions, tsConfigRaw?: unknown): () => (...args: unknown[]) => unknown;
28
29
  /**
29
30
  * Register ts-node or swc-node given a set of compiler options.
@@ -33,7 +34,7 @@ export declare function getTranspiler(compilerOptions: CompilerOptions, tsConfig
33
34
  *
34
35
  * @returns cleanup method
35
36
  */
36
- export declare function registerTranspiler(compilerOptions: CompilerOptions): () => void;
37
+ export declare function registerTranspiler(compilerOptions: CompilerOptions, tsConfigRaw?: unknown): () => void;
37
38
  /**
38
39
  * @param tsConfigPath Adds the paths from a tsconfig file into node resolutions
39
40
  * @returns cleanup function
@@ -9,6 +9,7 @@ exports.registerTsConfigPaths = registerTsConfigPaths;
9
9
  exports.getTsNodeCompilerOptions = getTsNodeCompilerOptions;
10
10
  const path_1 = require("path");
11
11
  const logger_1 = require("../../../utils/logger");
12
+ const typescript_1 = require("./typescript");
12
13
  const swcNodeInstalled = packageIsInstalled('@swc-node/register');
13
14
  const tsNodeInstalled = packageIsInstalled('ts-node/register');
14
15
  let ts;
@@ -53,10 +54,10 @@ function registerTsProject(path, configFilename) {
53
54
  return () => { };
54
55
  }
55
56
  const tsConfigPath = configFilename ? (0, path_1.join)(path, configFilename) : path;
56
- const compilerOptions = readCompilerOptions(tsConfigPath);
57
+ const { compilerOptions, tsConfigRaw } = readCompilerOptions(tsConfigPath);
57
58
  const cleanupFunctions = [
58
59
  registerTsConfigPaths(tsConfigPath),
59
- registerTranspiler(compilerOptions),
60
+ registerTranspiler(compilerOptions, tsConfigRaw),
60
61
  ];
61
62
  // Add ESM support for `.ts` files.
62
63
  // NOTE: There is no cleanup function for this, as it's not possible to unregister the loader.
@@ -90,12 +91,16 @@ function getSwcTranspiler(compilerOptions) {
90
91
  const cleanupFn = register(compilerOptions);
91
92
  return typeof cleanupFn === 'function' ? cleanupFn : () => { };
92
93
  }
93
- function getTsNodeTranspiler(compilerOptions) {
94
+ function getTsNodeTranspiler(compilerOptions, tsNodeOptions) {
94
95
  const { register } = require('ts-node');
95
96
  // ts-node doesn't provide a cleanup method
96
97
  const service = register({
98
+ ...tsNodeOptions,
97
99
  transpileOnly: true,
98
- compilerOptions: getTsNodeCompilerOptions(compilerOptions),
100
+ compilerOptions: getTsNodeCompilerOptions({
101
+ ...tsNodeOptions?.compilerOptions,
102
+ ...compilerOptions,
103
+ }),
99
104
  // we already read and provide the compiler options, so prevent ts-node from reading them again
100
105
  skipProject: true,
101
106
  });
@@ -165,21 +170,30 @@ function getTranspiler(compilerOptions, tsConfigRaw) {
165
170
  compilerOptions.target = ts.ScriptTarget.ES2021;
166
171
  compilerOptions.inlineSourceMap = true;
167
172
  compilerOptions.skipLibCheck = true;
173
+ let _getTranspiler;
174
+ let registrationKey = JSON.stringify(compilerOptions);
175
+ let tsNodeOptions;
176
+ if (swcNodeInstalled && !preferTsNode) {
177
+ _getTranspiler = getSwcTranspiler;
178
+ }
179
+ else if (tsNodeInstalled) {
180
+ // We can fall back on ts-node if it's available
181
+ _getTranspiler = getTsNodeTranspiler;
182
+ tsNodeOptions = filterRecognizedTsConfigTsNodeOptions(tsConfigRaw?.['ts-node']).recognized;
183
+ // include ts-node options in the registration key
184
+ registrationKey += JSON.stringify(tsNodeOptions);
185
+ }
186
+ else {
187
+ _getTranspiler = undefined;
188
+ }
168
189
  // Just return if transpiler was already registered before.
169
- const registrationKey = JSON.stringify(compilerOptions);
170
190
  const registrationEntry = registered.get(registrationKey);
171
191
  if (registered.has(registrationKey)) {
172
192
  registrationEntry.refCount++;
173
193
  return registrationEntry.cleanup;
174
194
  }
175
- const _getTranspiler = swcNodeInstalled && !preferTsNode
176
- ? getSwcTranspiler
177
- : tsNodeInstalled
178
- ? // We can fall back on ts-node if it's available
179
- getTsNodeTranspiler
180
- : undefined;
181
195
  if (_getTranspiler) {
182
- const transpilerCleanup = _getTranspiler(compilerOptions);
196
+ const transpilerCleanup = _getTranspiler(compilerOptions, tsNodeOptions);
183
197
  const currRegistrationEntry = {
184
198
  refCount: 1,
185
199
  cleanup: () => {
@@ -204,9 +218,9 @@ function getTranspiler(compilerOptions, tsConfigRaw) {
204
218
  *
205
219
  * @returns cleanup method
206
220
  */
207
- function registerTranspiler(compilerOptions) {
221
+ function registerTranspiler(compilerOptions, tsConfigRaw) {
208
222
  // Function to register transpiler that returns cleanup function
209
- const transpiler = getTranspiler(compilerOptions);
223
+ const transpiler = getTranspiler(compilerOptions, tsConfigRaw);
210
224
  if (!transpiler) {
211
225
  warnNoTranspiler();
212
226
  return () => { };
@@ -245,7 +259,9 @@ function registerTsConfigPaths(tsConfigPath) {
245
259
  function readCompilerOptions(tsConfigPath) {
246
260
  const preferTsNode = process.env.NX_PREFER_TS_NODE === 'true';
247
261
  if (swcNodeInstalled && !preferTsNode) {
248
- return readCompilerOptionsWithSwc(tsConfigPath);
262
+ return {
263
+ compilerOptions: readCompilerOptionsWithSwc(tsConfigPath),
264
+ };
249
265
  }
250
266
  else {
251
267
  return readCompilerOptionsWithTypescript(tsConfigPath);
@@ -261,16 +277,14 @@ function readCompilerOptionsWithSwc(tsConfigPath) {
261
277
  return compilerOptions;
262
278
  }
263
279
  function readCompilerOptionsWithTypescript(tsConfigPath) {
264
- if (!ts) {
265
- ts = require('typescript');
266
- }
267
- const { readConfigFile, parseJsonConfigFileContent, sys } = ts;
268
- const jsonContent = readConfigFile(tsConfigPath, sys.readFile);
269
- const { options } = parseJsonConfigFileContent(jsonContent.config, sys, (0, path_1.dirname)(tsConfigPath));
280
+ const { options, raw } = (0, typescript_1.readTsConfigWithoutFiles)(tsConfigPath);
270
281
  // This property is returned in compiler options for some reason, but not part of the typings.
271
282
  // ts-node fails on unknown props, so we have to remove it.
272
283
  delete options.configFilePath;
273
- return options;
284
+ return {
285
+ compilerOptions: options,
286
+ tsConfigRaw: raw,
287
+ };
274
288
  }
275
289
  function loadTsConfigPaths() {
276
290
  try {
@@ -1,6 +1,7 @@
1
1
  import type * as ts from 'typescript';
2
2
  import type { Node, SyntaxKind } from 'typescript';
3
- export declare function readTsConfig(tsConfigPath: string): ts.ParsedCommandLine;
3
+ export declare function readTsConfig(tsConfigPath: string, sys?: ts.System): ts.ParsedCommandLine;
4
+ export declare function readTsConfigWithoutFiles(tsConfigPath: string): ts.ParsedCommandLine;
4
5
  export declare function readTsConfigOptions(tsConfigPath: string): ts.CompilerOptions;
5
6
  /**
6
7
  * Find a module based on its import
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.readTsConfig = readTsConfig;
4
+ exports.readTsConfigWithoutFiles = readTsConfigWithoutFiles;
4
5
  exports.readTsConfigOptions = readTsConfigOptions;
5
6
  exports.resolveModuleByImport = resolveModuleByImport;
6
7
  exports.getRootTsConfigFileName = getRootTsConfigFileName;
@@ -11,25 +12,29 @@ const fs_1 = require("fs");
11
12
  const path_1 = require("path");
12
13
  const normalizedAppRoot = workspace_root_1.workspaceRoot.replace(/\\/g, '/');
13
14
  let tsModule;
14
- function readTsConfig(tsConfigPath) {
15
+ function readTsConfig(tsConfigPath, sys) {
15
16
  if (!tsModule) {
16
17
  tsModule = require('typescript');
17
18
  }
18
- const readResult = tsModule.readConfigFile(tsConfigPath, tsModule.sys.readFile);
19
- return tsModule.parseJsonConfigFileContent(readResult.config, tsModule.sys, (0, path_1.dirname)(tsConfigPath));
19
+ sys ??= tsModule.sys;
20
+ const readResult = tsModule.readConfigFile(tsConfigPath, sys.readFile);
21
+ return tsModule.parseJsonConfigFileContent(readResult.config, sys, (0, path_1.dirname)(tsConfigPath));
20
22
  }
21
- function readTsConfigOptions(tsConfigPath) {
23
+ function readTsConfigWithoutFiles(tsConfigPath) {
22
24
  if (!tsModule) {
23
25
  tsModule = require('typescript');
24
26
  }
25
- const readResult = tsModule.readConfigFile(tsConfigPath, tsModule.sys.readFile);
26
27
  // We only care about options, so we don't need to scan source files, and thus
27
28
  // `readDirectory` is stubbed for performance.
28
- const host = {
29
+ const sys = {
29
30
  ...tsModule.sys,
30
31
  readDirectory: () => [],
31
32
  };
32
- return tsModule.parseJsonConfigFileContent(readResult.config, host, (0, path_1.dirname)(tsConfigPath)).options;
33
+ return readTsConfig(tsConfigPath, sys);
34
+ }
35
+ function readTsConfigOptions(tsConfigPath) {
36
+ const { options } = readTsConfigWithoutFiles(tsConfigPath);
37
+ return options;
33
38
  }
34
39
  let compilerHost;
35
40
  /**
@@ -6,9 +6,9 @@ exports.pluginTranspilerIsRegistered = pluginTranspilerIsRegistered;
6
6
  exports.cleanupPluginTSTranspiler = cleanupPluginTSTranspiler;
7
7
  const node_fs_1 = require("node:fs");
8
8
  const posix_1 = require("node:path/posix");
9
- const workspace_root_1 = require("../../utils/workspace-root");
10
9
  const register_1 = require("../../plugins/js/utils/register");
11
10
  const typescript_1 = require("../../plugins/js/utils/typescript");
11
+ const workspace_root_1 = require("../../utils/workspace-root");
12
12
  exports.unregisterPluginTSTranspiler = null;
13
13
  /**
14
14
  * Register swc-node or ts-node if they are not currently registered
@@ -23,16 +23,16 @@ function registerPluginTSTranspiler() {
23
23
  if (!tsConfigName) {
24
24
  return;
25
25
  }
26
- const tsConfigOptions = tsConfigName
27
- ? (0, typescript_1.readTsConfigOptions)(tsConfigName)
26
+ const tsConfig = tsConfigName
27
+ ? (0, typescript_1.readTsConfigWithoutFiles)(tsConfigName)
28
28
  : {};
29
29
  const cleanupFns = [
30
30
  (0, register_1.registerTsConfigPaths)(tsConfigName),
31
31
  (0, register_1.registerTranspiler)({
32
32
  experimentalDecorators: true,
33
33
  emitDecoratorMetadata: true,
34
- ...tsConfigOptions,
35
- }),
34
+ ...tsConfig.options,
35
+ }, tsConfig.raw),
36
36
  ];
37
37
  exports.unregisterPluginTSTranspiler = () => {
38
38
  cleanupFns.forEach((fn) => fn?.());
@@ -38,7 +38,7 @@ function readCachedProjectGraph(minimumComputedAt) {
38
38
  ? (0, strip_indents_1.stripIndents) `
39
39
  Make sure invoke 'node ./decorate-angular-cli.js' in your postinstall script.
40
40
  The decorated CLI will compute the project graph.
41
- 'ng --help' should say 'Smart Monorepos · Fast CI'.
41
+ 'ng --help' should say 'Smart Repos · Fast Builds'.
42
42
  `
43
43
  : '';
44
44
  throw new Error((0, strip_indents_1.stripIndents) `
@@ -772,6 +772,17 @@ function getRunner(nxArgs, nxJson) {
772
772
  }
773
773
  const defaultTasksRunnerPath = require.resolve('./default-tasks-runner');
774
774
  function getTasksRunnerPath(runner, nxJson) {
775
+ // If running inside of Codex, there will be no internet access, so we cannot use the cloud runner, regardless of other config.
776
+ // We can infer this scenario by checking for certain environment variables defined in their base image: https://github.com/openai/codex-universal
777
+ if (process.env.CODEX_ENV_NODE_VERSION) {
778
+ output_1.output.warn({
779
+ title: 'Codex environment detected, using default tasks runner',
780
+ bodyLines: [
781
+ 'Codex does not have internet access when it runs tasks, so Nx will use the default tasks runner and only leverage local caching.',
782
+ ],
783
+ });
784
+ return defaultTasksRunnerPath;
785
+ }
775
786
  const isCloudRunner =
776
787
  // No tasksRunnerOptions for given --runner
777
788
  nxJson.nxCloudAccessToken ||
@@ -11,5 +11,6 @@ export declare class NoopChildProcess implements RunningTask {
11
11
  terminalOutput: string;
12
12
  }>;
13
13
  kill(): void;
14
- onExit(cb: (code: number) => void): void;
14
+ onExit(cb: (code: number, terminalOutput: string) => void): void;
15
+ onOutput(cb: (terminalOutput: string) => void): void;
15
16
  }
@@ -13,7 +13,10 @@ class NoopChildProcess {
13
13
  return;
14
14
  }
15
15
  onExit(cb) {
16
- cb(this.results.code);
16
+ cb(this.results.code, this.results.terminalOutput);
17
+ }
18
+ onOutput(cb) {
19
+ cb(this.results.terminalOutput);
17
20
  }
18
21
  }
19
22
  exports.NoopChildProcess = NoopChildProcess;