nx 23.3.0-beta.4 → 23.3.0-beta.6

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.
Files changed (113) hide show
  1. package/dist/nx-cloud-internals.d.ts +1 -0
  2. package/dist/nx-cloud-internals.js +9 -0
  3. package/dist/plugins/package-json.js +1 -1
  4. package/dist/src/command-line/affected/affected.js +51 -9
  5. package/dist/src/command-line/graph/graph.d.ts +31 -0
  6. package/dist/src/command-line/graph/graph.js +71 -17
  7. package/dist/src/command-line/release/publish.js +7 -11
  8. package/dist/src/command-line/release/utils/get-touched-projects-for-group.js +3 -3
  9. package/dist/src/command-line/run/run-one.js +5 -1
  10. package/dist/src/command-line/run-many/run-many.js +6 -12
  11. package/dist/src/command-line/show/projects.js +30 -1
  12. package/dist/src/config/task-graph.d.ts +1 -1
  13. package/dist/src/config/workspace-json-project-json.d.ts +21 -1
  14. package/dist/src/core/graph/main.js +1 -1
  15. package/dist/src/core/graph/runtime.js +1 -1
  16. package/dist/src/core/graph/styles.js +1 -1
  17. package/dist/src/daemon/client/client.d.ts +7 -2
  18. package/dist/src/daemon/client/client.js +15 -2
  19. package/dist/src/daemon/message-types/io-snapshot-version.d.ts +5 -0
  20. package/dist/src/daemon/message-types/io-snapshot-version.js +2 -0
  21. package/dist/src/daemon/message-types/select-affected-tasks.d.ts +18 -0
  22. package/dist/src/daemon/message-types/select-affected-tasks.js +11 -0
  23. package/dist/src/daemon/server/handle-hash-tasks.d.ts +2 -0
  24. package/dist/src/daemon/server/handle-hash-tasks.js +5 -3
  25. package/dist/src/daemon/server/handle-select-affected-tasks.d.ts +3 -0
  26. package/dist/src/daemon/server/handle-select-affected-tasks.js +23 -0
  27. package/dist/src/daemon/server/io-snapshots-state.d.ts +7 -0
  28. package/dist/src/daemon/server/io-snapshots-state.js +35 -0
  29. package/dist/src/daemon/server/planning-context.d.ts +8 -0
  30. package/dist/src/daemon/server/planning-context.js +18 -0
  31. package/dist/src/daemon/server/server.d.ts +1 -0
  32. package/dist/src/daemon/server/server.js +6 -0
  33. package/dist/src/executors/run-commands/run-commands.impl.d.ts +2 -1
  34. package/dist/src/executors/run-commands/run-commands.impl.js +19 -5
  35. package/dist/src/executors/run-commands/running-tasks.d.ts +5 -4
  36. package/dist/src/executors/run-commands/running-tasks.js +13 -13
  37. package/dist/src/hasher/create-task-hasher.d.ts +8 -1
  38. package/dist/src/hasher/create-task-hasher.js +13 -3
  39. package/dist/src/hasher/hash-plan-inspector.js +2 -2
  40. package/dist/src/hasher/hash-task.d.ts +2 -2
  41. package/dist/src/hasher/hash-task.js +7 -1
  42. package/dist/src/hasher/native-task-hasher-impl.d.ts +13 -5
  43. package/dist/src/hasher/native-task-hasher-impl.js +38 -15
  44. package/dist/src/hasher/task-hasher.d.ts +17 -9
  45. package/dist/src/hasher/task-hasher.js +16 -11
  46. package/dist/src/hasher/task-planning-context.d.ts +13 -0
  47. package/dist/src/hasher/task-planning-context.js +12 -0
  48. package/dist/src/io-snapshots/config.d.ts +23 -0
  49. package/dist/src/io-snapshots/config.js +32 -0
  50. package/dist/src/io-snapshots/fetch.d.ts +21 -0
  51. package/dist/src/io-snapshots/fetch.js +43 -0
  52. package/dist/src/io-snapshots/outputs.d.ts +12 -0
  53. package/dist/src/io-snapshots/outputs.js +33 -0
  54. package/dist/src/io-snapshots/overrides.d.ts +12 -0
  55. package/dist/src/io-snapshots/overrides.js +49 -0
  56. package/dist/src/io-snapshots/report.d.ts +13 -0
  57. package/dist/src/io-snapshots/report.js +68 -0
  58. package/dist/src/io-snapshots/store.d.ts +37 -0
  59. package/dist/src/io-snapshots/store.js +162 -0
  60. package/dist/src/native/index.d.ts +264 -2
  61. package/dist/src/native/native-bindings.js +10 -0
  62. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  63. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  64. package/dist/src/native/transform-objects.d.ts +11 -2
  65. package/dist/src/native/transform-objects.js +46 -0
  66. package/dist/src/nx-cloud/update-manager.d.ts +3 -0
  67. package/dist/src/plugins/js/project-graph/affected/lock-file-changes.d.ts +10 -2
  68. package/dist/src/plugins/js/project-graph/affected/lock-file-changes.js +51 -29
  69. package/dist/src/plugins/js/project-graph/affected/npm-packages.d.ts +10 -2
  70. package/dist/src/plugins/js/project-graph/affected/npm-packages.js +32 -11
  71. package/dist/src/plugins/package-json/create-nodes.d.ts +2 -2
  72. package/dist/src/plugins/package-json/create-nodes.js +13 -13
  73. package/dist/src/project-graph/affected/affected-project-graph-models.d.ts +14 -0
  74. package/dist/src/project-graph/affected/affected-project-graph.js +5 -18
  75. package/dist/src/project-graph/affected/affected-projects.d.ts +7 -0
  76. package/dist/src/project-graph/affected/affected-projects.js +42 -0
  77. package/dist/src/project-graph/affected/affected-tasks.d.ts +90 -0
  78. package/dist/src/project-graph/affected/affected-tasks.js +214 -0
  79. package/dist/src/project-graph/file-utils.js +6 -2
  80. package/dist/src/project-graph/utils/project-configuration/target-merging.js +67 -0
  81. package/dist/src/project-graph/utils/project-configuration/target-normalization.js +83 -0
  82. package/dist/src/project-graph/utils/project-configuration/utils.d.ts +1 -0
  83. package/dist/src/project-graph/utils/project-configuration/utils.js +1 -0
  84. package/dist/src/tasks-runner/create-task-graph.d.ts +24 -1
  85. package/dist/src/tasks-runner/create-task-graph.js +56 -2
  86. package/dist/src/tasks-runner/forked-process-task-runner.js +3 -3
  87. package/dist/src/tasks-runner/init-tasks-runner.d.ts +7 -2
  88. package/dist/src/tasks-runner/init-tasks-runner.js +17 -6
  89. package/dist/src/tasks-runner/run-command.d.ts +41 -5
  90. package/dist/src/tasks-runner/run-command.js +84 -18
  91. package/dist/src/tasks-runner/task-io-service.d.ts +11 -3
  92. package/dist/src/tasks-runner/task-io-service.js +14 -5
  93. package/dist/src/tasks-runner/task-orchestrator.js +1 -1
  94. package/dist/src/tasks-runner/utils.d.ts +5 -0
  95. package/dist/src/tasks-runner/utils.js +9 -0
  96. package/dist/src/utils/db-connection.d.ts +1 -0
  97. package/dist/src/utils/db-connection.js +1 -0
  98. package/dist/src/utils/json-diff.d.ts +4 -2
  99. package/dist/src/utils/json-diff.js +6 -94
  100. package/dist/src/utils/nx-cloud-utils.d.ts +2 -0
  101. package/dist/src/utils/nx-cloud-utils.js +6 -1
  102. package/dist/src/utils/project-graph-utils.d.ts +2 -0
  103. package/dist/src/utils/project-graph-utils.js +12 -0
  104. package/package.json +22 -13
  105. package/readme-template.md +16 -0
  106. package/schemas/nx-schema.json +34 -0
  107. package/schemas/project-schema.json +31 -0
  108. package/dist/src/project-graph/affected/locators/project-glob-changes.d.ts +0 -2
  109. package/dist/src/project-graph/affected/locators/project-glob-changes.js +0 -40
  110. package/dist/src/project-graph/affected/locators/workspace-json-changes.d.ts +0 -4
  111. package/dist/src/project-graph/affected/locators/workspace-json-changes.js +0 -47
  112. package/dist/src/project-graph/affected/locators/workspace-projects.d.ts +0 -3
  113. package/dist/src/project-graph/affected/locators/workspace-projects.js +0 -74
@@ -1,7 +1,52 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.transformProjectGraphForRust = transformProjectGraphForRust;
4
+ exports.transformProjectGraphForLocators = transformProjectGraphForLocators;
5
+ exports.toRustProjectGraph = toRustProjectGraph;
6
+ const index_1 = require("./index");
7
+ /**
8
+ * Keyed by graph identity, but weak so a replaced graph is collectable. A run's
9
+ * hasher reuses what affected's planner already copied.
10
+ */
11
+ const transferred = new WeakMap();
12
+ /** The graph copied into Rust, once per graph. */
4
13
  function transformProjectGraphForRust(graph) {
14
+ let ref = transferred.get(graph);
15
+ if (!ref) {
16
+ ref = (0, index_1.transferProjectGraph)(toRustProjectGraph(graph));
17
+ transferred.set(graph, ref);
18
+ }
19
+ return ref;
20
+ }
21
+ /** Per graph like `transferred`: `nx release` runs the locators once per commit. */
22
+ const transferredForLocators = new WeakMap();
23
+ /**
24
+ * Only what the touched-project locators read: project roots, named inputs and
25
+ * target inputs. Copying target options and every edge costs several times
26
+ * what the locators themselves do on a large workspace.
27
+ */
28
+ function transformProjectGraphForLocators(graph) {
29
+ let ref = transferredForLocators.get(graph);
30
+ if (!ref) {
31
+ const nodes = {};
32
+ for (const [name, node] of Object.entries(graph.nodes)) {
33
+ const targets = {};
34
+ for (const [target, config] of Object.entries(node.data.targets ?? {})) {
35
+ targets[target] = { inputs: config.inputs };
36
+ }
37
+ nodes[name] = {
38
+ root: node.data.root,
39
+ namedInputs: node.data.namedInputs,
40
+ targets,
41
+ };
42
+ }
43
+ ref = (0, index_1.transferProjectGraph)({ nodes, externalNodes: {}, dependencies: {} });
44
+ transferredForLocators.set(graph, ref);
45
+ }
46
+ return ref;
47
+ }
48
+ /** The graph in Rust's shape, still a JS object. Uncached, so safe to edit. */
49
+ function toRustProjectGraph(graph) {
5
50
  const dependencies = {};
6
51
  const nodes = {};
7
52
  const externalNodes = {};
@@ -32,6 +77,7 @@ function transformProjectGraphForRust(graph) {
32
77
  }
33
78
  for (const [projectName, externalNode] of Object.entries(graph.externalNodes ?? {})) {
34
79
  externalNodes[projectName] = {
80
+ type: externalNode.type,
35
81
  packageName: externalNode.data.packageName,
36
82
  hash: externalNode.data.hash,
37
83
  version: externalNode.data.version,
@@ -1,4 +1,5 @@
1
1
  import type { CloudTaskRunnerOptions } from './nx-cloud-tasks-runner-shell';
2
+ import type { ReadIoSnapshotsOptions, ReadIoSnapshotsResult } from '../io-snapshots/fetch';
2
3
  import { TasksRunner } from '../tasks-runner/tasks-runner';
3
4
  import { RemoteCacheV2 } from '../tasks-runner/default-tasks-runner';
4
5
  export declare class NxCloudEnterpriseOutdatedError extends Error {
@@ -12,6 +13,8 @@ export interface NxCloudClient {
12
13
  commands: Record<string, () => Promise<void>>;
13
14
  nxCloudTasksRunner: TasksRunner<CloudTaskRunnerOptions>;
14
15
  getRemoteCache: () => RemoteCacheV2;
16
+ /** Clients that expose I/O snapshots; see `fetchIoSnapshots`. */
17
+ readIoSnapshots?: (options: ReadIoSnapshotsOptions) => Promise<ReadIoSnapshotsResult | null>;
15
18
  }
16
19
  export declare function verifyOrUpdateNxCloudClient(options?: {
17
20
  url?: string;
@@ -1,3 +1,11 @@
1
- import { TouchedProjectLocator } from '../../../../project-graph/affected/affected-project-graph-models';
2
- import { LockFileChange, WholeFileChange } from '../../../../project-graph/file-utils';
1
+ import { DependencyChanges, TouchedProjectLocator } from '../../../../project-graph/affected/affected-project-graph-models';
2
+ import { FileChange, LockFileChange, WholeFileChange } from '../../../../project-graph/file-utils';
3
+ import { ProjectGraph, ProjectGraphProjectNode } from '../../../../config/project-graph';
4
+ import { NxJsonConfiguration } from '../../../../config/nx-json';
5
+ import { PackageJson } from '../../../../utils/package-json';
3
6
  export declare const getTouchedProjectsFromLockFile: TouchedProjectLocator<WholeFileChange | LockFileChange>;
7
+ /**
8
+ * The same change as task selection consumes it: the packages that moved,
9
+ * which a plan names as `External`, rather than the projects depending on them.
10
+ */
11
+ export declare function lockFileDependencyChanges(fileChanges: FileChange<WholeFileChange | LockFileChange>[], projectGraphNodes: Record<string, ProjectGraphProjectNode>, nxJson: NxJsonConfiguration, packageJson: PackageJson | undefined, projectGraph: ProjectGraph): DependencyChanges;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getTouchedProjectsFromLockFile = void 0;
4
+ exports.lockFileDependencyChanges = lockFileDependencyChanges;
4
5
  const file_utils_1 = require("../../../../project-graph/file-utils");
5
6
  const config_1 = require("../../utils/config");
6
7
  const find_matching_projects_1 = require("../../../../utils/find-matching-projects");
@@ -9,61 +10,82 @@ const output_1 = require("../../../../utils/output");
9
10
  const lock_file_1 = require("../../lock-file/lock-file");
10
11
  const getTouchedProjectsFromLockFile = (fileChanges, projectGraphNodes, nxJson, packageJson, projectGraph) => {
11
12
  const { projectsAffectedByDependencyUpdates } = (0, config_1.jsPluginConfig)(nxJson);
12
- const changedLockFile = fileChanges.find((f) => lock_file_1.AUTO_AFFECTED_LOCK_FILES.includes(f.file));
13
+ const changedLockFile = findChangedLockFile(fileChanges);
14
+ const allProjectNames = Object.values(projectGraphNodes).map((p) => p.name);
13
15
  if (projectsAffectedByDependencyUpdates === 'auto') {
14
- return getAutoAffected(changedLockFile, projectGraphNodes, projectGraph, packageJson);
16
+ if (!changedLockFile) {
17
+ return [];
18
+ }
19
+ // External node names, which the reverse walk in filterAffected carries
20
+ // back to the projects depending on them.
21
+ return (changedExternalNodes(changedLockFile, projectGraph, packageJson) ??
22
+ allProjectNames);
15
23
  }
16
24
  else if (Array.isArray(projectsAffectedByDependencyUpdates)) {
17
25
  return (0, find_matching_projects_1.findMatchingProjects)(projectsAffectedByDependencyUpdates, projectGraphNodes);
18
26
  }
19
- if (changedLockFile) {
20
- return Object.values(projectGraphNodes).map((p) => p.name);
21
- }
22
- return [];
27
+ return changedLockFile ? allProjectNames : [];
23
28
  };
24
29
  exports.getTouchedProjectsFromLockFile = getTouchedProjectsFromLockFile;
25
30
  /**
26
- * In auto mode, parse the lock file at the base and head revisions
27
- * using Nx's existing lock file parsers, then diff the resulting
28
- * external-node maps to determine which packages actually changed.
29
- *
30
- * Returns external node names (e.g. "npm:lodash@4.17.21") so the
31
- * graph reversal in filterAffected can walk back to workspace projects.
31
+ * The same change as task selection consumes it: the packages that moved,
32
+ * which a plan names as `External`, rather than the projects depending on them.
32
33
  */
33
- function getAutoAffected(changedLockFile, projectGraphNodes, projectGraph, packageJson) {
34
- const allProjectNames = Object.values(projectGraphNodes).map((p) => p.name);
34
+ function lockFileDependencyChanges(fileChanges, projectGraphNodes, nxJson, packageJson, projectGraph) {
35
+ const none = {
36
+ externals: [],
37
+ changedExternalTypes: [],
38
+ projects: [],
39
+ };
40
+ const changedLockFile = findChangedLockFile(fileChanges);
35
41
  if (!changedLockFile) {
36
- return [];
42
+ return none;
43
+ }
44
+ const { projectsAffectedByDependencyUpdates } = (0, config_1.jsPluginConfig)(nxJson);
45
+ if (Array.isArray(projectsAffectedByDependencyUpdates)) {
46
+ return {
47
+ ...none,
48
+ projects: (0, find_matching_projects_1.findMatchingProjects)(projectsAffectedByDependencyUpdates, projectGraphNodes),
49
+ };
37
50
  }
51
+ const externals = projectsAffectedByDependencyUpdates === 'auto'
52
+ ? changedExternalNodes(changedLockFile, projectGraph, packageJson)
53
+ : null;
54
+ return externals
55
+ ? { ...none, externals }
56
+ : { ...none, changedExternalTypes: ['npm'] };
57
+ }
58
+ function findChangedLockFile(fileChanges) {
59
+ return fileChanges.find((f) => lock_file_1.AUTO_AFFECTED_LOCK_FILES.includes(f.file));
60
+ }
61
+ /**
62
+ * Diffs the lock file's base and head revisions with the parsers the project
63
+ * graph is built from, and names the external nodes whose package changed.
64
+ *
65
+ * Null when the diff cannot be pinned to packages: a WholeFileChange (a
66
+ * revision could not be read), a parse failure, or a changed package with no
67
+ * external node in the head graph.
68
+ */
69
+ function changedExternalNodes(changedLockFile, projectGraph, packageJson) {
38
70
  const changes = changedLockFile.getChanges();
39
- // A WholeFileChange means we were unable to read both revisions of
40
- // the lock file (e.g. missing base revision, git error). Fall back
41
- // to marking all projects affected.
42
71
  if (!changes.every(file_utils_1.isLockFileChange)) {
43
- return allProjectNames;
72
+ return null;
44
73
  }
45
74
  const changedPackageNames = getChangedPackageNames(changedLockFile.file, changes, packageJson);
46
75
  if (changedPackageNames === null) {
47
- return allProjectNames;
76
+ return null;
48
77
  }
49
78
  if (changedPackageNames.size === 0) {
50
79
  return [];
51
80
  }
52
- // Look up the changed packages in the project graph's external nodes
53
- // and return the external node names. The graph reversal in
54
- // filterAffected walks from these nodes to workspace projects.
55
81
  const { touchedNodeNames, missingPackageNames } = findExternalNodesByPackageName(changedPackageNames, projectGraph.externalNodes ?? {});
56
- if (missingPackageNames.size > 0) {
57
- return allProjectNames;
58
- }
59
- return touchedNodeNames;
82
+ return missingPackageNames.size > 0 ? null : touchedNodeNames;
60
83
  }
61
84
  /**
62
85
  * Parse the base and head revisions of the lock file with Nx's
63
86
  * existing parsers and diff the resulting package -> version maps.
64
87
  *
65
- * Returns the set of changed package names, or null if parsing
66
- * failed (in which case the caller should fall back to all projects).
88
+ * Returns the set of changed package names, or null if parsing failed.
67
89
  */
68
90
  function getChangedPackageNames(file, changes, packageJson) {
69
91
  try {
@@ -1,4 +1,12 @@
1
- import { WholeFileChange } from '../../../../project-graph/file-utils';
1
+ import { FileChange, WholeFileChange } from '../../../../project-graph/file-utils';
2
2
  import { JsonChange } from '../../../../utils/json-diff';
3
- import { TouchedProjectLocator } from '../../../../project-graph/affected/affected-project-graph-models';
3
+ import { DependencyChanges, TouchedProjectLocator } from '../../../../project-graph/affected/affected-project-graph-models';
4
+ import { ProjectGraph } from '../../../../config/project-graph';
5
+ import { NxJsonConfiguration } from '../../../../config/nx-json';
4
6
  export declare const getTouchedNpmPackages: TouchedProjectLocator<WholeFileChange | JsonChange>;
7
+ /**
8
+ * The same change as task selection consumes it: the packages that moved,
9
+ * which a plan names as `External`, and the workspace projects the root
10
+ * package.json depends on directly.
11
+ */
12
+ export declare function packageJsonDependencyChanges(touchedFiles: FileChange<WholeFileChange | JsonChange>[], nxJson: NxJsonConfiguration, projectGraph: ProjectGraph): DependencyChanges;
@@ -1,11 +1,36 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getTouchedNpmPackages = void 0;
4
+ exports.packageJsonDependencyChanges = packageJsonDependencyChanges;
4
5
  const file_utils_1 = require("../../../../project-graph/file-utils");
5
6
  const json_diff_1 = require("../../../../utils/json-diff");
6
7
  const logger_1 = require("../../../../utils/logger");
7
8
  const get_package_name_from_import_path_1 = require("../../../../utils/get-package-name-from-import-path");
8
- const getTouchedNpmPackages = (touchedFiles, _, nxJson, packageJson, projectGraph) => {
9
+ const getTouchedNpmPackages = (touchedFiles, _nodes, nxJson, _packageJson, projectGraph) => touchedNpmPackages(touchedFiles, nxJson, projectGraph) ??
10
+ Object.keys(projectGraph.nodes);
11
+ exports.getTouchedNpmPackages = getTouchedNpmPackages;
12
+ /**
13
+ * The same change as task selection consumes it: the packages that moved,
14
+ * which a plan names as `External`, and the workspace projects the root
15
+ * package.json depends on directly.
16
+ */
17
+ function packageJsonDependencyChanges(touchedFiles, nxJson, projectGraph) {
18
+ const touched = touchedNpmPackages(touchedFiles, nxJson, projectGraph);
19
+ if (touched === null) {
20
+ return { externals: [], changedExternalTypes: ['npm'], projects: [] };
21
+ }
22
+ return {
23
+ externals: touched.filter((name) => name in projectGraph.externalNodes),
24
+ changedExternalTypes: [],
25
+ projects: touched.filter((name) => name in projectGraph.nodes),
26
+ };
27
+ }
28
+ /**
29
+ * External nodes and workspace projects the root package.json change names,
30
+ * or null when it cannot be pinned to them: a removed dependency, a global
31
+ * package, or an override selector matching nothing in the graph.
32
+ */
33
+ function touchedNpmPackages(touchedFiles, nxJson, projectGraph) {
9
34
  const packageJsonChange = touchedFiles.find((f) => f.file === 'package.json');
10
35
  if (!packageJsonChange)
11
36
  return [];
@@ -19,10 +44,8 @@ const getTouchedNpmPackages = (touchedFiles, _, nxJson, packageJson, projectGrap
19
44
  if ((0, json_diff_1.isJsonChange)(c) &&
20
45
  (c.path[0] === 'dependencies' || c.path[0] === 'devDependencies') &&
21
46
  c.path.length === 2) {
22
- // A package was deleted so mark all workspace projects as touched.
23
47
  if (c.type === json_diff_1.JsonDiffType.Deleted) {
24
- touched = Object.keys(projectGraph.nodes);
25
- break;
48
+ return null;
26
49
  }
27
50
  else {
28
51
  let npmPackage = npmPackages.find((pkg) => pkg.data.packageName === c.path[1]);
@@ -45,7 +68,7 @@ const getTouchedNpmPackages = (touchedFiles, _, nxJson, packageJson, projectGrap
45
68
  }
46
69
  if ('packageName' in npmPackage.data) {
47
70
  if (globalPackages.has(npmPackage.data.packageName)) {
48
- return Object.keys(projectGraph.nodes);
71
+ return null;
49
72
  }
50
73
  }
51
74
  }
@@ -59,13 +82,12 @@ const getTouchedNpmPackages = (touchedFiles, _, nxJson, packageJson, projectGrap
59
82
  continue;
60
83
  packagesByName ??= groupPackagesByName(npmPackages);
61
84
  const matchingNpmPackages = findPackagesForSelector(packageSelector, packagesByName, c.path[0] === 'pnpm');
62
- // An unresolved selector can still target a transitive dependency,
63
- // so fall back to marking every project affected.
85
+ // An unresolved selector can still target a transitive dependency.
64
86
  if (!matchingNpmPackages.length) {
65
- return Object.keys(projectGraph.nodes);
87
+ return null;
66
88
  }
67
89
  if (matchingNpmPackages.some((pkg) => globalPackages.has(pkg.data.packageName))) {
68
- return Object.keys(projectGraph.nodes);
90
+ return null;
69
91
  }
70
92
  touched.push(...matchingNpmPackages.map((pkg) => pkg.name));
71
93
  }
@@ -79,8 +101,7 @@ const getTouchedNpmPackages = (touchedFiles, _, nxJson, packageJson, projectGrap
79
101
  logger_1.logger.warn(`The affected projects might have not been identified properly. The package(s) ${missingTouchedNpmPackages.join(', ')} were not found. Please open an issue in GitHub including the package.json file.`);
80
102
  }
81
103
  return [...new Set(touched)];
82
- };
83
- exports.getTouchedNpmPackages = getTouchedNpmPackages;
104
+ }
84
105
  function getPackageSelector(change) {
85
106
  if (typeof change.value.lhs !== 'string' &&
86
107
  typeof change.value.rhs !== 'string') {
@@ -3,7 +3,7 @@ import type { ProjectConfiguration } from '../../config/workspace-json-project-j
3
3
  import { PackageJson } from '../../utils/package-json';
4
4
  import { PackageManagerCommands } from '../../utils/package-manager';
5
5
  import { CreateNodes } from '../../project-graph/plugins';
6
- import { PackageJsonConfigurationCache } from '../../../plugins/package-json';
6
+ import type { PackageJsonConfigurationCache } from '../../../plugins/package-json';
7
7
  export declare const createNodes: CreateNodes;
8
8
  export declare function buildPackageJsonPatterns(workspaceRoot: string, readJson: (path: string) => any): PackageJsonPatterns;
9
9
  type PackageJsonPatterns = {
@@ -13,7 +13,7 @@ type PackageJsonPatterns = {
13
13
  negativeLookup: Record<string, boolean>;
14
14
  };
15
15
  export declare function buildPackageJsonWorkspacesMatcher(patterns: PackageJsonPatterns): (p: any) => boolean;
16
- export declare function createNodeFromPackageJson(pkgJsonPath: string, workspaceRoot: string, cache: PackageJsonConfigurationCache, isInPackageManagerWorkspaces: boolean, packageManagerCommand: PackageManagerCommands): {
16
+ export declare function createNodeFromPackageJson(pkgJsonPath: string, workspaceRoot: string, cache: PackageJsonConfigurationCache | undefined, isInPackageManagerWorkspaces: boolean, packageManagerCommand: PackageManagerCommands, nxJson?: NxJsonConfiguration): {
17
17
  projects: {
18
18
  [x: string]: ProjectConfiguration;
19
19
  };
@@ -22,7 +22,6 @@ const versions_1 = require("../../utils/versions");
22
22
  const plugins_1 = require("../../project-graph/plugins");
23
23
  const path_2 = require("path");
24
24
  const file_hasher_1 = require("../../hasher/file-hasher");
25
- const package_json_2 = require("../../../plugins/package-json");
26
25
  const globPatterns = (0, globs_1.combineGlobPatterns)('package.json', '**/package.json', 'project.json', '**/project.json');
27
26
  exports.createNodes = [
28
27
  globPatterns,
@@ -38,7 +37,6 @@ exports.createNodes = [
38
37
  const isNextToProjectJson = (packageJsonPath) => {
39
38
  return projectJsonRoots.has((0, node_path_1.dirname)(packageJsonPath));
40
39
  };
41
- const cache = (0, package_json_2.readPackageJsonConfigurationCache)();
42
40
  const packageManagerCommand = (0, package_manager_1.getPackageManagerCommand)((0, package_manager_1.detectPackageManager)(context.workspaceRoot), context.workspaceRoot);
43
41
  return (0, plugins_1.createNodesFromFiles)((packageJsonPath, options, context) => {
44
42
  const isInPackageManagerWorkspaces = isInPackageJsonWorkspaces(packageJsonPath);
@@ -47,7 +45,7 @@ exports.createNodes = [
47
45
  // Skip if package.json is not part of the package.json workspaces and not next to a project.json.
48
46
  return null;
49
47
  }
50
- return createNodeFromPackageJson(packageJsonPath, context.workspaceRoot, cache, isInPackageManagerWorkspaces, packageManagerCommand);
48
+ return createNodeFromPackageJson(packageJsonPath, context.workspaceRoot, undefined, isInPackageManagerWorkspaces, packageManagerCommand, context.nxJsonConfiguration);
51
49
  }, packageJsons, _, context);
52
50
  },
53
51
  ];
@@ -115,16 +113,18 @@ function buildPackageJsonWorkspacesMatcher(patterns) {
115
113
  !patterns.negativeLookup[p] &&
116
114
  negative.every((m) => m.match(p));
117
115
  }
118
- function createNodeFromPackageJson(pkgJsonPath, workspaceRoot, cache, isInPackageManagerWorkspaces, packageManagerCommand) {
116
+ function createNodeFromPackageJson(pkgJsonPath, workspaceRoot, cache, isInPackageManagerWorkspaces, packageManagerCommand, nxJson) {
119
117
  const json = (0, fileutils_1.readJsonFile)((0, node_path_1.join)(workspaceRoot, pkgJsonPath));
120
118
  const projectRoot = (0, node_path_1.dirname)(pkgJsonPath);
121
- const hash = (0, file_hasher_1.hashObject)({
122
- ...json,
123
- root: projectRoot,
124
- isInPackageManagerWorkspaces,
125
- nxVersion: versions_1.nxVersion,
126
- });
127
- const cached = cache.get(hash);
119
+ const hash = cache
120
+ ? (0, file_hasher_1.hashObject)({
121
+ ...json,
122
+ root: projectRoot,
123
+ isInPackageManagerWorkspaces,
124
+ nxVersion: versions_1.nxVersion,
125
+ })
126
+ : undefined;
127
+ const cached = cache?.get(hash);
128
128
  if (cached) {
129
129
  return {
130
130
  projects: {
@@ -132,8 +132,8 @@ function createNodeFromPackageJson(pkgJsonPath, workspaceRoot, cache, isInPackag
132
132
  },
133
133
  };
134
134
  }
135
- const project = buildProjectConfigurationFromPackageJson(json, workspaceRoot, pkgJsonPath, (0, nx_json_1.readNxJson)(workspaceRoot), isInPackageManagerWorkspaces, packageManagerCommand);
136
- cache.set(hash, project);
135
+ const project = buildProjectConfigurationFromPackageJson(json, workspaceRoot, pkgJsonPath, nxJson ?? (0, nx_json_1.readNxJson)(workspaceRoot), isInPackageManagerWorkspaces, packageManagerCommand);
136
+ cache?.set(hash, project);
137
137
  return {
138
138
  projects: {
139
139
  [project.root]: project,
@@ -6,6 +6,20 @@ export interface AffectedProjectGraphContext {
6
6
  nxJson: NxJsonConfiguration<any>;
7
7
  touchedProjects: string[];
8
8
  }
9
+ /**
10
+ * What a lockfile or package.json change moved, before it is projected onto
11
+ * projects (the reverse walk) or tasks (matched against each plan's externals).
12
+ */
13
+ export interface DependencyChanges {
14
+ /** External node names whose version or integrity moved. */
15
+ externals: string[];
16
+ /** Ecosystems whose manifest changed without the change being pinnable to
17
+ * packages, so every node of that type counts as moved. A locator names the
18
+ * ecosystem it reads, since a change to one cannot move another's nodes. */
19
+ changedExternalTypes: string[];
20
+ /** Workspace projects the change names outright. */
21
+ projects: string[];
22
+ }
9
23
  export interface TouchedProjectLocator<T extends Change = Change> {
10
24
  (fileChanges: FileChange<T>[], projectGraphNodes?: Record<string, ProjectGraphProjectNode>, nxJson?: NxJsonConfiguration<any>, packageJson?: any, projectGraph?: ProjectGraph, projectDeletionAffectsAllProjects?: boolean): string[] | Promise<string[]>;
11
25
  }
@@ -2,27 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.filterAffected = filterAffected;
4
4
  const file_utils_1 = require("../file-utils");
5
- const workspace_projects_1 = require("./locators/workspace-projects");
6
- const touched_projects_1 = require("../../plugins/js/project-graph/affected/touched-projects");
7
5
  const operators_1 = require("../operators");
8
6
  const configuration_1 = require("../../config/configuration");
9
- const project_glob_changes_1 = require("./locators/project-glob-changes");
7
+ const affected_projects_1 = require("./affected-projects");
10
8
  async function filterAffected(graph, touchedFiles, nxJson = (0, configuration_1.readNxJson)(), packageJson = (0, file_utils_1.readPackageJson)(), projectDeletionAffectsAllProjects = true) {
11
- // Additional affected logic should be in this array.
12
- const touchedProjectLocators = [
13
- workspace_projects_1.getTouchedProjects,
14
- workspace_projects_1.getImplicitlyTouchedProjects,
15
- project_glob_changes_1.getTouchedProjectsFromProjectGlobChanges,
16
- touched_projects_1.getTouchedProjects,
17
- ];
18
- const touchedProjects = [];
19
- for (const locator of touchedProjectLocators) {
20
- performance.mark(locator.name + ':start');
21
- const projects = await locator(touchedFiles, graph.nodes, nxJson, packageJson, graph, projectDeletionAffectsAllProjects);
22
- performance.mark(locator.name + ':end');
23
- performance.measure(locator.name, locator.name + ':start', locator.name + ':end');
24
- touchedProjects.push(...projects);
25
- }
9
+ performance.mark('locateTouchedProjects:start');
10
+ const touchedProjects = await (0, affected_projects_1.runTouchedProjectLocators)(graph, touchedFiles, nxJson, packageJson, projectDeletionAffectsAllProjects);
11
+ performance.mark('locateTouchedProjects:end');
12
+ performance.measure('locateTouchedProjects', 'locateTouchedProjects:start', 'locateTouchedProjects:end');
26
13
  return filterAffectedProjects(graph, {
27
14
  projectGraphNodes: graph.nodes,
28
15
  nxJson,
@@ -0,0 +1,7 @@
1
+ import { NxJsonConfiguration } from '../../config/nx-json';
2
+ import { ProjectGraph } from '../../config/project-graph';
3
+ import { FileChange } from '../file-utils';
4
+ /** Runs every locator and returns what each one marked, duplicates included. */
5
+ export declare function runTouchedProjectLocators(graph: ProjectGraph, touchedFiles: FileChange[], nxJson: NxJsonConfiguration, packageJson?: any, projectDeletionAffectsAllProjects?: boolean): Promise<string[]>;
6
+ /** Resolved here because the native side takes the patterns, not the plugins. */
7
+ export declare function getProjectGlobPatterns(nxJson: NxJsonConfiguration): Promise<string[]>;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runTouchedProjectLocators = runTouchedProjectLocators;
4
+ exports.getProjectGlobPatterns = getProjectGlobPatterns;
5
+ const native_1 = require("../../native");
6
+ const get_plugins_1 = require("../plugins/get-plugins");
7
+ const workspace_root_1 = require("../../utils/workspace-root");
8
+ const file_utils_1 = require("../file-utils");
9
+ const touched_projects_1 = require("../../plugins/js/project-graph/affected/touched-projects");
10
+ const transform_objects_1 = require("../../native/transform-objects");
11
+ /** Runs every locator and returns what each one marked, duplicates included. */
12
+ async function runTouchedProjectLocators(graph, touchedFiles, nxJson, packageJson, projectDeletionAffectsAllProjects = true) {
13
+ return (0, native_1.locateTouchedProjects)((0, transform_objects_1.transformProjectGraphForLocators)(graph), nxJson, touchedFiles.map((f) => f.file), {
14
+ // Only a deletion reaches projects_from_project_glob_changes, and
15
+ // resolving the patterns can fall back to starting plugin workers.
16
+ projectGlobPatterns: touchedFiles.some((f) => (0, file_utils_1.isDeletedFile)(f.file))
17
+ ? await getProjectGlobPatterns(nxJson)
18
+ : [],
19
+ projectDeletionAffectsAllProjects,
20
+ workspaceRoot: workspace_root_1.workspaceRoot,
21
+ },
22
+ // Takes only paths, so the closure carries the FileChange objects: their
23
+ // lazy getChanges() cannot cross the native boundary.
24
+ [
25
+ async () => (0, touched_projects_1.getTouchedProjects)(touchedFiles, graph.nodes, nxJson, packageJson, graph, projectDeletionAffectsAllProjects),
26
+ ]);
27
+ }
28
+ /** Resolved here because the native side takes the patterns, not the plugins. */
29
+ async function getProjectGlobPatterns(nxJson) {
30
+ if (process.env.NX_FORCE_REUSE_CACHED_GRAPH === 'true') {
31
+ return [
32
+ '**/package.json',
33
+ '**/project.json',
34
+ 'project.json',
35
+ 'package.json',
36
+ ];
37
+ }
38
+ const capabilities = await (0, get_plugins_1.capabilitiesOfConfiguredPlugins)(nxJson, workspace_root_1.workspaceRoot);
39
+ return capabilities
40
+ .map((capability) => capability.createNodesPattern)
41
+ .filter((pattern) => !!pattern);
42
+ }
@@ -0,0 +1,90 @@
1
+ import { NxJsonConfiguration, TargetDependencies } from '../../config/nx-json';
2
+ import { ProjectGraph } from '../../config/project-graph';
3
+ import { TaskGraph } from '../../config/task-graph';
4
+ import { type IoSnapshots } from '../../native';
5
+ import { type IoSnapshotOutcome } from '../../io-snapshots/store';
6
+ import type { IoSnapshotVersion } from '../../daemon/message-types/io-snapshot-version';
7
+ import { FileChange } from '../file-utils';
8
+ import type { NxArgs } from '../../utils/command-line-utils';
9
+ import { TaskPlanningContext } from '../../hasher/task-planning-context';
10
+ import type { TaskSelection } from '../../tasks-runner/run-command';
11
+ /**
12
+ * Whether `nx affected` selects the individual tasks whose inputs a change
13
+ * reaches, rather than whole projects. Off by default while the task path
14
+ * settles.
15
+ *
16
+ * Env-var only, so `nx show projects --affected` and `nx affected` in one CI
17
+ * script agree. The run also executes the selected tasks' dependencies.
18
+ */
19
+ export declare function selectsAffectedTasks(): boolean;
20
+ export interface AffectedTasksResult {
21
+ /** The graph selection ran against, which the command should run with too. */
22
+ projectGraph: ProjectGraph;
23
+ /** Tasks that are themselves affected — NOT their dependency closure. */
24
+ affectedTaskIds: Set<string>;
25
+ /** The full, unpruned graph the answer was computed over. */
26
+ taskGraph: TaskGraph;
27
+ /** What the run executes: the affected tasks and what they depend on. */
28
+ taskSelection: TaskSelection;
29
+ }
30
+ export interface ComputeAffectedTasksOptions {
31
+ /** Fetched when absent. Unused when the daemon selects; it returns its own graph. */
32
+ projectGraph?: ProjectGraph;
33
+ nxJson: NxJsonConfiguration;
34
+ targets: string[];
35
+ touchedFiles: FileChange[];
36
+ /** What `touchedFiles` was computed from, so the daemon reads the same diff. */
37
+ fileChangeArgs?: FileChangeArgs;
38
+ configuration?: string;
39
+ overrides?: Record<string, unknown>;
40
+ extraTargetDependencies?: TargetDependencies;
41
+ excludeTaskDependencies?: boolean;
42
+ /** `--exclude` project patterns. Their tasks leave the selection but still carry a change and run as dependencies. */
43
+ exclude?: string[];
44
+ packageJson?: any;
45
+ /** This command's I/O snapshot set. Selection plans with it, as the run hashes with it. */
46
+ ioSnapshotOutcome?: IoSnapshotOutcome | null;
47
+ selectivelyHashTsConfig?: boolean;
48
+ }
49
+ export type FileChangeArgs = Pick<NxArgs, 'base' | 'head' | 'files'>;
50
+ /**
51
+ * What selection needs from the command, reduced to plain data so the daemon
52
+ * can run it. Anything read against the project graph, like `--exclude` and the
53
+ * lockfile diff, is resolved by whichever process selects.
54
+ */
55
+ export interface AffectedTasksRequest {
56
+ targets: string[];
57
+ changedFiles: string[];
58
+ fileChangeArgs?: FileChangeArgs;
59
+ configuration?: string;
60
+ overrides: Record<string, unknown>;
61
+ extraTargetDependencies: TargetDependencies;
62
+ excludeTaskDependencies: boolean;
63
+ exclude: string[];
64
+ ioSnapshots?: IoSnapshotVersion;
65
+ /** The runner's `selectivelyHashTsConfig`, which decides what the tsconfig hash reads. */
66
+ selectivelyHashTsConfig?: boolean;
67
+ }
68
+ /**
69
+ * Selects the tasks a change reaches, rather than the projects that own a
70
+ * changed file.
71
+ *
72
+ * With the daemon on, the daemon selects: it hashes the run's tasks, so its
73
+ * planner is the one that remembers the plans. It returns the graph it selected
74
+ * against, which the command must run with.
75
+ */
76
+ export declare function computeAffectedTasks(opts: ComputeAffectedTasksOptions): Promise<AffectedTasksResult>;
77
+ /**
78
+ * Plans the targets' full task graph and matches the changed paths against
79
+ * every plan. No project-level prefilter: under an I/O snapshot a task can read
80
+ * files no affected project owns. Shared by the client and the daemon.
81
+ */
82
+ export declare function selectAffectedTasks(projectGraph: ProjectGraph, nxJson: NxJsonConfiguration, planningContext: TaskPlanningContext, request: AffectedTasksRequest, { touchedFiles, packageJson, ioSnapshots, }?: {
83
+ touchedFiles?: FileChange[];
84
+ packageJson?: any;
85
+ ioSnapshots?: IoSnapshots;
86
+ }): Promise<{
87
+ affectedTaskIds: Set<string>;
88
+ taskGraph: TaskGraph;
89
+ taskSelection: TaskSelection;
90
+ }>;