nx 23.2.0-beta.0 → 23.2.0-beta.2

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 (59) hide show
  1. package/dist/bin/nx.js +1 -1
  2. package/dist/src/analytics/analytics.d.ts +6 -0
  3. package/dist/src/analytics/analytics.js +7 -1
  4. package/dist/src/analytics/index.d.ts +1 -1
  5. package/dist/src/analytics/index.js +2 -1
  6. package/dist/src/command-line/init/ai-agent-prompts.d.ts +1 -1
  7. package/dist/src/command-line/init/ai-agent-prompts.js +7 -6
  8. package/dist/src/command-line/init/command-object.js +10 -2
  9. package/dist/src/command-line/init/implementation/angular/integrated-workspace.js +2 -5
  10. package/dist/src/command-line/init/implementation/angular/legacy-angular-versions.js +3 -0
  11. package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +4 -1
  12. package/dist/src/command-line/migrate/execute-migration.d.ts +72 -0
  13. package/dist/src/command-line/migrate/execute-migration.js +389 -0
  14. package/dist/src/command-line/migrate/migrate-ui-api.js +17 -12
  15. package/dist/src/command-line/migrate/migrate.d.ts +1 -45
  16. package/dist/src/command-line/migrate/migrate.js +17 -375
  17. package/dist/src/command-line/nx-cloud/connect/view-logs.js +2 -0
  18. package/dist/src/command-line/release/utils/release-graph.d.ts +2 -2
  19. package/dist/src/command-line/release/utils/shared.d.ts +2 -2
  20. package/dist/src/command-line/show/show-target/inputs.js +50 -153
  21. package/dist/src/command-line/show/show-target/outputs.js +48 -173
  22. package/dist/src/command-line/show/show-target/utils.d.ts +28 -0
  23. package/dist/src/command-line/show/show-target/utils.js +83 -3
  24. package/dist/src/command-line/yargs-utils/shared-options.d.ts +1 -1
  25. package/dist/src/commands-runner/create-command-graph.js +5 -0
  26. package/dist/src/config/nx-json.d.ts +1 -1
  27. package/dist/src/core/graph/main.js +1 -1
  28. package/dist/src/daemon/server/handle-tasks-execution-hooks.d.ts +1 -1
  29. package/dist/src/daemon/server/server.js +7 -4
  30. package/dist/src/devkit-internals.d.ts +1 -0
  31. package/dist/src/devkit-internals.js +5 -2
  32. package/dist/src/generators/utils/nx-json.js +13 -3
  33. package/dist/src/hasher/check-task-files.d.ts +86 -0
  34. package/dist/src/hasher/check-task-files.js +378 -0
  35. package/dist/src/native/index.d.ts +25 -2
  36. package/dist/src/native/native-bindings.js +2 -0
  37. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  38. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  39. package/dist/src/plugins/js/lock-file/utils/pnpm-normalizer.js +3 -0
  40. package/dist/src/project-graph/build-project-graph.js +7 -1
  41. package/dist/src/project-graph/file-utils.js +6 -1
  42. package/dist/src/project-graph/plugins/loaded-nx-plugin.js +1 -0
  43. package/dist/src/project-graph/project-graph.js +3 -0
  44. package/dist/src/tasks-runner/life-cycle.d.ts +2 -2
  45. package/dist/src/tasks-runner/life-cycle.js +2 -2
  46. package/dist/src/tasks-runner/life-cycles/performance-analysis.d.ts +9 -4
  47. package/dist/src/tasks-runner/life-cycles/performance-life-cycle.js +5 -4
  48. package/dist/src/tasks-runner/life-cycles/performance-report.d.ts +16 -8
  49. package/dist/src/tasks-runner/life-cycles/performance-report.js +55 -27
  50. package/dist/src/tasks-runner/pseudo-terminal.d.ts +1 -1
  51. package/dist/src/tasks-runner/pseudo-terminal.js +2 -2
  52. package/dist/src/tasks-runner/task-orchestrator.d.ts +4 -1
  53. package/dist/src/tasks-runner/task-orchestrator.js +23 -6
  54. package/dist/src/utils/acknowledge-build-scripts.js +7 -5
  55. package/dist/src/utils/command-line-utils.js +30 -20
  56. package/dist/src/utils/git-revision.d.ts +12 -0
  57. package/dist/src/utils/git-revision.js +25 -0
  58. package/dist/src/utils/package-manager.js +6 -2
  59. package/package.json +11 -11
@@ -1,185 +1,82 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.showTargetInputsHandler = showTargetInputsHandler;
4
- const workspace_root_1 = require("../../../utils/workspace-root");
5
- const handle_import_1 = require("../../../utils/handle-import");
6
- const utils_1 = require("./utils");
4
+ const check_task_files_1 = require("../../../hasher/check-task-files");
5
+ const utils_1 = require("../../../tasks-runner/utils");
6
+ const utils_2 = require("./utils");
7
7
  // ── Handler ─────────────────────────────────────────────────────────
8
8
  async function showTargetInputsHandler(args) {
9
- const t = await (0, utils_1.resolveTarget)(args);
10
- const usesCustomHasher = (0, utils_1.hasCustomHasher)(t.projectName, t.targetName, t.graph);
11
- if (usesCustomHasher) {
12
- renderCustomHasherWarning(t.projectName, t.targetName, args);
9
+ const t = await (0, utils_2.resolveTarget)(args);
10
+ const { projectName, targetName, configuration } = t;
11
+ if ((0, utils_2.hasCustomHasher)(projectName, targetName, t.graph)) {
12
+ renderCustomHasherWarning(projectName, targetName, args);
13
13
  process.exitCode = 1;
14
14
  return;
15
15
  }
16
- const hashInputs = await resolveInputFiles(t);
16
+ const taskId = (0, utils_1.createTaskId)(projectName, targetName, configuration);
17
+ const hashInputs = await (0, check_task_files_1.getTaskRawInputs)(taskId, {
18
+ projectGraph: t.graph,
19
+ nxJson: t.nxJson,
20
+ });
21
+ if (!hashInputs) {
22
+ throw new Error(`Could not find hash plan for task "${taskId}".`);
23
+ }
17
24
  if (args.check !== undefined) {
18
- const checkItems = (0, utils_1.deduplicateFolderEntries)(args.check);
19
- const results = checkItems.map((input) => resolveCheckFromInputs(input, t.projectName, t.targetName, hashInputs));
20
- if (results.length >= 2) {
21
- renderBatchCheckInputs(results, t.projectName, t.targetName);
22
- }
23
- else {
24
- for (const data of results)
25
- renderCheckInput(data);
26
- }
27
- for (const data of results) {
28
- process.exitCode ||=
29
- data.isInput || data.containedInputFiles.length ? 0 : 1;
30
- }
25
+ const results = await checkInputs(taskId, args.check, hashInputs);
26
+ (0, utils_2.renderCheckResults)(results, projectName, targetName, 'input');
27
+ (0, utils_2.setCheckExitCode)(results);
31
28
  return;
32
29
  }
33
- renderInputs({ project: t.projectName, target: t.targetName, ...hashInputs }, t.node.data.targets[t.targetName].inputs, args);
30
+ renderInputs({ project: projectName, target: targetName, ...hashInputs }, t.node.data.targets[targetName].inputs, args);
34
31
  }
35
- async function resolveInputFiles(t) {
36
- const { projectName, targetName, configuration, graph, nxJson } = t;
37
- const { HashPlanInspector } = (await (0, handle_import_1.handleImport)('../../../hasher/hash-plan-inspector.js', __dirname));
38
- const inspector = new HashPlanInspector(graph, workspace_root_1.workspaceRoot, nxJson);
39
- await inspector.init();
40
- const plan = inspector.inspectTaskInputs({
41
- project: projectName,
42
- target: targetName,
43
- configuration,
32
+ // ── Data resolution ─────────────────────────────────────────────────
33
+ async function checkInputs(taskId, check, hashInputs) {
34
+ // checkFilesAreInputs matches environment/runtime/external names against the
35
+ // raw argument and paths against the workspace-relative form, so both are
36
+ // passed through — it has no cwd of its own.
37
+ const candidates = (0, utils_2.deduplicateFolderEntries)(check).map((value) => ({
38
+ value,
39
+ path: (0, utils_2.normalizePath)(value),
40
+ }));
41
+ const { categories } = await (0, check_task_files_1.checkFilesAreInputs)(taskId, candidates);
42
+ return candidates.map(({ value, path }) => {
43
+ const category = categories.get(value);
44
+ return {
45
+ value,
46
+ file: path,
47
+ matched: !!category,
48
+ category,
49
+ contained: category ? [] : (0, utils_2.pathsUnder)(path, hashInputs.files),
50
+ };
44
51
  });
45
- const targetConfig = graph.nodes[projectName]?.data?.targets?.[targetName];
46
- const effectiveConfig = configuration ?? targetConfig?.defaultConfiguration;
47
- const taskId = effectiveConfig
48
- ? `${projectName}:${targetName}:${effectiveConfig}`
49
- : `${projectName}:${targetName}`;
50
- const result = plan[taskId];
51
- if (!result) {
52
- throw new Error(`Could not find hash plan for task "${taskId}". Available tasks: ${Object.keys(plan).join(', ')}`);
53
- }
54
- return result;
55
- }
56
- function resolveCheckFromInputs(rawValue, projectName, targetName, inputs) {
57
- for (const [category, arr] of [
58
- ['environment', inputs.environment],
59
- ['runtime', inputs.runtime],
60
- ['external', inputs.external],
61
- ['depOutputs', inputs.depOutputs],
62
- ]) {
63
- if (arr.includes(rawValue)) {
64
- return {
65
- value: rawValue,
66
- file: rawValue,
67
- project: projectName,
68
- target: targetName,
69
- isInput: true,
70
- matchedCategory: category,
71
- containedInputFiles: [],
72
- };
73
- }
74
- }
75
- const fileToCheck = (0, utils_1.normalizePath)(rawValue);
76
- const isFile = inputs.files.includes(fileToCheck);
77
- let containedInputFiles = [];
78
- if (!isFile) {
79
- if (fileToCheck === '') {
80
- containedInputFiles = inputs.files;
81
- }
82
- else {
83
- const dirPrefix = fileToCheck.endsWith('/')
84
- ? fileToCheck
85
- : fileToCheck + '/';
86
- containedInputFiles = inputs.files.filter((f) => f.startsWith(dirPrefix));
87
- }
88
- }
89
- return {
90
- value: rawValue,
91
- file: fileToCheck,
92
- project: projectName,
93
- target: targetName,
94
- isInput: isFile,
95
- matchedCategory: isFile || containedInputFiles.length > 0
96
- ? 'files'
97
- : null,
98
- containedInputFiles,
99
- };
100
52
  }
101
53
  // ── Render ──────────────────────────────────────────────────────────
102
54
  function renderInputs(data, configuredInputs, args) {
103
55
  if (args.json) {
104
- const jsonData = data;
105
- const result = {};
106
- for (const [k, v] of Object.entries(jsonData)) {
107
- if (Array.isArray(v) && v.length === 0)
108
- continue;
109
- result[k] = v;
110
- }
111
- console.log(JSON.stringify(result, null, 2));
56
+ (0, utils_2.printJson)(data);
112
57
  return;
113
58
  }
114
- const c = (0, utils_1.pc)();
59
+ const c = (0, utils_2.pc)();
115
60
  console.log(`${c.bold('Inputs for')} ${c.cyan(data.project)}:${c.green(data.target)}`);
116
- if (configuredInputs && configuredInputs.length > 0) {
117
- (0, utils_1.printList)('Configured inputs', configuredInputs.map((i) => typeof i === 'string' ? i : JSON.stringify(i)));
118
- }
119
- (0, utils_1.printList)('External dependencies', [...data.external].sort());
120
- (0, utils_1.printList)('Runtime inputs', [...data.runtime].sort());
121
- (0, utils_1.printList)('Environment variables', [...data.environment].sort());
122
- (0, utils_1.printList)(`Files (${data.files.length})`, [...data.files, ...data.depOutputs].sort());
123
- }
124
- function renderCheckInput(data) {
125
- const c = (0, utils_1.pc)();
126
- const categoryLabel = data.matchedCategory
127
- ? ` (${data.matchedCategory})`
128
- : '';
129
- if (data.isInput) {
130
- console.log(`${c.green('✓')} ${c.bold(data.value)} is an input for ${c.cyan(data.project)}:${c.green(data.target)}${categoryLabel}`);
131
- }
132
- else if (data.containedInputFiles.length > 0) {
133
- console.log(`${c.yellow('~')} ${c.bold(data.file)} is a directory containing ${c.bold(String(data.containedInputFiles.length))} input file(s) for ${c.cyan(data.project)}:${c.green(data.target)}`);
134
- for (const f of [...data.containedInputFiles].sort())
135
- console.log(` ${f}`);
136
- }
137
- else {
138
- console.log(`${c.red('✗')} ${c.bold(data.value)} is ${c.red('not')} an input for ${c.cyan(data.project)}:${c.green(data.target)}`);
139
- }
140
- }
141
- function renderBatchCheckInputs(results, projectName, targetName) {
142
- const c = (0, utils_1.pc)();
143
- const label = `${c.cyan(projectName)}:${c.green(targetName)}`;
144
- const matched = [];
145
- const directories = [];
146
- const unmatched = [];
147
- for (const r of results) {
148
- if (r.isInput) {
149
- matched.push(r.value);
150
- }
151
- else if (r.containedInputFiles.length > 0) {
152
- directories.push({ value: r.file, count: r.containedInputFiles.length });
153
- }
154
- else {
155
- unmatched.push(r.value);
156
- }
157
- }
158
- if (matched.length > 0 || directories.length > 0) {
159
- console.log(`\n${c.green('✓')} These arguments were inputs for ${label}:`);
160
- for (const v of matched)
161
- console.log(` ${v}`);
162
- for (const d of directories) {
163
- console.log(` ${d.value} (directory containing ${d.count} input files)`);
164
- }
165
- }
166
- if (unmatched.length > 0) {
167
- console.log(`\n${c.red('✗')} These arguments were ${c.red('not')} inputs for ${label}:`);
168
- for (const v of unmatched)
169
- console.log(` ${v}`);
61
+ if (configuredInputs?.length) {
62
+ (0, utils_2.printList)('Configured inputs', configuredInputs.map((i) => typeof i === 'string' ? i : JSON.stringify(i)));
170
63
  }
64
+ (0, utils_2.printList)('External dependencies', [...data.external].sort());
65
+ (0, utils_2.printList)('Runtime inputs', [...data.runtime].sort());
66
+ (0, utils_2.printList)('Environment variables', [...data.environment].sort());
67
+ (0, utils_2.printList)(`Files (${data.files.length})`, [...data.files, ...data.depOutputs].sort());
171
68
  }
172
69
  function renderCustomHasherWarning(projectName, targetName, args) {
173
- const c = (0, utils_1.pc)();
174
- const label = `${c.cyan(projectName)}:${c.green(targetName)}`;
70
+ const c = (0, utils_2.pc)();
175
71
  if (args.json) {
176
- console.log(JSON.stringify({
72
+ (0, utils_2.printJson)({
177
73
  project: projectName,
178
74
  target: targetName,
179
75
  warning: 'This target uses a custom hasher. Configured inputs do not affect the cache hash.',
180
- }, null, 2));
76
+ });
181
77
  return;
182
78
  }
79
+ const label = `${c.cyan(projectName)}:${c.green(targetName)}`;
183
80
  console.log(`\n${c.yellow('⚠')} ${label} uses a ${c.yellow('custom hasher')}.`);
184
81
  console.log(` Configured inputs do not affect the cache hash for this target.`);
185
82
  console.log(` The executor's hasher determines what is included in the hash.`);
@@ -1,195 +1,70 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.showTargetOutputsHandler = showTargetOutputsHandler;
4
+ const check_task_files_1 = require("../../../hasher/check-task-files");
4
5
  const utils_1 = require("../../../tasks-runner/utils");
5
- const workspace_root_1 = require("../../../utils/workspace-root");
6
6
  const utils_2 = require("./utils");
7
7
  // ── Handler ─────────────────────────────────────────────────────────
8
8
  async function showTargetOutputsHandler(args) {
9
9
  const t = await (0, utils_2.resolveTarget)(args);
10
- const outputsData = resolveOutputsData(t);
10
+ const { projectName, targetName, configuration } = t;
11
+ const taskId = (0, utils_1.createTaskId)(projectName, targetName, configuration);
12
+ const outputs = await (0, check_task_files_1.getTaskOutputs)(taskId, {
13
+ projectGraph: t.graph,
14
+ nxJson: t.nxJson,
15
+ });
11
16
  if (args.check !== undefined) {
12
- const checkItems = (0, utils_2.deduplicateFolderEntries)(args.check);
13
- const results = checkItems.map((o) => resolveCheckOutputData(o, outputsData));
14
- if (results.length >= 2) {
15
- renderBatchCheckOutputs(results, outputsData.project, outputsData.target);
16
- }
17
- else {
18
- for (const data of results)
19
- renderCheckOutput(data);
20
- }
21
- for (const data of results) {
22
- process.exitCode ||=
23
- data.matchedOutput ||
24
- data.containedOutputPaths.length ||
25
- data.containedExpandedOutputs.length
26
- ? 0
27
- : 1;
28
- }
17
+ const results = await checkOutputs(taskId, args.check, outputs);
18
+ (0, utils_2.renderCheckResults)(results, projectName, targetName, 'output');
19
+ (0, utils_2.setCheckExitCode)(results);
29
20
  return;
30
21
  }
31
- renderOutputs(outputsData, args);
22
+ renderOutputs(projectName, targetName, outputs, args);
32
23
  }
33
- function resolveOutputsData(t) {
34
- const { projectName, targetName, configuration, node } = t;
35
- const resolvedOutputs = (0, utils_1.getOutputsForTargetAndConfiguration)({ project: projectName, target: targetName, configuration }, {}, node);
36
- const targetConfig = node.data.targets?.[targetName];
37
- const configuredOutputs = targetConfig?.outputs ?? [];
38
- const mergedOptions = {
39
- ...targetConfig?.options,
40
- ...(configuration
41
- ? targetConfig?.configurations?.[configuration]
42
- : undefined),
43
- };
44
- const unresolvedOutputs = configuredOutputs.filter((o) => {
45
- if (!/\{options\./.test(o))
46
- return false;
47
- const unresolved = o.match(/\{options\.([^}]+)\}/g);
48
- return unresolved?.some((token) => {
49
- const key = token.slice('{options.'.length, -1);
50
- return mergedOptions[key] === undefined;
51
- });
24
+ // ── Data resolution ─────────────────────────────────────────────────
25
+ async function checkOutputs(taskId, check, { resolved, expanded }) {
26
+ const checkItems = (0, utils_2.deduplicateFolderEntries)(check);
27
+ const paths = checkItems.map(utils_2.normalizePath);
28
+ // checkFilesAreOutputs handles exact, directory-prefix and glob matching (and
29
+ // `!` exclusions) through the same native engine the task runner uses.
30
+ const { matched } = await (0, check_task_files_1.checkFilesAreOutputs)(taskId, paths);
31
+ const matchedPaths = new Set(matched);
32
+ return checkItems.map((value, i) => {
33
+ const path = paths[i];
34
+ const isMatch = matchedPaths.has(path);
35
+ return {
36
+ value,
37
+ file: path,
38
+ matched: isMatch,
39
+ contained: isMatch
40
+ ? []
41
+ : [
42
+ ...new Set([
43
+ ...(0, utils_2.pathsUnder)(path, resolved),
44
+ ...(0, utils_2.pathsUnder)(path, expanded),
45
+ ]),
46
+ ],
47
+ };
52
48
  });
53
- let expandedOutputs;
54
- try {
55
- const { expandOutputs } = require('../../../native');
56
- expandedOutputs = expandOutputs(workspace_root_1.workspaceRoot, resolvedOutputs);
57
- }
58
- catch {
59
- expandedOutputs = resolvedOutputs;
60
- }
61
- return {
62
- project: projectName,
63
- target: targetName,
64
- outputPaths: resolvedOutputs,
65
- expandedOutputs,
66
- unresolvedOutputs,
67
- };
68
- }
69
- function resolveCheckOutputData(rawFileToCheck, outputsData) {
70
- const fileToCheck = (0, utils_2.normalizePath)(rawFileToCheck);
71
- const { outputPaths, expandedOutputs } = outputsData;
72
- let matchedOutput = null;
73
- for (const outputPath of outputPaths) {
74
- const normalizedOutput = outputPath.replace(/\\/g, '/');
75
- if (fileToCheck === normalizedOutput ||
76
- fileToCheck.startsWith(normalizedOutput + '/')) {
77
- matchedOutput = outputPath;
78
- break;
79
- }
80
- }
81
- if (!matchedOutput && expandedOutputs.includes(fileToCheck)) {
82
- matchedOutput = fileToCheck;
83
- }
84
- let containedOutputPaths = [];
85
- let containedExpandedOutputs = [];
86
- if (!matchedOutput) {
87
- if (fileToCheck === '') {
88
- containedOutputPaths = [...outputPaths];
89
- containedExpandedOutputs = [...expandedOutputs];
90
- }
91
- else {
92
- const dirPrefix = fileToCheck.endsWith('/')
93
- ? fileToCheck
94
- : fileToCheck + '/';
95
- containedOutputPaths = outputPaths.filter((o) => o.replace(/\\/g, '/').startsWith(dirPrefix));
96
- containedExpandedOutputs = expandedOutputs.filter((o) => o.replace(/\\/g, '/').startsWith(dirPrefix));
97
- }
98
- }
99
- return {
100
- value: rawFileToCheck,
101
- file: fileToCheck,
102
- project: outputsData.project,
103
- target: outputsData.target,
104
- matchedOutput,
105
- containedOutputPaths,
106
- containedExpandedOutputs,
107
- };
108
49
  }
109
50
  // ── Render ──────────────────────────────────────────────────────────
110
- function renderOutputs(data, args) {
51
+ function renderOutputs(project, target, { resolved, expanded, unresolved }, args) {
111
52
  if (args.json) {
112
- const jsonData = data;
113
- const result = {};
114
- for (const [k, v] of Object.entries(jsonData)) {
115
- if (Array.isArray(v) && v.length === 0)
116
- continue;
117
- result[k] = v;
118
- }
119
- console.log(JSON.stringify(result, null, 2));
53
+ (0, utils_2.printJson)({
54
+ project,
55
+ target,
56
+ outputPaths: resolved,
57
+ expandedOutputs: expanded,
58
+ unresolvedOutputs: unresolved,
59
+ });
120
60
  return;
121
61
  }
122
62
  const c = (0, utils_2.pc)();
123
- console.log(`${c.bold('Output paths for')} ${c.cyan(data.project)}:${c.green(data.target)}`);
124
- if (data.outputPaths.length > 0) {
125
- (0, utils_2.printList)('Configured outputs', data.outputPaths);
126
- }
127
- if (data.expandedOutputs.length > 0) {
128
- (0, utils_2.printList)('Resolved outputs', data.expandedOutputs);
129
- }
130
- if (data.unresolvedOutputs.length > 0) {
131
- (0, utils_2.printList)(`${c.yellow('Unresolved outputs')} (option not set)`, data.unresolvedOutputs);
132
- }
133
- if (data.outputPaths.length === 0 && data.unresolvedOutputs.length === 0) {
63
+ console.log(`${c.bold('Output paths for')} ${c.cyan(project)}:${c.green(target)}`);
64
+ (0, utils_2.printList)('Configured outputs', resolved);
65
+ (0, utils_2.printList)('Resolved outputs', expanded);
66
+ (0, utils_2.printList)(`${c.yellow('Unresolved outputs')} (option not set)`, unresolved);
67
+ if (resolved.length === 0 && unresolved.length === 0) {
134
68
  console.log(`\n No outputs configured for this target.`);
135
69
  }
136
70
  }
137
- function renderCheckOutput(data) {
138
- const c = (0, utils_2.pc)();
139
- const displayPath = data.value || data.file;
140
- if (data.matchedOutput) {
141
- console.log(`${c.green('✓')} ${c.bold(displayPath)} is an output of ${c.cyan(data.project)}:${c.green(data.target)}`);
142
- }
143
- else if (data.containedOutputPaths.length > 0 ||
144
- data.containedExpandedOutputs.length > 0) {
145
- const uniquePaths = new Set([
146
- ...data.containedOutputPaths,
147
- ...data.containedExpandedOutputs,
148
- ]);
149
- console.log(`${c.yellow('~')} ${c.bold(displayPath)} is a directory containing ${c.bold(String(uniquePaths.size))} output path(s) for ${c.cyan(data.project)}:${c.green(data.target)}`);
150
- const extraExpanded = data.containedExpandedOutputs.filter((o) => !data.containedOutputPaths.includes(o));
151
- if (extraExpanded.length > 0) {
152
- (0, utils_2.printList)('Expanded outputs', extraExpanded);
153
- }
154
- }
155
- else {
156
- console.log(`${c.red('✗')} ${c.bold(displayPath)} is ${c.red('not')} an output of ${c.cyan(data.project)}:${c.green(data.target)}`);
157
- }
158
- }
159
- function renderBatchCheckOutputs(results, projectName, targetName) {
160
- const c = (0, utils_2.pc)();
161
- const label = `${c.cyan(projectName)}:${c.green(targetName)}`;
162
- const matched = [];
163
- const directories = [];
164
- const unmatched = [];
165
- for (const r of results) {
166
- if (r.matchedOutput) {
167
- matched.push(r.value);
168
- }
169
- else {
170
- const uniqueCount = new Set([
171
- ...r.containedOutputPaths,
172
- ...r.containedExpandedOutputs,
173
- ]).size;
174
- if (uniqueCount > 0) {
175
- directories.push({ value: r.file, count: uniqueCount });
176
- }
177
- else {
178
- unmatched.push(r.value);
179
- }
180
- }
181
- }
182
- if (matched.length > 0 || directories.length > 0) {
183
- console.log(`\n${c.green('✓')} These arguments were outputs of ${label}:`);
184
- for (const v of matched)
185
- console.log(` ${v}`);
186
- for (const d of directories) {
187
- console.log(` ${d.value} (directory containing ${d.count} output paths)`);
188
- }
189
- }
190
- if (unmatched.length > 0) {
191
- console.log(`\n${c.red('✗')} These arguments were ${c.red('not')} outputs of ${label}:`);
192
- for (const v of unmatched)
193
- console.log(` ${v}`);
194
- }
195
- }
@@ -24,3 +24,31 @@ export declare function normalizePath(p: string): string;
24
24
  export declare function deduplicateFolderEntries(items: string[]): string[];
25
25
  export declare function pc(): any;
26
26
  export declare function printList(header: string, items: unknown[], prefix?: string): void;
27
+ export declare function printJson(data: Record<string, unknown>): void;
28
+ /** The paths that live under `dir`. An empty `dir` is the workspace root. */
29
+ export declare function pathsUnder(dir: string, paths: string[]): string[];
30
+ export interface CheckResult {
31
+ /** The argument as the user typed it. */
32
+ value: string;
33
+ /** Workspace-relative form of `value`. */
34
+ file: string;
35
+ matched: boolean;
36
+ /** Which rule matched, when the caller can name one. */
37
+ category?: string;
38
+ /** Matches found underneath `value`, when it is a directory. */
39
+ contained: string[];
40
+ }
41
+ declare const NOUNS: {
42
+ readonly input: {
43
+ readonly preposition: 'for';
44
+ readonly contained: 'input file';
45
+ };
46
+ readonly output: {
47
+ readonly preposition: 'of';
48
+ readonly contained: 'output path';
49
+ };
50
+ };
51
+ type CheckNoun = keyof typeof NOUNS;
52
+ export declare function renderCheckResults(results: CheckResult[], project: string, target: string, noun: CheckNoun): void;
53
+ export declare function setCheckExitCode(results: CheckResult[]): void;
54
+ export {};
@@ -6,6 +6,10 @@ exports.normalizePath = normalizePath;
6
6
  exports.deduplicateFolderEntries = deduplicateFolderEntries;
7
7
  exports.pc = pc;
8
8
  exports.printList = printList;
9
+ exports.printJson = printJson;
10
+ exports.pathsUnder = pathsUnder;
11
+ exports.renderCheckResults = renderCheckResults;
12
+ exports.setCheckExitCode = setCheckExitCode;
9
13
  const path_1 = require("path");
10
14
  const calculate_default_project_name_1 = require("../../../config/calculate-default-project-name");
11
15
  const configuration_1 = require("../../../config/configuration");
@@ -29,18 +33,22 @@ async function resolveTarget(args, opts) {
29
33
  }
30
34
  const nxJson = (0, configuration_1.readNxJson)();
31
35
  const { projectName, targetName, configurationName } = resolveTargetIdentifier(args, graph, nxJson);
36
+ // `resolveProjectNode` accepts a pattern specifier (`my-*`), so the concrete
37
+ // name it resolved to is the one everything downstream has to use — it is a
38
+ // lookup key for the task id, not just a label.
32
39
  const node = resolveProjectNode(projectName, graph);
40
+ const resolvedProjectName = node.name;
33
41
  if (!node.data.targets?.[targetName]) {
34
- reportTargetNotFound(projectName, targetName, node);
42
+ reportTargetNotFound(resolvedProjectName, targetName, node);
35
43
  }
36
44
  const configuration = configurationName ?? args.configuration;
37
45
  if (configuration) {
38
- validateConfiguration(projectName, targetName, configuration, node.data.targets[targetName]);
46
+ validateConfiguration(resolvedProjectName, targetName, configuration, node.data.targets[targetName]);
39
47
  }
40
48
  return {
41
49
  graph,
42
50
  nxJson,
43
- projectName,
51
+ projectName: resolvedProjectName,
44
52
  targetName,
45
53
  configuration,
46
54
  node,
@@ -183,3 +191,75 @@ function printList(header, items, prefix = '\n') {
183
191
  for (const item of items)
184
192
  console.log(` ${item}`);
185
193
  }
194
+ function printJson(data) {
195
+ const result = {};
196
+ for (const [key, value] of Object.entries(data)) {
197
+ if (Array.isArray(value) && value.length === 0)
198
+ continue;
199
+ result[key] = value;
200
+ }
201
+ console.log(JSON.stringify(result, null, 2));
202
+ }
203
+ /** The paths that live under `dir`. An empty `dir` is the workspace root. */
204
+ function pathsUnder(dir, paths) {
205
+ if (dir === '')
206
+ return [...paths];
207
+ const prefix = dir.endsWith('/') ? dir : dir + '/';
208
+ return paths.filter((p) => p.startsWith(prefix));
209
+ }
210
+ const NOUNS = {
211
+ input: { preposition: 'for', contained: 'input file' },
212
+ output: { preposition: 'of', contained: 'output path' },
213
+ };
214
+ function renderCheckResults(results, project, target, noun) {
215
+ if (results.length >= 2) {
216
+ renderBatchCheckResults(results, project, target, noun);
217
+ return;
218
+ }
219
+ for (const result of results) {
220
+ renderCheckResult(result, project, target, noun);
221
+ }
222
+ }
223
+ function setCheckExitCode(results) {
224
+ for (const result of results) {
225
+ process.exitCode ||= result.matched || result.contained.length ? 0 : 1;
226
+ }
227
+ }
228
+ function renderCheckResult(result, project, target, noun) {
229
+ const c = pc();
230
+ const { preposition, contained } = NOUNS[noun];
231
+ const label = `${c.cyan(project)}:${c.green(target)}`;
232
+ if (result.matched) {
233
+ const category = result.category ? ` (${result.category})` : '';
234
+ console.log(`${c.green('✓')} ${c.bold(result.value)} is an ${noun} ${preposition} ${label}${category}`);
235
+ }
236
+ else if (result.contained.length > 0) {
237
+ console.log(`${c.yellow('~')} ${c.bold(result.file)} is a directory containing ${c.bold(String(result.contained.length))} ${contained}(s) ${preposition} ${label}`);
238
+ for (const item of [...result.contained].sort())
239
+ console.log(` ${item}`);
240
+ }
241
+ else {
242
+ console.log(`${c.red('✗')} ${c.bold(result.value)} is ${c.red('not')} an ${noun} ${preposition} ${label}`);
243
+ }
244
+ }
245
+ function renderBatchCheckResults(results, project, target, noun) {
246
+ const c = pc();
247
+ const { preposition, contained } = NOUNS[noun];
248
+ const label = `${c.cyan(project)}:${c.green(target)}`;
249
+ const matched = results.filter((r) => r.matched);
250
+ const directories = results.filter((r) => !r.matched && r.contained.length);
251
+ const unmatched = results.filter((r) => !r.matched && !r.contained.length);
252
+ if (matched.length > 0 || directories.length > 0) {
253
+ console.log(`\n${c.green('✓')} These arguments were ${noun}s ${preposition} ${label}:`);
254
+ for (const r of matched)
255
+ console.log(` ${r.value}`);
256
+ for (const r of directories) {
257
+ console.log(` ${r.file} (directory containing ${r.contained.length} ${contained}s)`);
258
+ }
259
+ }
260
+ if (unmatched.length > 0) {
261
+ console.log(`\n${c.red('✗')} These arguments were ${c.red('not')} ${noun}s ${preposition} ${label}:`);
262
+ for (const r of unmatched)
263
+ console.log(` ${r.value}`);
264
+ }
265
+ }
@@ -1,4 +1,4 @@
1
- import { Argv, ParserConfigurationOptions } from 'yargs';
1
+ import type { Argv, ParserConfigurationOptions } from 'yargs';
2
2
  interface ExcludeOptions {
3
3
  exclude: string[];
4
4
  }
@@ -41,6 +41,11 @@ function createCommandGraph(projectGraph, projectNames, nxArgs) {
41
41
  recursiveResolveDeps(projectGraph, projectName, dependencies);
42
42
  }
43
43
  }
44
+ else {
45
+ for (const projectName of projectNames) {
46
+ dependencies[projectName] = [];
47
+ }
48
+ }
44
49
  const roots = Object.keys(dependencies).filter((d) => dependencies[d].length === 0);
45
50
  const commandGraph = {
46
51
  dependencies,
@@ -787,7 +787,7 @@ export interface NxJsonConfiguration<T = '*' | string[]> {
787
787
  targetDefaults?: TargetDefaults;
788
788
  /**
789
789
  * Default options for `nx affected`
790
- * @deprecated use {@link defaultBase} instead. For more information see https://nx.dev/deprecated/affected-config#affected-config
790
+ * @deprecated use {@link defaultBase} instead. For more information see https://nx.dev/docs/reference/nx-json#default-base
791
791
  */
792
792
  affected?: NxAffectedConfig;
793
793
  /**