nx 23.2.0-beta.1 → 23.2.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/nx.js +1 -0
- package/dist/src/analytics/analytics.d.ts +6 -0
- package/dist/src/analytics/analytics.js +16 -8
- package/dist/src/analytics/index.d.ts +1 -1
- package/dist/src/analytics/index.js +2 -1
- package/dist/src/command-line/graph/graph.d.ts +1 -0
- package/dist/src/command-line/graph/graph.js +15 -6
- package/dist/src/command-line/init/implementation/angular/integrated-workspace.js +2 -5
- package/dist/src/command-line/init/implementation/angular/legacy-angular-versions.js +3 -0
- package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +4 -1
- package/dist/src/command-line/migrate/migrate.js +20 -1
- package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.js +1 -1
- package/dist/src/command-line/nx-cloud/connect/view-logs.js +2 -0
- package/dist/src/command-line/release/utils/remote-release-clients/github.js +1 -1
- package/dist/src/command-line/release/utils/remote-release-clients/gitlab.js +1 -1
- package/dist/src/command-line/show/show-target/inputs.js +50 -153
- package/dist/src/command-line/show/show-target/outputs.js +48 -173
- package/dist/src/command-line/show/show-target/utils.d.ts +28 -0
- package/dist/src/command-line/show/show-target/utils.js +83 -3
- package/dist/src/command-line/yargs-utils/shared-options.d.ts +1 -1
- package/dist/src/config/nx-json.d.ts +4 -2
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/daemon/server/handle-tasks-execution-hooks.d.ts +1 -1
- package/dist/src/daemon/server/server.js +7 -4
- package/dist/src/devkit-internals.d.ts +1 -0
- package/dist/src/devkit-internals.js +5 -2
- package/dist/src/hasher/check-task-files.d.ts +86 -0
- package/dist/src/hasher/check-task-files.js +378 -0
- package/dist/src/native/index.d.ts +27 -4
- package/dist/src/native/native-bindings.js +2 -0
- package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
- package/dist/src/plugins/js/lock-file/utils/pnpm-normalizer.js +3 -0
- package/dist/src/plugins/js/project-graph/build-dependencies/target-project-locator.js +12 -4
- package/dist/src/project-graph/build-project-graph.js +7 -1
- package/dist/src/project-graph/plugins/loaded-nx-plugin.js +1 -0
- package/dist/src/project-graph/project-graph.js +3 -0
- package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.d.ts +1 -0
- package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.js +16 -2
- package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.d.ts +5 -8
- package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.js +11 -14
- package/dist/src/project-graph/utils/project-configuration/source-maps.d.ts +12 -5
- package/dist/src/project-graph/utils/project-configuration/source-maps.js +21 -7
- package/dist/src/project-graph/utils/project-configuration/target-defaults.d.ts +1 -1
- package/dist/src/project-graph/utils/project-configuration/target-defaults.js +26 -27
- package/dist/src/project-graph/utils/project-configuration/target-merging.js +50 -8
- package/dist/src/project-graph/utils/project-configuration/target-normalization.js +16 -3
- package/dist/src/project-graph/utils/project-configuration/utils.d.ts +15 -0
- package/dist/src/project-graph/utils/project-configuration/utils.js +42 -6
- package/dist/src/project-graph/utils/project-configuration-utils.d.ts +15 -12
- package/dist/src/project-graph/utils/project-configuration-utils.js +79 -99
- package/dist/src/tasks-runner/life-cycle.d.ts +2 -2
- package/dist/src/tasks-runner/life-cycle.js +2 -2
- package/dist/src/tasks-runner/pseudo-terminal.d.ts +1 -1
- package/dist/src/tasks-runner/pseudo-terminal.js +2 -2
- package/dist/src/tasks-runner/task-env.d.ts +9 -0
- package/dist/src/tasks-runner/task-env.js +26 -2
- package/dist/src/tasks-runner/task-orchestrator.d.ts +4 -1
- package/dist/src/tasks-runner/task-orchestrator.js +25 -12
- package/dist/src/utils/acknowledge-build-scripts.js +7 -5
- package/dist/src/utils/analytics-prompt.d.ts +0 -6
- package/dist/src/utils/analytics-prompt.js +0 -51
- package/dist/src/utils/catalog/bun-manager-utils.d.ts +8 -0
- package/dist/src/utils/catalog/bun-manager-utils.js +174 -0
- package/dist/src/utils/catalog/bun-manager.d.ts +28 -0
- package/dist/src/utils/catalog/bun-manager.js +130 -0
- package/dist/src/utils/catalog/index.d.ts +1 -1
- package/dist/src/utils/catalog/index.js +1 -1
- package/dist/src/utils/catalog/manager-factory.js +3 -0
- package/dist/src/utils/catalog/manager-utils.d.ts +8 -1
- package/dist/src/utils/catalog/manager-utils.js +9 -4
- package/dist/src/utils/catalog/manager.d.ts +13 -1
- package/dist/src/utils/catalog/manager.js +30 -0
- package/dist/src/utils/catalog/pnpm-manager.d.ts +2 -1
- package/dist/src/utils/catalog/pnpm-manager.js +3 -0
- package/dist/src/utils/catalog/types.d.ts +4 -0
- package/dist/src/utils/catalog/yarn-manager.d.ts +6 -2
- package/dist/src/utils/catalog/yarn-manager.js +23 -32
- package/dist/src/utils/git-utils.d.ts +15 -0
- package/dist/src/utils/git-utils.js +64 -6
- package/dist/src/utils/package-manager.d.ts +3 -1
- package/dist/src/utils/package-manager.js +22 -2
- package/dist/src/utils/workspace-id.d.ts +20 -0
- package/dist/src/utils/workspace-id.js +54 -0
- package/package.json +20 -15
|
@@ -13,10 +13,10 @@ const delayed_spinner_1 = require("../../utils/delayed-spinner");
|
|
|
13
13
|
const plugin_progress_text_1 = require("../../utils/plugin-progress-text");
|
|
14
14
|
const progress_topics_1 = require("../../utils/progress-topics");
|
|
15
15
|
const error_types_1 = require("../error-types");
|
|
16
|
-
const source_maps_1 = require("./project-configuration/source-maps");
|
|
17
16
|
const target_defaults_1 = require("./project-configuration/target-defaults");
|
|
18
17
|
var target_merging_1 = require("./project-configuration/target-merging");
|
|
19
18
|
Object.defineProperty(exports, "mergeTargetConfigurations", { enumerable: true, get: function () { return target_merging_1.mergeTargetConfigurations; } });
|
|
19
|
+
const target_merging_2 = require("./project-configuration/target-merging");
|
|
20
20
|
var target_defaults_2 = require("./project-configuration/target-defaults");
|
|
21
21
|
Object.defineProperty(exports, "readTargetDefaultsForTarget", { enumerable: true, get: function () { return target_defaults_2.readTargetDefaultsForTarget; } });
|
|
22
22
|
/**
|
|
@@ -123,14 +123,13 @@ async function createProjectConfigurationsWithPlugins(root = workspace_root_1.wo
|
|
|
123
123
|
* Runs a single plugin batch through two passes:
|
|
124
124
|
*
|
|
125
125
|
* 1. Every project node in every plugin result is handed to `mergeFn`,
|
|
126
|
-
* which
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
* onto the shared `externalNodes` record.
|
|
126
|
+
* which merges it into the manager's rootMap. Any failure is
|
|
127
|
+
* collected into `errors`; processing keeps going. External nodes
|
|
128
|
+
* are accumulated onto the shared `externalNodes` record.
|
|
130
129
|
* 2. After every project in the batch has been merged, name-reference
|
|
131
|
-
* sentinels for the batch are registered against
|
|
132
|
-
*
|
|
133
|
-
*
|
|
130
|
+
* sentinels for the batch are registered against the manager's
|
|
131
|
+
* rootMap, so sentinels point at the target objects that actually
|
|
132
|
+
* received the merges.
|
|
134
133
|
*
|
|
135
134
|
* The two passes can't be collapsed: a sentinel registered too early
|
|
136
135
|
* would point at the pre-merge object, and a later project in the same
|
|
@@ -138,7 +137,11 @@ async function createProjectConfigurationsWithPlugins(root = workspace_root_1.wo
|
|
|
138
137
|
* the registration into a second pass also lets forward references
|
|
139
138
|
* inside the same batch resolve eagerly.
|
|
140
139
|
*/
|
|
141
|
-
function mergeCreateNodesResultsFromSinglePlugin(pluginResults, mergeFn, nodesManager,
|
|
140
|
+
function mergeCreateNodesResultsFromSinglePlugin(pluginResults, mergeFn, nodesManager, externalNodes, errors) {
|
|
141
|
+
mergeSinglePluginResults(pluginResults, mergeFn, externalNodes, errors);
|
|
142
|
+
registerNameRefsFromSinglePlugin(pluginResults, nodesManager, errors);
|
|
143
|
+
}
|
|
144
|
+
function mergeSinglePluginResults(pluginResults, mergeFn, externalNodes, errors) {
|
|
142
145
|
for (const result of pluginResults) {
|
|
143
146
|
const [pluginName, file, nodes, pluginIndex] = result;
|
|
144
147
|
const { projects: projectNodes, externalNodes: pluginExternalNodes } = nodes;
|
|
@@ -156,11 +159,13 @@ function mergeCreateNodesResultsFromSinglePlugin(pluginResults, mergeFn, nodesMa
|
|
|
156
159
|
}
|
|
157
160
|
Object.assign(externalNodes, pluginExternalNodes);
|
|
158
161
|
}
|
|
162
|
+
}
|
|
163
|
+
function registerNameRefsFromSinglePlugin(pluginResults, nodesManager, errors) {
|
|
159
164
|
for (const result of pluginResults) {
|
|
160
165
|
const [pluginName, file, nodes, pluginIndex] = result;
|
|
161
166
|
const { projects: projectNodes } = nodes;
|
|
162
167
|
try {
|
|
163
|
-
nodesManager.registerNameRefs(projectNodes
|
|
168
|
+
nodesManager.registerNameRefs(projectNodes);
|
|
164
169
|
}
|
|
165
170
|
catch (error) {
|
|
166
171
|
errors.push(new error_types_1.MergeNodesError({ file, pluginName, error, pluginIndex }));
|
|
@@ -170,108 +175,83 @@ function mergeCreateNodesResultsFromSinglePlugin(pluginResults, mergeFn, nodesMa
|
|
|
170
175
|
/**
|
|
171
176
|
* Merges create nodes results into a single rootMap.
|
|
172
177
|
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
178
|
+
* Every layer merges into the manager through the same source-map-aware
|
|
179
|
+
* merge, in precedence order:
|
|
180
|
+
*
|
|
181
|
+
* specified plugins → synthetic target defaults → default plugins
|
|
182
|
+
*
|
|
183
|
+
* so field-level provenance is decided by the merge itself for all three
|
|
184
|
+
* layers — whichever layer a field's final value came from owns its
|
|
185
|
+
* attribution, and `'...'` spreads in default-plugin configs resolve against
|
|
186
|
+
* the accumulated specified + target-defaults base.
|
|
180
187
|
*
|
|
181
|
-
*
|
|
182
|
-
* (
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
188
|
+
* Target-default synthesis needs the *merged* shape of the default layer
|
|
189
|
+
* (to predict each target's eventual executor/command) before that layer
|
|
190
|
+
* merges into the manager. To get it, default results are first staged into
|
|
191
|
+
* a throwaway intermediate rootMap with unresolvable `'...'` spreads
|
|
192
|
+
* deferred. The staging output feeds only `createTargetDefaultsResults`; the
|
|
193
|
+
* default plugins then merge into the manager from their original results.
|
|
186
194
|
*/
|
|
187
195
|
function mergeCreateNodesResults(specifiedResults, defaultResults, nxJsonConfiguration, workspaceRoot, errors) {
|
|
188
196
|
perf_hooks_1.performance.mark('createNodes:merge - start');
|
|
189
197
|
const nodesManager = new project_nodes_manager_1.ProjectNodesManager();
|
|
190
198
|
const externalNodes = {};
|
|
191
199
|
const configurationSourceMaps = {};
|
|
192
|
-
const intermediateDefaultRootMap = {};
|
|
193
|
-
// Kept separate so the intermediate merge doesn't clobber
|
|
194
|
-
// specified/TD attribution on fields the defaults don't touch.
|
|
195
|
-
const defaultConfigurationSourceMaps = {};
|
|
196
200
|
const mergeToManager = (project, sourceInfo) => nodesManager.mergeProjectNode(project, configurationSourceMaps, sourceInfo);
|
|
197
|
-
const mergeToIntermediate = (project, sourceInfo) => {
|
|
198
|
-
(0, project_nodes_manager_1.mergeProjectConfigurationIntoRootMap)(intermediateDefaultRootMap, project, defaultConfigurationSourceMaps, sourceInfo);
|
|
199
|
-
};
|
|
200
201
|
for (const pluginResults of specifiedResults) {
|
|
201
|
-
mergeCreateNodesResultsFromSinglePlugin(pluginResults, mergeToManager, nodesManager,
|
|
202
|
-
}
|
|
203
|
-
for (const pluginResults of defaultResults) {
|
|
204
|
-
mergeCreateNodesResultsFromSinglePlugin(pluginResults, mergeToIntermediate, nodesManager, intermediateDefaultRootMap, externalNodes, errors);
|
|
205
|
-
}
|
|
206
|
-
const targetDefaultsResults = (0, target_defaults_1.createTargetDefaultsResults)(nodesManager.getRootMap(), intermediateDefaultRootMap, nxJsonConfiguration, configurationSourceMaps, defaultConfigurationSourceMaps);
|
|
207
|
-
if (targetDefaultsResults.length > 0) {
|
|
208
|
-
mergeCreateNodesResultsFromSinglePlugin(targetDefaultsResults, mergeToManager, nodesManager, nodesManager.getRootMap(), externalNodes, errors);
|
|
202
|
+
mergeCreateNodesResultsFromSinglePlugin(pluginResults, mergeToManager, nodesManager, externalNodes, errors);
|
|
209
203
|
}
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
//
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
204
|
+
// Without target defaults there is nothing to synthesize, and the staging
|
|
205
|
+
// pass exists only to feed synthesis — skip straight to the default-plugin
|
|
206
|
+
// merge.
|
|
207
|
+
if (Object.keys(nxJsonConfiguration.targetDefaults ?? {}).length > 0) {
|
|
208
|
+
// Throwaway staging area: the default layer's merged shape (unresolvable
|
|
209
|
+
// `'...'` spreads deferred), read only by target-default synthesis. The
|
|
210
|
+
// default plugins merge into the manager from their original results, not
|
|
211
|
+
// from this map. No source maps are kept for it — synthesis attributes
|
|
212
|
+
// targets without them (a default plugin can never be named by a
|
|
213
|
+
// `filter.plugin`); the real default merge writes the manager's.
|
|
214
|
+
const intermediateDefaultRootMap = {};
|
|
215
|
+
// The rootMap merge adopts input arrays/objects by reference and grows
|
|
216
|
+
// them in place (e.g. `mergeMetadata`), so staging works on deep clones —
|
|
217
|
+
// handing it the plugin results themselves would corrupt them before the
|
|
218
|
+
// real merge below reads them.
|
|
219
|
+
const mergeToIntermediate = (project, sourceInfo) => {
|
|
220
|
+
(0, project_nodes_manager_1.mergeProjectConfigurationIntoRootMap)(intermediateDefaultRootMap, (0, target_merging_2.deepClone)(project), undefined, sourceInfo, false, true);
|
|
221
|
+
};
|
|
222
|
+
// Stage the default layer for synthesis. Merge errors are discarded and
|
|
223
|
+
// external nodes land in a scratch object — the same results merge into
|
|
224
|
+
// the manager below, where both surface once with proper plugin context.
|
|
225
|
+
// The discard is safe because every merge throw is base-independent in
|
|
226
|
+
// both its condition and its reachability: each throw's condition reads
|
|
227
|
+
// only the plugin's own config, and the spread-ambiguity throws fire even
|
|
228
|
+
// when a key is dropped by a base-owns-key shortcut, because those
|
|
229
|
+
// shortcuts eagerly validate the dropped value (`assertNoIntegerLikeSpreadKey`).
|
|
230
|
+
// So a given config raises the same error in this pass and the real merge
|
|
231
|
+
// below despite their bases differing.
|
|
232
|
+
// Name references are NOT registered here: `applySubstitutions` sweeps only
|
|
233
|
+
// the manager's `rootMap`, so sentinels registered against this throwaway
|
|
234
|
+
// rootMap would never be visited and would never resolve.
|
|
235
|
+
const stagingErrors = [];
|
|
236
|
+
const stagingExternalNodes = {};
|
|
237
|
+
for (const pluginResults of defaultResults) {
|
|
238
|
+
mergeSinglePluginResults(pluginResults, mergeToIntermediate, stagingExternalNodes, stagingErrors);
|
|
218
239
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
pluginName: 'nx/default-plugins',
|
|
223
|
-
error,
|
|
224
|
-
pluginIndex: undefined,
|
|
225
|
-
}));
|
|
240
|
+
const targetDefaultsResults = (0, target_defaults_1.createTargetDefaultsResults)(nodesManager.getRootMap(), intermediateDefaultRootMap, nxJsonConfiguration, configurationSourceMaps);
|
|
241
|
+
if (targetDefaultsResults.length > 0) {
|
|
242
|
+
mergeCreateNodesResultsFromSinglePlugin(targetDefaultsResults, mergeToManager, nodesManager, externalNodes, errors);
|
|
226
243
|
}
|
|
227
244
|
}
|
|
228
|
-
//
|
|
229
|
-
//
|
|
230
|
-
//
|
|
231
|
-
//
|
|
232
|
-
|
|
233
|
-
//
|
|
234
|
-
//
|
|
235
|
-
//
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
// already matches what the default plugin would overlay.
|
|
239
|
-
// - For fields where a default plugin placed `...` after other keys,
|
|
240
|
-
// those keys yielded to the base during the single-layer apply
|
|
241
|
-
// above. The stale default-plugin entry in
|
|
242
|
-
// `defaultConfigurationSourceMaps` must NOT clobber the base
|
|
243
|
-
// attribution that the specified plugin / TD already recorded.
|
|
244
|
-
const mainRootMap = nodesManager.getRootMap();
|
|
245
|
-
for (const root in defaultConfigurationSourceMaps) {
|
|
246
|
-
const existing = (configurationSourceMaps[root] ??= {});
|
|
247
|
-
const incoming = defaultConfigurationSourceMaps[root];
|
|
248
|
-
// A default plugin's targets are synthesized into the main rootmap by
|
|
249
|
-
// target defaults *before* the default layer is applied, so target
|
|
250
|
-
// defaults wrote the main source map's entry for the target node and its
|
|
251
|
-
// identity fields first — even though it never authored them (it only
|
|
252
|
-
// stamps them as a merge guard and cannot bring a target into existence).
|
|
253
|
-
// The identity fields are the executor/command plus, for run-commands, the
|
|
254
|
-
// `options.command`/`options.commands` the synthetic copies from the winner
|
|
255
|
-
// to stay compatible (#36067). For those keys, the real default plugin's
|
|
256
|
-
// attribution must override the target-defaults stamp.
|
|
257
|
-
const identityKeys = new Set();
|
|
258
|
-
for (const targetName in mainRootMap[root]?.targets ?? {}) {
|
|
259
|
-
const base = (0, source_maps_1.targetSourceMapKey)(targetName);
|
|
260
|
-
identityKeys.add(base);
|
|
261
|
-
identityKeys.add(`${base}.executor`);
|
|
262
|
-
identityKeys.add(`${base}.command`);
|
|
263
|
-
identityKeys.add(`${base}.options.command`);
|
|
264
|
-
identityKeys.add(`${base}.options.commands`);
|
|
265
|
-
}
|
|
266
|
-
for (const key in incoming) {
|
|
267
|
-
if (existing[key] === undefined) {
|
|
268
|
-
existing[key] = incoming[key];
|
|
269
|
-
}
|
|
270
|
-
else if (identityKeys.has(key) &&
|
|
271
|
-
existing[key][1] === source_maps_1.TARGET_DEFAULTS_PLUGIN_NAME) {
|
|
272
|
-
existing[key] = incoming[key];
|
|
273
|
-
}
|
|
274
|
-
}
|
|
245
|
+
// Merge the default plugins into the manager on top of the specified + TD
|
|
246
|
+
// base, from their original results. This is the same source-map-aware path
|
|
247
|
+
// the other layers take, so every field a default plugin wins — including
|
|
248
|
+
// fields it overrides on a specified/TD target — is attributed to it by the
|
|
249
|
+
// merge itself, `'...'` spreads resolve against the real base (keys a spread
|
|
250
|
+
// lets the base win keep their base attribution), and identity provenance
|
|
251
|
+
// follows the node-ownership rules in `recordTargetIdentitySourceMapInfo` /
|
|
252
|
+
// `getMergeValueResult`.
|
|
253
|
+
for (const pluginResults of defaultResults) {
|
|
254
|
+
mergeCreateNodesResultsFromSinglePlugin(pluginResults, mergeToManager, nodesManager, externalNodes, errors);
|
|
275
255
|
}
|
|
276
256
|
const projectRootMap = nodesManager.getRootMap();
|
|
277
257
|
try {
|
|
@@ -44,7 +44,7 @@ export interface LifeCycle {
|
|
|
44
44
|
startTasks?(task: Task[], metadata: TaskMetadata): void | Promise<void>;
|
|
45
45
|
endTasks?(taskResults: TaskResult[], metadata: TaskMetadata): void | Promise<void>;
|
|
46
46
|
printTaskTerminalOutput?(task: Task, status: TaskStatus, output: string): void;
|
|
47
|
-
registerRunningTask?(taskId: string,
|
|
47
|
+
registerRunningTask?(taskId: string, ptyHandles: ExternalObject<[any, any, any]>): void;
|
|
48
48
|
registerRunningTaskWithEmptyParser?(taskId: string): void;
|
|
49
49
|
appendTaskOutput?(taskId: string, output: string, isPtyTask: boolean): void;
|
|
50
50
|
setTaskStatus?(taskId: string, status: NativeTaskStatus): void;
|
|
@@ -72,7 +72,7 @@ export declare class CompositeLifeCycle implements LifeCycle {
|
|
|
72
72
|
startTasks(tasks: Task[], metadata: TaskMetadata): Promise<void>;
|
|
73
73
|
endTasks(taskResults: TaskResult[], metadata: TaskMetadata): Promise<void>;
|
|
74
74
|
printTaskTerminalOutput(task: Task, status: TaskStatus, output: string): void;
|
|
75
|
-
registerRunningTask(taskId: string,
|
|
75
|
+
registerRunningTask(taskId: string, ptyHandles: ExternalObject<[any, any, any]>): void;
|
|
76
76
|
registerRunningTaskWithEmptyParser(taskId: string): void;
|
|
77
77
|
appendTaskOutput(taskId: string, output: string, isPtyTask: boolean): void;
|
|
78
78
|
setTaskStatus(taskId: string, status: NativeTaskStatus): void;
|
|
@@ -67,10 +67,10 @@ class CompositeLifeCycle {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
-
registerRunningTask(taskId,
|
|
70
|
+
registerRunningTask(taskId, ptyHandles) {
|
|
71
71
|
for (let l of this.lifeCycles) {
|
|
72
72
|
if (l.registerRunningTask) {
|
|
73
|
-
l.registerRunningTask(taskId,
|
|
73
|
+
l.registerRunningTask(taskId, ptyHandles);
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
}
|
|
@@ -47,7 +47,7 @@ export declare class PseudoTtyProcess implements RunningTask {
|
|
|
47
47
|
onOutput(callback: (message: string) => void): void;
|
|
48
48
|
getPid(): number | undefined;
|
|
49
49
|
kill(s?: NodeJS.Signals): Promise<void>;
|
|
50
|
-
|
|
50
|
+
getPtyHandles(): import("../native").ExternalObject<[import("../native").ParserArc, import("../native").WriterArc, import("../native").MasterArc]>;
|
|
51
51
|
}
|
|
52
52
|
export declare class PseudoTtyProcessWithSend extends PseudoTtyProcess {
|
|
53
53
|
rustPseudoTerminal: RustPseudoTerminal;
|
|
@@ -150,8 +150,8 @@ class PseudoTtyProcess {
|
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
}
|
|
153
|
-
|
|
154
|
-
return this.childProcess.
|
|
153
|
+
getPtyHandles() {
|
|
154
|
+
return this.childProcess.getPtyHandles();
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
exports.PseudoTtyProcess = PseudoTtyProcess;
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { ProjectGraph } from '../config/project-graph';
|
|
2
2
|
import { Task } from '../config/task-graph';
|
|
3
|
+
/**
|
|
4
|
+
* Resolves the FORCE_COLOR value for forked child processes.
|
|
5
|
+
*
|
|
6
|
+
* When the user sets FORCE_COLOR=0, bin/nx.ts deletes it from process.env
|
|
7
|
+
* (workaround for picocolors treating "0" as truthy) and saves the original
|
|
8
|
+
* value in NX_ORIGINAL_FORCE_COLOR. Without this check, the undefined
|
|
9
|
+
* FORCE_COLOR would default to 'true', re-enabling colors in all children.
|
|
10
|
+
*/
|
|
11
|
+
export declare function getForceColorForChild(): string;
|
|
3
12
|
export declare function getEnvVariablesForBatchProcess(skipNxCache: boolean, captureStderr: boolean): NodeJS.ProcessEnv;
|
|
4
13
|
export declare function getTaskSpecificEnv(task: Task, graph: ProjectGraph): NodeJS.ProcessEnv;
|
|
5
14
|
export declare function getEnvVariablesForTask(task: Task, taskSpecificEnv: NodeJS.ProcessEnv, forceColor: string, skipNxCache: boolean, captureStderr: boolean, outputPath: string, streamOutput: boolean): NodeJS.ProcessEnv;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getForceColorForChild = getForceColorForChild;
|
|
3
4
|
exports.getEnvVariablesForBatchProcess = getEnvVariablesForBatchProcess;
|
|
4
5
|
exports.getTaskSpecificEnv = getTaskSpecificEnv;
|
|
5
6
|
exports.getEnvVariablesForTask = getEnvVariablesForTask;
|
|
@@ -11,13 +12,33 @@ const dotenv_expand_1 = require("dotenv-expand");
|
|
|
11
12
|
const node_path_1 = require("node:path");
|
|
12
13
|
const workspace_root_1 = require("../utils/workspace-root");
|
|
13
14
|
const task_env_paths_1 = require("./task-env-paths");
|
|
15
|
+
/**
|
|
16
|
+
* Resolves the FORCE_COLOR value for forked child processes.
|
|
17
|
+
*
|
|
18
|
+
* When the user sets FORCE_COLOR=0, bin/nx.ts deletes it from process.env
|
|
19
|
+
* (workaround for picocolors treating "0" as truthy) and saves the original
|
|
20
|
+
* value in NX_ORIGINAL_FORCE_COLOR. Without this check, the undefined
|
|
21
|
+
* FORCE_COLOR would default to 'true', re-enabling colors in all children.
|
|
22
|
+
*/
|
|
23
|
+
function getForceColorForChild() {
|
|
24
|
+
if (process.env.FORCE_COLOR !== undefined) {
|
|
25
|
+
return process.env.FORCE_COLOR;
|
|
26
|
+
}
|
|
27
|
+
if (process.env.NX_ORIGINAL_FORCE_COLOR === '0') {
|
|
28
|
+
return '0';
|
|
29
|
+
}
|
|
30
|
+
return 'true';
|
|
31
|
+
}
|
|
14
32
|
function getEnvVariablesForBatchProcess(skipNxCache, captureStderr) {
|
|
15
|
-
|
|
33
|
+
const res = {
|
|
16
34
|
// User Process Env Variables override Dotenv Variables
|
|
17
35
|
...process.env,
|
|
18
36
|
// Nx Env Variables overrides everything
|
|
19
|
-
...getNxEnvVariablesForForkedProcess(
|
|
37
|
+
...getNxEnvVariablesForForkedProcess(getForceColorForChild(), skipNxCache, captureStderr),
|
|
20
38
|
};
|
|
39
|
+
// NX_ORIGINAL_FORCE_COLOR is an internal signal and should not leak into child processes
|
|
40
|
+
delete res.NX_ORIGINAL_FORCE_COLOR;
|
|
41
|
+
return res;
|
|
21
42
|
}
|
|
22
43
|
// The orchestrator now calls this eagerly during the coordinator pre-hash
|
|
23
44
|
// in addition to processTask (and again in hashBatchTasks), so the same
|
|
@@ -58,6 +79,9 @@ function getEnvVariablesForTask(task, taskSpecificEnv, forceColor, skipNxCache,
|
|
|
58
79
|
}
|
|
59
80
|
// we don't reset NX_BASE or NX_HEAD because those are set by the user and should be preserved
|
|
60
81
|
delete res.NX_SET_CLI;
|
|
82
|
+
// NX_ORIGINAL_FORCE_COLOR is an internal signal used by getForceColorForChild()
|
|
83
|
+
// and should not leak into child processes
|
|
84
|
+
delete res.NX_ORIGINAL_FORCE_COLOR;
|
|
61
85
|
return res;
|
|
62
86
|
}
|
|
63
87
|
function getNxEnvVariablesForForkedProcess(forceColor, skipNxCache, captureStderr, outputPath, streamOutput) {
|
|
@@ -35,6 +35,7 @@ export declare class TaskOrchestrator {
|
|
|
35
35
|
private reverseTaskDeps;
|
|
36
36
|
private initializingTaskIds;
|
|
37
37
|
private processedTasks;
|
|
38
|
+
private cacheMissedHashes;
|
|
38
39
|
private completedTasks;
|
|
39
40
|
private waitingForTasks;
|
|
40
41
|
private pendingDiscreteWorkers;
|
|
@@ -100,7 +101,9 @@ export declare class TaskOrchestrator {
|
|
|
100
101
|
* The coordinator relies on this running unconditionally (when cache
|
|
101
102
|
* is enabled): tasks dispatched in step 5 via runTaskDirectly skip
|
|
102
103
|
* their own cache lookup on the assumption that this has already
|
|
103
|
-
* confirmed them as misses.
|
|
104
|
+
* confirmed them as misses. Excluding cacheMissedHashes preserves that
|
|
105
|
+
* invariant — every dispatched hash was queried exactly once — but
|
|
106
|
+
* don't add other length-based bails.
|
|
104
107
|
*/
|
|
105
108
|
private resolveCachedTasksBulk;
|
|
106
109
|
/**
|
|
@@ -79,6 +79,12 @@ class TaskOrchestrator {
|
|
|
79
79
|
// underlying real tasks become the anchors.
|
|
80
80
|
this.initializingTaskIds = (0, utils_1.expandInitiatingTasksThroughNoop)(this.initiatingTasks, this.taskGraph, this.projectGraph);
|
|
81
81
|
this.processedTasks = new Map();
|
|
82
|
+
// Hashes confirmed absent from the cache this run. A confirmed miss can
|
|
83
|
+
// only become a hit when the task itself runs — and then it leaves the
|
|
84
|
+
// schedule — so a missed hash never needs re-querying. Without this, a
|
|
85
|
+
// miss waiting for a worker slot is re-queried (including the remote
|
|
86
|
+
// retrieval) on every coordinator cycle.
|
|
87
|
+
this.cacheMissedHashes = new Set();
|
|
82
88
|
this.completedTasks = new Map();
|
|
83
89
|
this.waitingForTasks = [];
|
|
84
90
|
this.pendingDiscreteWorkers = new Set();
|
|
@@ -324,9 +330,12 @@ class TaskOrchestrator {
|
|
|
324
330
|
* inside DbCache.getBatch.
|
|
325
331
|
*/
|
|
326
332
|
async fetchCacheHits(tasks) {
|
|
327
|
-
const
|
|
333
|
+
const tasksToQuery = tasks.filter((t) => t.hash && !this.cacheMissedHashes.has(t.hash));
|
|
334
|
+
if (tasksToQuery.length === 0)
|
|
335
|
+
return [];
|
|
336
|
+
const batchResults = await this.cache.getBatch(tasksToQuery);
|
|
328
337
|
const cacheHits = [];
|
|
329
|
-
for (const task of
|
|
338
|
+
for (const task of tasksToQuery) {
|
|
330
339
|
const cachedResult = batchResults.get(task.hash);
|
|
331
340
|
// Replay a cached result only under the same condition it was cached
|
|
332
341
|
// under (shouldCacheTaskResult): successes always, failures only when
|
|
@@ -335,6 +344,9 @@ class TaskOrchestrator {
|
|
|
335
344
|
if (cachedResult && this.shouldCacheTaskResult(task, cachedResult.code)) {
|
|
336
345
|
cacheHits.push({ task, cachedResult });
|
|
337
346
|
}
|
|
347
|
+
else {
|
|
348
|
+
this.cacheMissedHashes.add(task.hash);
|
|
349
|
+
}
|
|
338
350
|
}
|
|
339
351
|
return cacheHits;
|
|
340
352
|
}
|
|
@@ -396,14 +408,19 @@ class TaskOrchestrator {
|
|
|
396
408
|
* The coordinator relies on this running unconditionally (when cache
|
|
397
409
|
* is enabled): tasks dispatched in step 5 via runTaskDirectly skip
|
|
398
410
|
* their own cache lookup on the assumption that this has already
|
|
399
|
-
* confirmed them as misses.
|
|
411
|
+
* confirmed them as misses. Excluding cacheMissedHashes preserves that
|
|
412
|
+
* invariant — every dispatched hash was queried exactly once — but
|
|
413
|
+
* don't add other length-based bails.
|
|
400
414
|
*/
|
|
401
415
|
async resolveCachedTasksBulk() {
|
|
402
416
|
const { scheduledTasks } = this.tasksSchedule.getAllScheduledTasks();
|
|
403
417
|
const candidates = [];
|
|
404
418
|
for (const id of scheduledTasks) {
|
|
405
419
|
const task = this.taskGraph.tasks[id];
|
|
406
|
-
if (task.hash &&
|
|
420
|
+
if (task.hash &&
|
|
421
|
+
!this.cacheMissedHashes.has(task.hash) &&
|
|
422
|
+
!task.continuous &&
|
|
423
|
+
task.cache) {
|
|
407
424
|
candidates.push(task);
|
|
408
425
|
}
|
|
409
426
|
}
|
|
@@ -714,9 +731,7 @@ class TaskOrchestrator {
|
|
|
714
731
|
? false
|
|
715
732
|
: (0, utils_1.shouldStreamOutput)(task, this.initiatingProject);
|
|
716
733
|
const env = pipeOutput
|
|
717
|
-
? (0, task_env_1.getEnvVariablesForTask)(task, taskSpecificEnv,
|
|
718
|
-
? 'true'
|
|
719
|
-
: process.env.FORCE_COLOR, this.options.skipNxCache, this.options.captureStderr, null, null)
|
|
734
|
+
? (0, task_env_1.getEnvVariablesForTask)(task, taskSpecificEnv, (0, task_env_1.getForceColorForChild)(), this.options.skipNxCache, this.options.captureStderr, null, null)
|
|
720
735
|
: (0, task_env_1.getEnvVariablesForTask)(task, taskSpecificEnv, undefined, this.options.skipNxCache, this.options.captureStderr, temporaryOutputPath, streamOutput);
|
|
721
736
|
let resolveDiscreteExit;
|
|
722
737
|
const discreteExitHandled = new Promise((r) => (resolveDiscreteExit = r));
|
|
@@ -790,7 +805,7 @@ class TaskOrchestrator {
|
|
|
790
805
|
else if (this.tuiEnabled) {
|
|
791
806
|
if (runningTask instanceof pseudo_terminal_1.PseudoTtyProcess) {
|
|
792
807
|
// This is an external of a the pseudo terminal where a task is running and can be passed to the TUI
|
|
793
|
-
this.options.lifeCycle.registerRunningTask(task.id, runningTask.
|
|
808
|
+
this.options.lifeCycle.registerRunningTask(task.id, runningTask.getPtyHandles());
|
|
794
809
|
runningTask.onOutput((output) => {
|
|
795
810
|
this.options.lifeCycle.appendTaskOutput(task.id, output, true);
|
|
796
811
|
});
|
|
@@ -839,7 +854,7 @@ class TaskOrchestrator {
|
|
|
839
854
|
if (this.tuiEnabled) {
|
|
840
855
|
if (runningTask instanceof pseudo_terminal_1.PseudoTtyProcess) {
|
|
841
856
|
// This is an external of a the pseudo terminal where a task is running and can be passed to the TUI
|
|
842
|
-
this.options.lifeCycle.registerRunningTask(task.id, runningTask.
|
|
857
|
+
this.options.lifeCycle.registerRunningTask(task.id, runningTask.getPtyHandles());
|
|
843
858
|
runningTask.onOutput((output) => {
|
|
844
859
|
this.options.lifeCycle.appendTaskOutput(task.id, output, true);
|
|
845
860
|
});
|
|
@@ -927,9 +942,7 @@ class TaskOrchestrator {
|
|
|
927
942
|
? false
|
|
928
943
|
: (0, utils_1.shouldStreamOutput)(task, this.initiatingProject);
|
|
929
944
|
let env = pipeOutput
|
|
930
|
-
? (0, task_env_1.getEnvVariablesForTask)(task, taskSpecificEnv,
|
|
931
|
-
? 'true'
|
|
932
|
-
: process.env.FORCE_COLOR, this.options.skipNxCache, this.options.captureStderr, null, null)
|
|
945
|
+
? (0, task_env_1.getEnvVariablesForTask)(task, taskSpecificEnv, (0, task_env_1.getForceColorForChild)(), this.options.skipNxCache, this.options.captureStderr, null, null)
|
|
933
946
|
: (0, task_env_1.getEnvVariablesForTask)(task, taskSpecificEnv, undefined, this.options.skipNxCache, this.options.captureStderr, temporaryOutputPath, streamOutput);
|
|
934
947
|
this.detectTaskInvocationLoop(task);
|
|
935
948
|
const childProcess = await this.runTask(task, streamOutput, env, temporaryOutputPath, pipeOutput);
|
|
@@ -7,6 +7,7 @@ const yaml_1 = require("yaml");
|
|
|
7
7
|
const semver_1 = require("semver");
|
|
8
8
|
const package_manager_1 = require("./package-manager");
|
|
9
9
|
const fileutils_1 = require("./fileutils");
|
|
10
|
+
const json_1 = require("./json");
|
|
10
11
|
const PNPM_WORKSPACE_FILE = 'pnpm-workspace.yaml';
|
|
11
12
|
/**
|
|
12
13
|
* Records build-script decisions for dependencies that are about to be
|
|
@@ -42,23 +43,24 @@ function acknowledgePnpmBuildScripts(treeOrRoot, entries) {
|
|
|
42
43
|
// A file that doesn't parse cleanly or whose root isn't a mapping is
|
|
43
44
|
// malformed for pnpm; leave it alone rather than crashing or replacing the
|
|
44
45
|
// user's content. pnpm's own error on the file is the actionable signal.
|
|
46
|
+
// Empty and comment-only files have no contents at all; setIn creates the
|
|
47
|
+
// mapping for them while keeping whatever comments they carry.
|
|
45
48
|
if (parsed.errors.length > 0 ||
|
|
46
49
|
(parsed.contents != null && !(parsed.contents instanceof yaml_1.YAMLMap))) {
|
|
47
50
|
return;
|
|
48
51
|
}
|
|
49
|
-
const doc = parsed.contents instanceof yaml_1.YAMLMap ? parsed : new yaml_1.Document({});
|
|
50
52
|
let changed = false;
|
|
51
53
|
for (const [pkg, allowed] of Object.entries(entries)) {
|
|
52
54
|
// Only a real boolean is a user decision. pnpm's non-strict installs stub
|
|
53
55
|
// undecided packages with a placeholder string ("set this to true or
|
|
54
56
|
// false"), which would fail the next strict install if left in place.
|
|
55
|
-
if (typeof
|
|
56
|
-
|
|
57
|
+
if (typeof parsed.getIn(['allowBuilds', pkg]) !== 'boolean') {
|
|
58
|
+
parsed.setIn(['allowBuilds', pkg], allowed);
|
|
57
59
|
changed = true;
|
|
58
60
|
}
|
|
59
61
|
}
|
|
60
62
|
if (changed) {
|
|
61
|
-
host.write(PNPM_WORKSPACE_FILE,
|
|
63
|
+
host.write(PNPM_WORKSPACE_FILE, parsed.toString());
|
|
62
64
|
}
|
|
63
65
|
}
|
|
64
66
|
function createHost(treeOrRoot) {
|
|
@@ -76,7 +78,7 @@ function createHost(treeOrRoot) {
|
|
|
76
78
|
exists: (p) => treeOrRoot.exists(p),
|
|
77
79
|
read: (p) => treeOrRoot.read(p, 'utf-8'),
|
|
78
80
|
write: (p, c) => treeOrRoot.write(p, c),
|
|
79
|
-
readJson: (p) =>
|
|
81
|
+
readJson: (p) => (0, json_1.parseJson)(treeOrRoot.read(p, 'utf-8')),
|
|
80
82
|
};
|
|
81
83
|
}
|
|
82
84
|
function getPnpmVersion(host) {
|
|
@@ -7,9 +7,3 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export declare function ensureAnalyticsPreferenceSet(root?: string, interactive?: boolean): Promise<'yes' | 'no' | 'unset'>;
|
|
9
9
|
export declare function promptForAnalyticsPreference(): Promise<boolean>;
|
|
10
|
-
/**
|
|
11
|
-
* Generates a deterministic workspace ID.
|
|
12
|
-
* Priority: nxCloudId > git remote URL (hashed).
|
|
13
|
-
* Returns null if neither is available (no telemetry).
|
|
14
|
-
*/
|
|
15
|
-
export declare function generateWorkspaceId(cwd?: string): string | null;
|
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ensureAnalyticsPreferenceSet = ensureAnalyticsPreferenceSet;
|
|
4
4
|
exports.promptForAnalyticsPreference = promptForAnalyticsPreference;
|
|
5
|
-
exports.generateWorkspaceId = generateWorkspaceId;
|
|
6
|
-
const crypto_1 = require("crypto");
|
|
7
|
-
const child_process_1 = require("child_process");
|
|
8
5
|
const fs_1 = require("fs");
|
|
9
6
|
const enquirer_1 = require("enquirer");
|
|
10
7
|
const path_1 = require("path");
|
|
@@ -85,51 +82,3 @@ async function saveAnalyticsPreference(root, enabled) {
|
|
|
85
82
|
// Silently fail - don't block user's command
|
|
86
83
|
}
|
|
87
84
|
}
|
|
88
|
-
/**
|
|
89
|
-
* Generates a deterministic workspace ID.
|
|
90
|
-
* Priority: nxCloudId > git remote URL (hashed).
|
|
91
|
-
* Returns null if neither is available (no telemetry).
|
|
92
|
-
*/
|
|
93
|
-
function generateWorkspaceId(cwd) {
|
|
94
|
-
const root = cwd ?? workspace_root_1.workspaceRoot;
|
|
95
|
-
// Use nxCloudId if available — most stable identifier
|
|
96
|
-
const nxJson = (0, nx_json_1.readNxJson)(root);
|
|
97
|
-
const nxCloudId = nxJson?.nxCloudId ?? nxJson?.nxCloudAccessToken;
|
|
98
|
-
if (nxCloudId) {
|
|
99
|
-
return nxCloudId;
|
|
100
|
-
}
|
|
101
|
-
// Fall back to git remote URL hash
|
|
102
|
-
try {
|
|
103
|
-
const remoteUrl = (0, child_process_1.execSync)('git remote get-url origin', {
|
|
104
|
-
stdio: 'pipe',
|
|
105
|
-
cwd: root,
|
|
106
|
-
windowsHide: true,
|
|
107
|
-
})
|
|
108
|
-
.toString()
|
|
109
|
-
.trim();
|
|
110
|
-
if (remoteUrl) {
|
|
111
|
-
return (0, crypto_1.createHash)('sha256').update(remoteUrl).digest('hex').slice(0, 32);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
catch {
|
|
115
|
-
// No git remote available
|
|
116
|
-
}
|
|
117
|
-
// Fall back to first commit SHA — already a hash
|
|
118
|
-
try {
|
|
119
|
-
const firstCommit = (0, child_process_1.execSync)('git rev-list --max-parents=0 HEAD', {
|
|
120
|
-
stdio: 'pipe',
|
|
121
|
-
cwd: root,
|
|
122
|
-
windowsHide: true,
|
|
123
|
-
})
|
|
124
|
-
.toString()
|
|
125
|
-
.trim()
|
|
126
|
-
.split('\n')[0];
|
|
127
|
-
if (firstCommit) {
|
|
128
|
-
return firstCommit;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
catch {
|
|
132
|
-
// Not a git repo
|
|
133
|
-
}
|
|
134
|
-
return null;
|
|
135
|
-
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Tree } from '../../generators/tree';
|
|
2
|
+
import type { CatalogDefinitions } from './types';
|
|
3
|
+
export declare function readBunCatalogDefinitions(filename: string, treeOrRoot: Tree | string, cache: Map<string, CatalogDefinitions | null>): CatalogDefinitions | null;
|
|
4
|
+
export declare function updateBunCatalogVersionsInFile(filename: string, treeOrRoot: Tree | string, updates: Array<{
|
|
5
|
+
packageName: string;
|
|
6
|
+
version: string;
|
|
7
|
+
catalogName?: string;
|
|
8
|
+
}>): void;
|