nx 23.0.0-beta.5 → 23.0.0-beta.7

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.
@@ -8,6 +8,7 @@ const cache_directory_1 = require("../src/utils/cache-directory");
8
8
  const path_1 = require("path");
9
9
  const fileutils_1 = require("../src/utils/fileutils");
10
10
  const plugin_cache_utils_1 = require("../src/utils/plugin-cache-utils");
11
+ const package_manager_1 = require("../src/utils/package-manager");
11
12
  const cachePath = (0, path_1.join)(cache_directory_1.workspaceDataDirectory, 'package-json.hash');
12
13
  let packageJsonPluginCache = null;
13
14
  function readPackageJsonConfigurationCache() {
@@ -16,7 +17,7 @@ function readPackageJsonConfigurationCache() {
16
17
  }
17
18
  function writeCache() {
18
19
  if (packageJsonPluginCache) {
19
- packageJsonPluginCache.writeToDisk(cachePath);
20
+ packageJsonPluginCache.writeToDisk();
20
21
  }
21
22
  }
22
23
  const plugin = {
@@ -27,7 +28,8 @@ const plugin = {
27
28
  const cache = readPackageJsonConfigurationCache();
28
29
  const patterns = (0, package_json_1.buildPackageJsonPatterns)(context.workspaceRoot, (f) => (0, fileutils_1.readJsonFile)((0, path_1.join)(context.workspaceRoot, f)));
29
30
  const isInPackageJsonWorkspaces = (0, package_json_1.buildPackageJsonWorkspacesMatcher)(patterns);
30
- const result = (0, plugins_1.createNodesFromFiles)((packageJsonPath) => (0, package_json_1.createNodeFromPackageJson)(packageJsonPath, workspace_root_1.workspaceRoot, cache, isInPackageJsonWorkspaces(packageJsonPath)), configFiles, options, context);
31
+ const packageManagerCommand = (0, package_manager_1.getPackageManagerCommand)((0, package_manager_1.detectPackageManager)(context.workspaceRoot), context.workspaceRoot);
32
+ const result = (0, plugins_1.createNodesFromFiles)((packageJsonPath) => (0, package_json_1.createNodeFromPackageJson)(packageJsonPath, workspace_root_1.workspaceRoot, cache, isInPackageJsonWorkspaces(packageJsonPath), packageManagerCommand), configFiles, options, context);
31
33
  writeCache();
32
34
  return result;
33
35
  },
@@ -16,6 +16,7 @@ const native_1 = require("../native");
16
16
  const package_manager_1 = require("../utils/package-manager");
17
17
  const semver_1 = require("semver");
18
18
  const os = tslib_1.__importStar(require("os"));
19
+ const crypto_1 = require("crypto");
19
20
  const machine_id_cache_1 = require("../utils/machine-id-cache");
20
21
  const is_ci_1 = require("../utils/is-ci");
21
22
  const analytics_prompt_1 = require("../utils/analytics-prompt");
@@ -56,7 +57,7 @@ async function startAnalytics() {
56
57
  return;
57
58
  }
58
59
  const isNxCloud = !!(nxJson?.nxCloudId ?? nxJson?.nxCloudAccessToken);
59
- const userId = await (0, machine_id_cache_1.getCurrentMachineId)();
60
+ const userId = await getTelemetryUserId(workspaceId);
60
61
  const packageManagerInfo = getPackageManagerInfo();
61
62
  const nodeVersion = (0, semver_1.parse)(process.version);
62
63
  const nodeVersionString = nodeVersion
@@ -225,3 +226,11 @@ function isAnalyticsEnabled() {
225
226
  const nxJson = (0, nx_json_1.readNxJson)(workspace_root_1.workspaceRoot);
226
227
  return nxJson?.analytics === true;
227
228
  }
229
+ // Mix workspace id in: shared Docker images (Gitpod, Cypress, etc.) bake
230
+ // in /etc/machine-id, so machine-id alone collapses many users into one.
231
+ async function getTelemetryUserId(workspaceId) {
232
+ const machineId = await (0, machine_id_cache_1.getCurrentMachineId)();
233
+ return (0, crypto_1.createHash)('sha256')
234
+ .update(`${machineId}|${workspaceId}`)
235
+ .digest('hex');
236
+ }
@@ -1,109 +1,6 @@
1
1
  /**
2
- * A representation of the invocation of an Executor
2
+ * `Task` and `TaskGraph` are defined as Rust structs in
3
+ * `packages/nx/src/native/tasks/types.rs` and exposed to TypeScript via NAPI.
4
+ * This file re-exports them so existing imports keep working.
3
5
  */
4
- export interface Task {
5
- /**
6
- * Unique ID
7
- */
8
- id: string;
9
- /**
10
- * Details about which project, target, and configuration to run.
11
- */
12
- target: {
13
- /**
14
- * The project for which the task belongs to
15
- */
16
- project: string;
17
- /**
18
- * The target name which the task should invoke
19
- */
20
- target: string;
21
- /**
22
- * The configuration of the target which the task invokes
23
- */
24
- configuration?: string;
25
- };
26
- /**
27
- * Overrides for the configured options of the target
28
- */
29
- overrides: any;
30
- /**
31
- * The outputs the task may produce
32
- */
33
- outputs: string[];
34
- /**
35
- * Root of the project the task belongs to
36
- */
37
- projectRoot?: string;
38
- /**
39
- * Hash of the task which is used for caching.
40
- */
41
- hash?: string;
42
- /**
43
- * Details about the composition of the hash
44
- */
45
- hashDetails?: {
46
- /**
47
- * Command of the task
48
- */
49
- command: string;
50
- /**
51
- * Hashes of inputs used in the hash
52
- */
53
- nodes: {
54
- [name: string]: string;
55
- };
56
- /**
57
- * Hashes of implicit dependencies which are included in the hash
58
- */
59
- implicitDeps?: {
60
- [fileName: string]: string;
61
- };
62
- /**
63
- * Hash of the runtime environment which the task was executed
64
- */
65
- runtime?: {
66
- [input: string]: string;
67
- };
68
- };
69
- /**
70
- *
71
- * Unix timestamp of when a Batch Task starts
72
- **/
73
- startTime?: number;
74
- /**
75
- *
76
- * Unix timestamp of when a Batch Task ends
77
- **/
78
- endTime?: number;
79
- /**
80
- * Determines if a given task should be cacheable.
81
- */
82
- cache?: boolean;
83
- /**
84
- * Determines if a given task should be parallelizable.
85
- */
86
- parallelism: boolean;
87
- /**
88
- * This denotes if the task runs continuously
89
- */
90
- continuous?: boolean;
91
- }
92
- /**
93
- * Graph of Tasks to be executed
94
- */
95
- export interface TaskGraph {
96
- /**
97
- * IDs of Tasks which do not have any dependencies and are thus ready to execute immediately
98
- */
99
- roots: string[];
100
- /**
101
- * Map of Task IDs to Tasks
102
- */
103
- tasks: Record<string, Task>;
104
- /**
105
- * Map of Task IDs to IDs of tasks which the task depends on
106
- */
107
- dependencies: Record<string, string[]>;
108
- continuousDependencies: Record<string, string[]>;
109
- }
6
+ export type { Task, TaskGraph, TaskTarget, TaskHashDetails } from '../native';
@@ -15,7 +15,7 @@ export declare class HashPlanInspector {
15
15
  /**
16
16
  * This is a lower level method which will inspect the hash plan for a set of tasks.
17
17
  */
18
- inspectHashPlan(projectNames: string[], targets: string[], configuration?: string, overrides?: Object, extraTargetDependencies?: TargetDependencies, excludeTaskDependencies?: boolean): Record<string, string[]>;
18
+ inspectHashPlan(projectNames: string[], targets: string[], configuration?: string, overrides?: Record<string, unknown>, extraTargetDependencies?: TargetDependencies, excludeTaskDependencies?: boolean): Record<string, string[]>;
19
19
  /**
20
20
  * This inspects tasks involved in the execution of a task, including its dependencies by default.
21
21
  * @deprecated Prefer inspectTaskInputs
@@ -581,26 +581,66 @@ export interface Target {
581
581
  parallelism?: boolean
582
582
  }
583
583
 
584
+ /** A representation of the invocation of an Executor */
584
585
  export interface Task {
586
+ /** Unique ID */
585
587
  id: string
588
+ /** Details about which project, target, and configuration to run. */
586
589
  target: TaskTarget
590
+ /** Overrides for the configured options of the target */
591
+ overrides: Record<string, unknown>
592
+ /** The outputs the task may produce */
587
593
  outputs: Array<string>
594
+ /** Root of the project the task belongs to */
588
595
  projectRoot?: string
596
+ /** Hash of the task which is used for caching. */
597
+ hash?: string
598
+ /** Details about the composition of the hash */
599
+ hashDetails?: TaskHashDetails
600
+ /** Unix timestamp of when a Batch Task starts */
589
601
  startTime?: number
602
+ /** Unix timestamp of when a Batch Task ends */
590
603
  endTime?: number
604
+ /** Determines if a given task should be cacheable. */
605
+ cache?: boolean
606
+ /** Determines if a given task should be parallelizable. */
607
+ parallelism?: boolean
608
+ /** This denotes if the task runs continuously */
591
609
  continuous?: boolean
592
610
  }
593
611
 
612
+ /** Graph of Tasks to be executed */
594
613
  export interface TaskGraph {
614
+ /** IDs of Tasks which do not have any dependencies and are thus ready to execute immediately */
595
615
  roots: Array<string>
616
+ /** Map of Task IDs to Tasks */
596
617
  tasks: Record<string, Task>
618
+ /** Map of Task IDs to IDs of tasks which the task depends on */
597
619
  dependencies: Record<string, Array<string>>
598
620
  continuousDependencies: Record<string, Array<string>>
599
621
  }
600
622
 
623
+ /** Details about the composition of a task's hash */
624
+ export interface TaskHashDetails {
625
+ /** Command of the task */
626
+ command: string
627
+ /** Hashes of inputs used in the hash */
628
+ nodes: Record<string, string>
629
+ /** Hashes of implicit dependencies which are included in the hash */
630
+ implicitDeps?: Record<string, string>
631
+ /** Hash of the runtime environment which the task was executed */
632
+ runtime?: Record<string, string>
633
+ }
634
+
635
+ /**
636
+ * The result of a completed Task.
637
+ *
638
+ * Task timing information (start and end timestamps) is available
639
+ * on the Task object itself via `Task.startTime` and `Task.endTime`.
640
+ */
601
641
  export interface TaskResult {
602
642
  task: Task
603
- status: string
643
+ status: 'success' | 'failure' | 'skipped' | 'stopped' | 'local-cache-kept-existing' | 'local-cache' | 'remote-cache'
604
644
  code: number
605
645
  terminalOutput?: string
606
646
  }
@@ -627,8 +667,11 @@ export declare const enum TaskStatus {
627
667
  }
628
668
 
629
669
  export interface TaskTarget {
670
+ /** The project for which the task belongs to */
630
671
  project: string
672
+ /** The target name which the task should invoke */
631
673
  target: string
674
+ /** The configuration of the target which the task invokes */
632
675
  configuration?: string
633
676
  }
634
677
 
Binary file
@@ -270,27 +270,45 @@ function stringifyNpmLockfile(graph, rootLockFileContent, packageJson) {
270
270
  }
271
271
  return JSON.stringify(output, null, 2);
272
272
  }
273
+ const WORKSPACE_DEP_TYPES = [
274
+ 'dependencies',
275
+ 'optionalDependencies',
276
+ 'peerDependencies',
277
+ ];
273
278
  function mapWorkspaceModules(packageJson, rootLockFile, workspaceModules) {
274
279
  const output = {};
275
- for (const [pkgName, pkgVersion] of Object.entries(packageJson.dependencies ?? {})) {
276
- if (workspaceModules.has(pkgName)) {
277
- let workspaceModuleDefinition;
278
- for (const [depName, depSnapshot] of Object.entries(rootLockFile.packages || rootLockFile.dependencies)) {
279
- if (depSnapshot.name === pkgName) {
280
- workspaceModuleDefinition = depSnapshot;
281
- break;
282
- }
283
- }
284
- output[`node_modules/${pkgName}`] = {
285
- version: `file:./workspace_modules/${pkgName}`,
286
- resolved: `workspace_modules/${pkgName}`,
287
- link: true,
288
- };
289
- output[`workspace_modules/${pkgName}`] = {
290
- name: pkgName,
291
- version: `0.0.1`,
292
- dependencies: workspaceModuleDefinition.dependencies,
293
- };
280
+ const snapshotsByName = new Map();
281
+ for (const snapshot of Object.values(rootLockFile.packages || rootLockFile.dependencies || {})) {
282
+ if (snapshot.name)
283
+ snapshotsByName.set(snapshot.name, snapshot);
284
+ }
285
+ // Walk transitive workspace deps so every workspace package
286
+ // copy-workspace-modules writes to disk has matching lockfile entries.
287
+ // Without this, `npm ci` errors with "Missing: <pkg> from lock file".
288
+ const queue = Object.keys(packageJson.dependencies ?? {});
289
+ const visited = new Set();
290
+ while (queue.length > 0) {
291
+ const pkgName = queue.shift();
292
+ if (visited.has(pkgName) || !workspaceModules.has(pkgName))
293
+ continue;
294
+ visited.add(pkgName);
295
+ const snapshot = snapshotsByName.get(pkgName);
296
+ output[`node_modules/${pkgName}`] = {
297
+ version: `file:./workspace_modules/${pkgName}`,
298
+ resolved: `workspace_modules/${pkgName}`,
299
+ link: true,
300
+ };
301
+ output[`workspace_modules/${pkgName}`] = {
302
+ name: pkgName,
303
+ version: `0.0.1`,
304
+ dependencies: snapshot?.dependencies,
305
+ };
306
+ for (const depType of WORKSPACE_DEP_TYPES) {
307
+ const deps = snapshot?.[depType];
308
+ if (!deps)
309
+ continue;
310
+ for (const depName of Object.keys(deps))
311
+ queue.push(depName);
294
312
  }
295
313
  }
296
314
  return output;
@@ -14,6 +14,11 @@ const project_graph_pruning_1 = require("./project-graph-pruning");
14
14
  const path_1 = require("path");
15
15
  const get_workspace_packages_from_graph_1 = require("../utils/get-workspace-packages-from-graph");
16
16
  const semver_1 = require("semver");
17
+ const WORKSPACE_DEP_TYPES = [
18
+ 'dependencies',
19
+ 'optionalDependencies',
20
+ 'peerDependencies',
21
+ ];
17
22
  let currentLockFileHash;
18
23
  let parsedLockFile;
19
24
  function parsePnpmLockFile(lockFileContent, lockFileHash) {
@@ -389,13 +394,55 @@ function stringifyPnpmLockfile(graph, rootLockFileContent, packageJson, workspac
389
394
  const { lockfileVersion, packages, importers } = data;
390
395
  const { snapshot: rootSnapshot, importers: requiredImporters } = mapRootSnapshot(packageJson, importers, packages, graph, +lockfileVersion, workspaceRoot);
391
396
  const snapshots = mapSnapshots(data.packages, graph.externalNodes, +lockfileVersion);
397
+ const workspaceModules = (0, get_workspace_packages_from_graph_1.getWorkspacePackagesFromGraph)(graph);
398
+ // Walk transitive workspace deps so every package copy-workspace-modules
399
+ // writes to disk has a matching importer block. Without this, pnpm errors
400
+ // with ERR_PNPM_OUTDATED_LOCKFILE on transitive workspace chains.
401
+ const allRequiredImporters = { ...requiredImporters };
402
+ const queue = Object.keys(requiredImporters);
403
+ while (queue.length > 0) {
404
+ const pkgName = queue.shift();
405
+ const importer = importers[allRequiredImporters[pkgName]];
406
+ if (!importer)
407
+ continue;
408
+ for (const depType of WORKSPACE_DEP_TYPES) {
409
+ const deps = importer[depType];
410
+ if (!deps)
411
+ continue;
412
+ for (const depName of Object.keys(deps)) {
413
+ if (workspaceModules.has(depName) && !allRequiredImporters[depName]) {
414
+ allRequiredImporters[depName] =
415
+ workspaceModules.get(depName).data.root;
416
+ queue.push(depName);
417
+ }
418
+ }
419
+ }
420
+ }
392
421
  const workspaceDependencyImporters = {};
393
- for (const [packageName, importerPath] of Object.entries(requiredImporters)) {
422
+ for (const [packageName, importerPath] of Object.entries(allRequiredImporters)) {
394
423
  const baseImporter = importers[importerPath];
395
- if (baseImporter) {
396
- workspaceDependencyImporters[`workspace_modules/${packageName}`] =
397
- baseImporter;
424
+ if (!baseImporter)
425
+ continue;
426
+ const importer = structuredClone(baseImporter);
427
+ for (const depType of WORKSPACE_DEP_TYPES) {
428
+ const deps = importer[depType];
429
+ if (!deps)
430
+ continue;
431
+ for (const depName of Object.keys(deps)) {
432
+ if (!workspaceModules.has(depName))
433
+ continue;
434
+ // All workspace modules are siblings under workspace_modules/, so the
435
+ // relative path between them is relative(packageName, depName).
436
+ // Specifier must match the file: ref copy-workspace-modules writes
437
+ // to the package's package.json — pnpm errors on a mismatch.
438
+ const rel = (0, path_1.relative)(packageName, depName).split(path_1.sep).join('/');
439
+ if (!importer.specifiers)
440
+ importer.specifiers = {};
441
+ importer.specifiers[depName] = `file:${rel}`;
442
+ deps[depName] = `link:${rel}`;
443
+ }
398
444
  }
445
+ workspaceDependencyImporters[`workspace_modules/${packageName}`] = importer;
399
446
  }
400
447
  const output = {
401
448
  ...data,
@@ -115,11 +115,19 @@ function traverseNode(graph, builder, node) {
115
115
  builder.addStaticDependency(node.name, dep.target);
116
116
  });
117
117
  }
118
- function traverseWorkspaceNode(graph, builder, node) {
118
+ function traverseWorkspaceNode(graph, builder, node, visited = new Set()) {
119
+ if (visited.has(node.name))
120
+ return;
121
+ visited.add(node.name);
119
122
  graph.dependencies[node.name]?.forEach((dep) => {
120
- const depNode = graph.externalNodes[dep.target];
121
- if (depNode) {
122
- traverseNode(graph, builder, depNode);
123
+ const externalDepNode = graph.externalNodes[dep.target];
124
+ if (externalDepNode) {
125
+ traverseNode(graph, builder, externalDepNode);
126
+ return;
127
+ }
128
+ const workspaceDepNode = graph.nodes[dep.target];
129
+ if (workspaceDepNode) {
130
+ traverseWorkspaceNode(graph, builder, workspaceDepNode, visited);
123
131
  }
124
132
  });
125
133
  }
@@ -1,6 +1,7 @@
1
1
  import { NxJsonConfiguration } from '../../config/nx-json';
2
2
  import type { ProjectConfiguration } from '../../config/workspace-json-project-json';
3
3
  import { PackageJson } from '../../utils/package-json';
4
+ import { PackageManagerCommands } from '../../utils/package-manager';
4
5
  import { CreateNodesV2 } from '../../project-graph/plugins';
5
6
  import { PackageJsonConfigurationCache } from '../../../plugins/package-json';
6
7
  export declare const createNodesV2: CreateNodesV2;
@@ -12,12 +13,12 @@ type PackageJsonPatterns = {
12
13
  negativeLookup: Record<string, boolean>;
13
14
  };
14
15
  export declare function buildPackageJsonWorkspacesMatcher(patterns: PackageJsonPatterns): (p: any) => boolean;
15
- export declare function createNodeFromPackageJson(pkgJsonPath: string, workspaceRoot: string, cache: PackageJsonConfigurationCache, isInPackageManagerWorkspaces: boolean): {
16
+ export declare function createNodeFromPackageJson(pkgJsonPath: string, workspaceRoot: string, cache: PackageJsonConfigurationCache, isInPackageManagerWorkspaces: boolean, packageManagerCommand: PackageManagerCommands): {
16
17
  projects: {
17
18
  [x: string]: ProjectConfiguration;
18
19
  };
19
20
  };
20
- export declare function buildProjectConfigurationFromPackageJson(packageJson: PackageJson, workspaceRoot: string, packageJsonPath: string, nxJson: NxJsonConfiguration, isInPackageManagerWorkspaces: boolean): ProjectConfiguration & {
21
+ export declare function buildProjectConfigurationFromPackageJson(packageJson: PackageJson, workspaceRoot: string, packageJsonPath: string, nxJson: NxJsonConfiguration, isInPackageManagerWorkspaces: boolean, packageManagerCommand: PackageManagerCommands): ProjectConfiguration & {
21
22
  name: string;
22
23
  };
23
24
  /**
@@ -16,6 +16,7 @@ const globs_1 = require("../../utils/globs");
16
16
  const logger_1 = require("../../utils/logger");
17
17
  const output_1 = require("../../utils/output");
18
18
  const package_json_1 = require("../../utils/package-json");
19
+ const package_manager_1 = require("../../utils/package-manager");
19
20
  const path_1 = require("../../utils/path");
20
21
  const versions_1 = require("../../utils/versions");
21
22
  const plugins_1 = require("../../project-graph/plugins");
@@ -38,6 +39,7 @@ exports.createNodesV2 = [
38
39
  return projectJsonRoots.has((0, node_path_1.dirname)(packageJsonPath));
39
40
  };
40
41
  const cache = (0, package_json_2.readPackageJsonConfigurationCache)();
42
+ const packageManagerCommand = (0, package_manager_1.getPackageManagerCommand)((0, package_manager_1.detectPackageManager)(context.workspaceRoot), context.workspaceRoot);
41
43
  return (0, plugins_1.createNodesFromFiles)((packageJsonPath, options, context) => {
42
44
  const isInPackageManagerWorkspaces = isInPackageJsonWorkspaces(packageJsonPath);
43
45
  if (!isInPackageManagerWorkspaces &&
@@ -45,7 +47,7 @@ exports.createNodesV2 = [
45
47
  // Skip if package.json is not part of the package.json workspaces and not next to a project.json.
46
48
  return null;
47
49
  }
48
- return createNodeFromPackageJson(packageJsonPath, context.workspaceRoot, cache, isInPackageManagerWorkspaces);
50
+ return createNodeFromPackageJson(packageJsonPath, context.workspaceRoot, cache, isInPackageManagerWorkspaces, packageManagerCommand);
49
51
  }, packageJsons, _, context);
50
52
  },
51
53
  ];
@@ -111,7 +113,7 @@ function buildPackageJsonWorkspacesMatcher(patterns) {
111
113
  !patterns.negativeLookup[p] &&
112
114
  patterns.negative.every((negative) => (0, minimatch_1.minimatch)(p, negative));
113
115
  }
114
- function createNodeFromPackageJson(pkgJsonPath, workspaceRoot, cache, isInPackageManagerWorkspaces) {
116
+ function createNodeFromPackageJson(pkgJsonPath, workspaceRoot, cache, isInPackageManagerWorkspaces, packageManagerCommand) {
115
117
  const json = (0, fileutils_1.readJsonFile)((0, node_path_1.join)(workspaceRoot, pkgJsonPath));
116
118
  const projectRoot = (0, node_path_1.dirname)(pkgJsonPath);
117
119
  const hash = (0, file_hasher_1.hashObject)({
@@ -128,7 +130,7 @@ function createNodeFromPackageJson(pkgJsonPath, workspaceRoot, cache, isInPackag
128
130
  },
129
131
  };
130
132
  }
131
- const project = buildProjectConfigurationFromPackageJson(json, workspaceRoot, pkgJsonPath, (0, nx_json_1.readNxJson)(workspaceRoot), isInPackageManagerWorkspaces);
133
+ const project = buildProjectConfigurationFromPackageJson(json, workspaceRoot, pkgJsonPath, (0, nx_json_1.readNxJson)(workspaceRoot), isInPackageManagerWorkspaces, packageManagerCommand);
132
134
  cache.set(hash, project);
133
135
  return {
134
136
  projects: {
@@ -136,7 +138,7 @@ function createNodeFromPackageJson(pkgJsonPath, workspaceRoot, cache, isInPackag
136
138
  },
137
139
  };
138
140
  }
139
- function buildProjectConfigurationFromPackageJson(packageJson, workspaceRoot, packageJsonPath, nxJson, isInPackageManagerWorkspaces) {
141
+ function buildProjectConfigurationFromPackageJson(packageJson, workspaceRoot, packageJsonPath, nxJson, isInPackageManagerWorkspaces, packageManagerCommand) {
140
142
  const normalizedPath = packageJsonPath.split('\\').join('/');
141
143
  const projectRoot = (0, node_path_1.dirname)(normalizedPath);
142
144
  const siblingProjectJson = tryReadJson((0, node_path_1.join)(workspaceRoot, projectRoot, 'project.json'));
@@ -161,7 +163,7 @@ function buildProjectConfigurationFromPackageJson(packageJson, workspaceRoot, pa
161
163
  root: projectRoot,
162
164
  name,
163
165
  ...packageJson.nx,
164
- targets: (0, package_json_1.readTargetsFromPackageJson)(packageJson, nxJson, projectRoot, workspaceRoot),
166
+ targets: (0, package_json_1.readTargetsFromPackageJson)(packageJson, nxJson, projectRoot, workspaceRoot, packageManagerCommand),
165
167
  tags: (0, package_json_1.getTagsFromPackageJson)(packageJson),
166
168
  metadata: (0, package_json_1.getMetadataFromPackageJson)(packageJson, isInPackageManagerWorkspaces),
167
169
  };
@@ -16,16 +16,16 @@ export declare class ProcessTasks {
16
16
  };
17
17
  private readonly allTargetNames;
18
18
  constructor(extraTargetDependencies: TargetDependencies, projectGraph: ProjectGraph);
19
- processTasks(projectNames: string[], targets: string[], configuration: string, overrides: Object, excludeTaskDependencies: boolean): string[];
20
- processTask(task: Task, projectUsedToDeriveDependencies: string, configuration: string, overrides: Object): void;
19
+ processTasks(projectNames: string[], targets: string[], configuration: string, overrides: Record<string, unknown>, excludeTaskDependencies: boolean): string[];
20
+ processTask(task: Task, projectUsedToDeriveDependencies: string, configuration: string, overrides: Record<string, unknown>): void;
21
21
  private processTasksForMultipleProjects;
22
22
  private processTasksForSingleProject;
23
23
  private processTasksForDependencies;
24
24
  private createDummyTask;
25
- createTask(id: string, project: ProjectGraphProjectNode, target: string, resolvedConfiguration: string | undefined, overrides: Object): Task;
25
+ createTask(id: string, project: ProjectGraphProjectNode, target: string, resolvedConfiguration: string | undefined, overrides: Record<string, unknown>): Task;
26
26
  resolveConfiguration(project: ProjectGraphProjectNode, target: string, configuration: string | undefined): string;
27
27
  }
28
- export declare function createTaskGraph(projectGraph: ProjectGraph, extraTargetDependencies: TargetDependencies, projectNames: string[], targets: string[], configuration: string | undefined, overrides: Object, excludeTaskDependencies?: boolean): TaskGraph;
28
+ export declare function createTaskGraph(projectGraph: ProjectGraph, extraTargetDependencies: TargetDependencies, projectNames: string[], targets: string[], configuration: string | undefined, overrides: Record<string, unknown>, excludeTaskDependencies?: boolean): TaskGraph;
29
29
  export declare function mapTargetDefaultsToDependencies(defaults: TargetDefaults | undefined): TargetDependencies;
30
30
  /**
31
31
  * This function is used to filter out the dummy tasks from the dependencies
@@ -1,19 +1,18 @@
1
1
  import { Task } from '../config/task-graph';
2
- import { BatchInfo, BatchStatus, ExternalObject, TaskStatus as NativeTaskStatus } from '../native';
2
+ import { BatchInfo, BatchStatus, ExternalObject, TaskResult, TaskStatus as NativeTaskStatus } from '../native';
3
3
  import { TaskStatus } from './tasks-runner';
4
4
  /**
5
- * The result of a completed {@link Task}
5
+ * The result of a completed {@link Task}.
6
+ *
7
+ * Defined as a Rust struct in `packages/nx/src/native/tasks/types.rs` and
8
+ * exposed to TypeScript via NAPI. Re-exported here so existing imports
9
+ * keep working.
6
10
  *
7
11
  * Task timing information (start and end timestamps) is available
8
12
  * on the {@link Task} object itself via {@link Task.startTime} and
9
13
  * {@link Task.endTime}.
10
14
  */
11
- export interface TaskResult {
12
- task: Task;
13
- status: TaskStatus;
14
- code: number;
15
- terminalOutput?: string;
16
- }
15
+ export type { TaskResult };
17
16
  /**
18
17
  * A map of {@link TaskResult} keyed by the ID of the completed {@link Task}s
19
18
  */
@@ -13,9 +13,10 @@ class InvokeRunnerTerminalOutputLifeCycle {
13
13
  output_1.output.log({
14
14
  color: 'cyan',
15
15
  title: `Running ${this.tasks.length} tasks:`,
16
- bodyLines: this.tasks.map((task) => `- Task ${task.id} ${task.overrides.__overrides_unparsed__.length > 0
17
- ? `Overrides: ${task.overrides.__overrides_unparsed__.join(' ')}`
18
- : ''}`),
16
+ bodyLines: this.tasks.map((task) => {
17
+ const unparsed = (0, utils_1.getUnparsedOverrideArgs)(task);
18
+ return `- Task ${task.id} ${unparsed.length > 0 ? `Overrides: ${unparsed.join(' ')}` : ''}`;
19
+ }),
19
20
  });
20
21
  output_1.output.addVerticalSeparatorWithoutNewLines('cyan');
21
22
  }
@@ -24,9 +25,8 @@ class InvokeRunnerTerminalOutputLifeCycle {
24
25
  const taskIds = this.tasks.map((task) => {
25
26
  const cached = this.cachedTasks.indexOf(task) !== -1;
26
27
  const failed = this.failedTasks.indexOf(task) !== -1;
27
- return `- Task ${task.id} ${task.overrides.__overrides_unparsed__.length > 0
28
- ? `Overrides: ${task.overrides.__overrides_unparsed__.join(' ')}`
29
- : ''} ${cached ? 'CACHED' : ''} ${failed ? 'FAILED' : ''}`;
28
+ const unparsed = (0, utils_1.getUnparsedOverrideArgs)(task);
29
+ return `- Task ${task.id} ${unparsed.length > 0 ? `Overrides: ${unparsed.join(' ')}` : ''} ${cached ? 'CACHED' : ''} ${failed ? 'FAILED' : ''}`;
30
30
  });
31
31
  if (this.failedTasks.length === 0) {
32
32
  output_1.output.addVerticalSeparatorWithoutNewLines('green');
@@ -50,6 +50,7 @@ export declare function getCustomHasher(task: Task, projects: Record<string, Pro
50
50
  export declare function removeTasksFromTaskGraph(graph: TaskGraph, ids: string[]): TaskGraph;
51
51
  export declare function calculateReverseDeps(taskGraph: TaskGraph): Record<string, string[]>;
52
52
  export declare function getCliPath(): string;
53
+ export declare function getUnparsedOverrideArgs(task: Task): string[];
53
54
  export declare function getPrintableCommandArgsForTask(task: Task): string[];
54
55
  export declare function getSerializedArgsForTask(task: Task, isVerbose: boolean): string[];
55
56
  export declare function shouldStreamOutput(task: Task, initiatingProject: string | null): boolean;
@@ -20,6 +20,7 @@ exports.getCustomHasher = getCustomHasher;
20
20
  exports.removeTasksFromTaskGraph = removeTasksFromTaskGraph;
21
21
  exports.calculateReverseDeps = calculateReverseDeps;
22
22
  exports.getCliPath = getCliPath;
23
+ exports.getUnparsedOverrideArgs = getUnparsedOverrideArgs;
23
24
  exports.getPrintableCommandArgsForTask = getPrintableCommandArgsForTask;
24
25
  exports.getSerializedArgsForTask = getSerializedArgsForTask;
25
26
  exports.shouldStreamOutput = shouldStreamOutput;
@@ -206,7 +207,7 @@ function transformLegacyOutputs(projectRoot, outputs) {
206
207
  function getOutputsForTargetAndConfiguration(taskTargetOrTask, overridesOrNode, node) {
207
208
  const taskTarget = 'id' in taskTargetOrTask ? taskTargetOrTask.target : taskTargetOrTask;
208
209
  const overrides = 'id' in taskTargetOrTask ? taskTargetOrTask.overrides : overridesOrNode;
209
- node = 'id' in taskTargetOrTask ? overridesOrNode : node;
210
+ node = ('id' in taskTargetOrTask ? overridesOrNode : node);
210
211
  const { target, configuration } = taskTarget;
211
212
  const targetConfiguration = node.data.targets[target];
212
213
  const options = {
@@ -385,8 +386,12 @@ function calculateReverseDeps(taskGraph) {
385
386
  function getCliPath() {
386
387
  return require.resolve(`../../bin/run-executor.js`);
387
388
  }
389
+ function getUnparsedOverrideArgs(task) {
390
+ return task.overrides
391
+ .__overrides_unparsed__;
392
+ }
388
393
  function getPrintableCommandArgsForTask(task) {
389
- const args = task.overrides['__overrides_unparsed__'];
394
+ const args = getUnparsedOverrideArgs(task);
390
395
  const target = task.target.target.includes(':')
391
396
  ? `"${task.target.target}"`
392
397
  : task.target.target;
@@ -13,8 +13,8 @@ const exit_codes_1 = require("./exit-codes");
13
13
  function getRunNxBaseCommand(packageManagerCommand, cwd = process.cwd()) {
14
14
  if ((0, fs_1.existsSync)((0, path_1.join)(workspace_root_1.workspaceRoot, 'package.json'))) {
15
15
  if (!packageManagerCommand) {
16
- const pm = (0, package_manager_1.detectPackageManager)();
17
- packageManagerCommand = (0, package_manager_1.getPackageManagerCommand)(pm);
16
+ const pm = (0, package_manager_1.detectPackageManager)(workspace_root_1.workspaceRoot);
17
+ packageManagerCommand = (0, package_manager_1.getPackageManagerCommand)(pm, workspace_root_1.workspaceRoot);
18
18
  }
19
19
  return `${packageManagerCommand.exec} nx`;
20
20
  }
@@ -94,7 +94,7 @@ export declare function readNxMigrateConfig(json: Partial<PackageJson>): NxMigra
94
94
  export declare function buildTargetFromScript(script: string, scripts: Record<string, string>, packageManagerCommand: PackageManagerCommands): TargetConfiguration;
95
95
  export declare function getMetadataFromPackageJson(packageJson: PackageJson, isInPackageManagerWorkspaces: boolean): ProjectMetadata;
96
96
  export declare function getTagsFromPackageJson(packageJson: PackageJson): string[];
97
- export declare function readTargetsFromPackageJson(packageJson: PackageJson, nxJson: NxJsonConfiguration, projectRoot: string, workspaceRoot: string): Record<string, TargetConfiguration<any>>;
97
+ export declare function readTargetsFromPackageJson(packageJson: PackageJson, nxJson: NxJsonConfiguration, projectRoot: string, workspaceRoot: string, packageManagerCommand: PackageManagerCommands): Record<string, TargetConfiguration<any>>;
98
98
  /**
99
99
  * Uses `require.resolve` to read the package.json for a module.
100
100
  *
@@ -67,7 +67,6 @@ function buildTargetFromScript(script, scripts = {}, packageManagerCommand) {
67
67
  },
68
68
  };
69
69
  }
70
- let packageManagerCommand;
71
70
  function getMetadataFromPackageJson(packageJson, isInPackageManagerWorkspaces) {
72
71
  const { scripts, nx, description, name, exports, main, version } = packageJson;
73
72
  const includedScripts = nx?.includedScripts || Object.keys(scripts ?? {});
@@ -95,12 +94,11 @@ function getTagsFromPackageJson(packageJson) {
95
94
  }
96
95
  return tags;
97
96
  }
98
- function readTargetsFromPackageJson(packageJson, nxJson, projectRoot, workspaceRoot) {
97
+ function readTargetsFromPackageJson(packageJson, nxJson, projectRoot, workspaceRoot, packageManagerCommand) {
99
98
  const { scripts, nx, private: isPrivate } = packageJson ?? {};
100
99
  const res = {};
101
100
  const includedScripts = nx?.includedScripts || Object.keys(scripts ?? {});
102
101
  for (const script of includedScripts) {
103
- packageManagerCommand ??= (0, package_manager_1.getPackageManagerCommand)();
104
102
  res[script] = buildTargetFromScript(script, scripts, packageManagerCommand);
105
103
  }
106
104
  for (const targetName in nx?.targets) {
@@ -210,11 +208,11 @@ function preparePackageInstallation(pkg, requiredVersion) {
210
208
  cleanup: () => { },
211
209
  };
212
210
  console.log(`Fetching ${pkg}...`);
213
- const packageManager = (0, package_manager_1.detectPackageManager)();
211
+ const packageManager = (0, package_manager_1.detectPackageManager)(workspace_root_1.workspaceRoot);
214
212
  const isVerbose = process.env.NX_VERBOSE_LOGGING === 'true';
215
213
  generatePackageManagerFiles(tempDir, packageManager);
216
- const preInstallCommand = (0, package_manager_1.getPackageManagerCommand)(packageManager).preInstall;
217
214
  const pmCommands = (0, package_manager_1.getPackageManagerCommand)(packageManager);
215
+ const preInstallCommand = pmCommands.preInstall;
218
216
  let addCommand = pmCommands.addDev;
219
217
  if (packageManager === 'pnpm') {
220
218
  addCommand = 'pnpm add -D'; // we need to ensure that we are not using workspace command
@@ -21,8 +21,17 @@ interface PluginCacheData<T> {
21
21
  export declare class PluginCache<T> {
22
22
  private entries;
23
23
  private accessOrder;
24
- constructor(cachePath: string);
25
- constructor(entries?: Record<string, T>, accessOrder?: string[] | Set<string>);
24
+ private cachePath;
25
+ /**
26
+ * Constructs a `PluginCache`. The `cachePath` is the single source of truth
27
+ * for both reading and writing — `writeToDisk()` writes to it.
28
+ *
29
+ * If `entries` is omitted, the cache is loaded from `cachePath` on disk.
30
+ * If `entries` is provided, those entries are used as the in-memory state
31
+ * and the on-disk file is not read (useful for tests or for seeding the
32
+ * cache with known state).
33
+ */
34
+ constructor(cachePath: string, entries?: Record<string, T>, accessOrder?: string[] | Set<string>);
26
35
  private touch;
27
36
  /**
28
37
  * Returns the value for `key`, or `undefined` if not present.
@@ -44,7 +53,7 @@ export declare class PluginCache<T> {
44
53
  */
45
54
  toSerializable(): PluginCacheData<T>;
46
55
  /**
47
- * Safely writes this cache to disk.
56
+ * Safely writes this cache to the path it was constructed with.
48
57
  *
49
58
  * Strategy:
50
59
  * 1. Serialize to JSON
@@ -55,7 +64,7 @@ export declare class PluginCache<T> {
55
64
  * 3. On total serialization failure (even after eviction),
56
65
  * write an empty cache so the file is valid
57
66
  */
58
- writeToDisk(cachePath: string): void;
67
+ writeToDisk(): void;
59
68
  /**
60
69
  * Evicts the oldest 50% of entries (front of the access-order queue)
61
70
  * and returns the remaining entries + accessOrder as a plain object.
@@ -20,17 +20,27 @@ const logger_1 = require("./logger");
20
20
  * least recently used keys.
21
21
  */
22
22
  class PluginCache {
23
- constructor(cachePathOrEntries, accessOrder) {
24
- if (typeof cachePathOrEntries === 'string') {
25
- const loaded = loadFromDisk(cachePathOrEntries);
26
- this.entries = loaded.entries;
27
- this.accessOrder = loaded.accessOrder;
28
- }
29
- else {
30
- this.entries = cachePathOrEntries ?? {};
23
+ /**
24
+ * Constructs a `PluginCache`. The `cachePath` is the single source of truth
25
+ * for both reading and writing — `writeToDisk()` writes to it.
26
+ *
27
+ * If `entries` is omitted, the cache is loaded from `cachePath` on disk.
28
+ * If `entries` is provided, those entries are used as the in-memory state
29
+ * and the on-disk file is not read (useful for tests or for seeding the
30
+ * cache with known state).
31
+ */
32
+ constructor(cachePath, entries, accessOrder) {
33
+ this.cachePath = cachePath;
34
+ if (entries !== undefined) {
35
+ this.entries = entries;
31
36
  this.accessOrder =
32
37
  accessOrder instanceof Set ? accessOrder : new Set(accessOrder ?? []);
33
38
  }
39
+ else {
40
+ const loaded = loadFromDisk(cachePath);
41
+ this.entries = loaded.entries;
42
+ this.accessOrder = loaded.accessOrder;
43
+ }
34
44
  }
35
45
  touch(key) {
36
46
  // Sets are guaranteed to maintain insertion order, so we can delete and re-add to move it to the end.
@@ -73,7 +83,7 @@ class PluginCache {
73
83
  };
74
84
  }
75
85
  /**
76
- * Safely writes this cache to disk.
86
+ * Safely writes this cache to the path it was constructed with.
77
87
  *
78
88
  * Strategy:
79
89
  * 1. Serialize to JSON
@@ -84,8 +94,8 @@ class PluginCache {
84
94
  * 3. On total serialization failure (even after eviction),
85
95
  * write an empty cache so the file is valid
86
96
  */
87
- writeToDisk(cachePath) {
88
- (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(cachePath), { recursive: true });
97
+ writeToDisk() {
98
+ (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(this.cachePath), { recursive: true });
89
99
  let content;
90
100
  try {
91
101
  content = JSON.stringify({
@@ -115,11 +125,11 @@ class PluginCache {
115
125
  }
116
126
  // Attempt to write the serialized content to disk
117
127
  try {
118
- (0, node_fs_1.writeFileSync)(cachePath, content);
128
+ (0, node_fs_1.writeFileSync)(this.cachePath, content);
119
129
  }
120
130
  catch {
121
131
  // Filesystem error — wipe cache so a corrupted file doesn't persist
122
- tryRemoveFile(cachePath);
132
+ tryRemoveFile(this.cachePath);
123
133
  }
124
134
  }
125
135
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nx",
3
- "version": "23.0.0-beta.5",
3
+ "version": "23.0.0-beta.7",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.",
@@ -171,16 +171,16 @@
171
171
  }
172
172
  },
173
173
  "optionalDependencies": {
174
- "@nx/nx-darwin-arm64": "23.0.0-beta.5",
175
- "@nx/nx-darwin-x64": "23.0.0-beta.5",
176
- "@nx/nx-freebsd-x64": "23.0.0-beta.5",
177
- "@nx/nx-linux-arm-gnueabihf": "23.0.0-beta.5",
178
- "@nx/nx-linux-arm64-gnu": "23.0.0-beta.5",
179
- "@nx/nx-linux-arm64-musl": "23.0.0-beta.5",
180
- "@nx/nx-linux-x64-gnu": "23.0.0-beta.5",
181
- "@nx/nx-linux-x64-musl": "23.0.0-beta.5",
182
- "@nx/nx-win32-arm64-msvc": "23.0.0-beta.5",
183
- "@nx/nx-win32-x64-msvc": "23.0.0-beta.5"
174
+ "@nx/nx-darwin-arm64": "23.0.0-beta.7",
175
+ "@nx/nx-darwin-x64": "23.0.0-beta.7",
176
+ "@nx/nx-freebsd-x64": "23.0.0-beta.7",
177
+ "@nx/nx-linux-arm-gnueabihf": "23.0.0-beta.7",
178
+ "@nx/nx-linux-arm64-gnu": "23.0.0-beta.7",
179
+ "@nx/nx-linux-arm64-musl": "23.0.0-beta.7",
180
+ "@nx/nx-linux-x64-gnu": "23.0.0-beta.7",
181
+ "@nx/nx-linux-x64-musl": "23.0.0-beta.7",
182
+ "@nx/nx-win32-arm64-msvc": "23.0.0-beta.7",
183
+ "@nx/nx-win32-x64-msvc": "23.0.0-beta.7"
184
184
  },
185
185
  "nx-migrations": {
186
186
  "migrations": "./migrations.json",