nx 22.7.0-rc.1 → 22.7.0

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.
@@ -3,12 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.yargsInitCommand = void 0;
4
4
  const handle_import_1 = require("../../utils/handle-import");
5
5
  const shared_options_1 = require("../yargs-utils/shared-options");
6
- const native_1 = require("../../native");
7
- const ai_output_1 = require("./utils/ai-output");
8
- const ab_testing_1 = require("../../utils/ab-testing");
9
- const versions_1 = require("../../utils/versions");
10
- const is_ci_1 = require("../../utils/is-ci");
11
- const package_manager_1 = require("../../utils/package-manager");
12
6
  exports.yargsInitCommand = {
13
7
  command: 'init',
14
8
  describe: 'Adds Nx to any type of workspace. It installs nx, creates an nx.json configuration file and optionally sets up remote caching. For more info, check https://nx.dev/recipes/adopting-nx.',
@@ -33,70 +27,15 @@ exports.yargsInitCommand = {
33
27
  return;
34
28
  throw error;
35
29
  });
36
- const aiAgent = (0, native_1.isAiAgent)();
37
- (0, ab_testing_1.recordStat)({
38
- command: 'init',
39
- nxVersion: versions_1.nxVersion,
40
- useCloud: false,
41
- meta: {
42
- type: 'start',
43
- nodeVersion: process.versions.node,
44
- os: process.platform,
45
- packageManager: (0, package_manager_1.detectPackageManager)(),
46
- aiAgent,
47
- isCI: (0, is_ci_1.isCI)(),
48
- },
49
- });
50
- try {
51
- const useV2 = await isInitV2();
52
- if (useV2) {
53
- // v2 records its own complete event with richer context
54
- await require('./init-v2').initHandler(args);
55
- }
56
- else {
57
- await require('./init-v1').initHandler(args);
58
- await (0, ab_testing_1.recordStat)({
59
- command: 'init',
60
- nxVersion: versions_1.nxVersion,
61
- useCloud: false,
62
- meta: {
63
- type: 'complete',
64
- nodeVersion: process.versions.node,
65
- os: process.platform,
66
- packageManager: (0, package_manager_1.detectPackageManager)(),
67
- aiAgent,
68
- isCI: (0, is_ci_1.isCI)(),
69
- },
70
- });
71
- }
72
- process.exit(0);
30
+ const useV2 = await isInitV2();
31
+ if (useV2) {
32
+ await require('./init-v2').initHandler(args);
73
33
  }
74
- catch (error) {
75
- const errorMessage = error instanceof Error ? error.message : String(error);
76
- const errorCode = (0, ai_output_1.determineErrorCode)(error);
77
- await (0, ab_testing_1.recordStat)({
78
- command: 'init',
79
- nxVersion: versions_1.nxVersion,
80
- useCloud: false,
81
- meta: {
82
- type: 'error',
83
- errorCode,
84
- errorMessage: errorMessage.substring(0, 250),
85
- aiAgent,
86
- },
87
- });
88
- // Output structured error for AI agents
89
- if (aiAgent) {
90
- const errorLogPath = (0, ai_output_1.writeErrorLog)(error);
91
- (0, ai_output_1.writeAiOutput)((0, ai_output_1.buildErrorResult)(errorMessage, errorCode, errorLogPath));
92
- }
93
- else {
94
- // Ensure the cursor is always restored just in case the user has bailed during interactive prompts
95
- // Skip for AI agents to avoid corrupting NDJSON output
96
- process.stdout.write('\x1b[?25h');
97
- }
98
- process.exit(1);
34
+ else {
35
+ // v1 path retained for `NX_ADD_PLUGINS=false`; slated for removal.
36
+ await require('./init-v1').initHandler(args);
99
37
  }
38
+ process.exit(0);
100
39
  },
101
40
  };
102
41
  async function isInitV2() {
@@ -35,8 +35,14 @@ function installPluginPackages(repoRoot, pmc = (0, package_manager_1.getPackageM
35
35
  nxJson.installation.plugins[plugin] = versions_1.nxVersion;
36
36
  }
37
37
  (0, fileutils_1.writeJsonFile)((0, path_1.join)(repoRoot, 'nx.json'), nxJson);
38
- // Invoking nx wrapper to install plugins.
39
- (0, child_process_1.runNxSync)('--version', { stdio: 'ignore' });
38
+ try {
39
+ (0, child_process_1.runNxSync)('--version', { stdio: 'pipe' });
40
+ }
41
+ catch (e) {
42
+ if (e?.stderr)
43
+ process.stderr.write(e.stderr);
44
+ throw e;
45
+ }
40
46
  }
41
47
  }
42
48
  /**
@@ -8,6 +8,13 @@ export declare function createNxJsonFromTurboJson(turboJson: Record<string, any>
8
8
  export declare function addDepsToPackageJson(repoRoot: string, additionalPackages?: string[]): void;
9
9
  export declare function updateGitIgnore(root: string): void;
10
10
  export declare function runInstall(repoRoot: string, pmc?: PackageManagerCommands): void;
11
+ /**
12
+ * Coerce any thrown value into a non-empty telemetry string. The naive
13
+ * `error.message || String(error)` yields "" for bare `new Error()`.
14
+ */
15
+ export declare function toErrorString(error: unknown): string;
16
+ export declare function readErrorStderr(error: unknown): string;
17
+ export declare function extractErrorName(error: unknown, stderr: string): string;
11
18
  export declare function initCloud(installationSource: 'nx-init' | 'nx-init-angular' | 'nx-init-monorepo' | 'nx-init-nest' | 'nx-init-npm-repo' | 'nx-init-turborepo'): Promise<void>;
12
19
  export declare function setNeverConnectToCloud(repoRoot: string): void;
13
20
  export declare function addVsCodeRecommendedExtensions(repoRoot: string, extensions: string[]): void;
@@ -5,6 +5,9 @@ exports.createNxJsonFromTurboJson = createNxJsonFromTurboJson;
5
5
  exports.addDepsToPackageJson = addDepsToPackageJson;
6
6
  exports.updateGitIgnore = updateGitIgnore;
7
7
  exports.runInstall = runInstall;
8
+ exports.toErrorString = toErrorString;
9
+ exports.readErrorStderr = readErrorStderr;
10
+ exports.extractErrorName = extractErrorName;
8
11
  exports.initCloud = initCloud;
9
12
  exports.setNeverConnectToCloud = setNeverConnectToCloud;
10
13
  exports.addVsCodeRecommendedExtensions = addVsCodeRecommendedExtensions;
@@ -189,11 +192,74 @@ function updateGitIgnore(root) {
189
192
  catch { }
190
193
  }
191
194
  function runInstall(repoRoot, pmc = (0, package_manager_1.getPackageManagerCommand)()) {
192
- (0, child_process_1.execSync)(pmc.install, {
193
- stdio: ['ignore', 'ignore', 'inherit'],
194
- cwd: repoRoot,
195
- windowsHide: true,
196
- });
195
+ try {
196
+ (0, child_process_1.execSync)(pmc.install, {
197
+ stdio: ['ignore', 'ignore', 'pipe'],
198
+ encoding: 'utf8',
199
+ cwd: repoRoot,
200
+ windowsHide: true,
201
+ });
202
+ }
203
+ catch (e) {
204
+ if (e?.stderr)
205
+ process.stderr.write(e.stderr);
206
+ throw e;
207
+ }
208
+ }
209
+ /**
210
+ * Coerce any thrown value into a non-empty telemetry string. The naive
211
+ * `error.message || String(error)` yields "" for bare `new Error()`.
212
+ */
213
+ function toErrorString(error) {
214
+ if (error == null)
215
+ return 'Unknown error';
216
+ if (error instanceof Error) {
217
+ if (error.message)
218
+ return error.message;
219
+ if (error.name && error.name !== 'Error')
220
+ return error.name;
221
+ // Drop `stack` — large and contains absolute paths (PII).
222
+ const keys = Object.getOwnPropertyNames(error).filter((k) => k !== 'stack');
223
+ const serialized = safeJsonStringify(error, keys);
224
+ if (serialized && serialized !== '{}')
225
+ return serialized;
226
+ return error.name || 'Error';
227
+ }
228
+ if (typeof error === 'object') {
229
+ const serialized = safeJsonStringify(error);
230
+ if (serialized && serialized !== '{}')
231
+ return serialized;
232
+ return Object.prototype.toString.call(error);
233
+ }
234
+ return String(error);
235
+ }
236
+ function readErrorStderr(error) {
237
+ const raw = error?.stderr;
238
+ if (typeof raw === 'string')
239
+ return raw;
240
+ if (raw && typeof raw.toString === 'function') {
241
+ return raw.toString('utf8');
242
+ }
243
+ return '';
244
+ }
245
+ function extractErrorName(error, stderr) {
246
+ const nodeCode = error?.code;
247
+ if (typeof nodeCode === 'string')
248
+ return nodeCode;
249
+ const m = stderr.match(/\b(E[A-Z0-9_]{2,}|ERR_[A-Z0-9_]+)\b/);
250
+ if (m)
251
+ return m[1];
252
+ if (error instanceof Error)
253
+ return error.name;
254
+ return typeof error;
255
+ }
256
+ function safeJsonStringify(value, replacer) {
257
+ try {
258
+ return JSON.stringify(value, replacer);
259
+ }
260
+ catch {
261
+ return '';
262
+ }
197
263
  }
198
264
  async function initCloud(installationSource) {
199
265
  const token = await (0, connect_to_nx_cloud_2.connectWorkspaceToCloud)({
@@ -60,8 +60,58 @@ async function initHandler(options, inner = false) {
60
60
  return initHandlerImpl(options);
61
61
  }
62
62
  }
63
+ async function recordInitError(error, baseMeta) {
64
+ const errorMessage = (0, utils_1.toErrorString)(error);
65
+ const errorCode = (0, ai_output_1.determineErrorCode)(error);
66
+ const stderr = (0, utils_1.readErrorStderr)(error).trim();
67
+ const telemetryMessage = (stderr ? `${errorMessage} | stderr: ${stderr.slice(-250)}` : errorMessage).slice(0, 500);
68
+ const errorName = (0, utils_1.extractErrorName)(error, stderr);
69
+ await (0, ab_testing_1.recordStat)({
70
+ command: 'init',
71
+ nxVersion: versions_1.nxVersion,
72
+ useCloud: false,
73
+ meta: {
74
+ type: 'error',
75
+ errorCode,
76
+ errorName,
77
+ errorMessage: telemetryMessage,
78
+ ...baseMeta,
79
+ },
80
+ });
81
+ if (baseMeta.aiAgent) {
82
+ const errorLogPath = (0, ai_output_1.writeErrorLog)(error);
83
+ (0, ai_output_1.writeAiOutput)((0, ai_output_1.buildErrorResult)(errorMessage, errorCode, errorLogPath));
84
+ }
85
+ else {
86
+ // Restore the cursor in case the user bailed during an interactive
87
+ // prompt. Skip for AI agents — it would corrupt NDJSON output.
88
+ process.stdout.write('\x1b[?25h');
89
+ }
90
+ process.exit(1);
91
+ }
63
92
  async function initHandlerImpl(options) {
64
93
  process.env.NX_RUNNING_NX_INIT = 'true';
94
+ const baseMeta = {
95
+ nodeVersion: process.versions.node,
96
+ os: process.platform,
97
+ packageManager: (0, package_manager_2.detectPackageManager)(),
98
+ aiAgent: (0, native_1.isAiAgent)(),
99
+ isCI: (0, is_ci_1.isCI)(),
100
+ };
101
+ (0, ab_testing_1.recordStat)({
102
+ command: 'init',
103
+ nxVersion: versions_1.nxVersion,
104
+ useCloud: false,
105
+ meta: { type: 'start', ...baseMeta },
106
+ });
107
+ try {
108
+ return await runInit(options, baseMeta);
109
+ }
110
+ catch (error) {
111
+ await recordInitError(error, baseMeta);
112
+ }
113
+ }
114
+ async function runInit(options, baseMeta) {
65
115
  const version = process.env.NX_VERSION ?? ((0, semver_1.prerelease)(versions_1.nxVersion) ? versions_1.nxVersion : 'latest');
66
116
  if (process.env.NX_VERSION) {
67
117
  output_1.output.log({ title: `Using version ${process.env.NX_VERSION}` });
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.yargsViewLogsCommand = exports.yargsConnectCommand = void 0;
4
4
  const handle_import_1 = require("../../../utils/handle-import");
5
5
  const documentation_1 = require("../../yargs-utils/documentation");
6
- const versions_1 = require("../../../utils/versions");
7
6
  const shared_options_1 = require("../../yargs-utils/shared-options");
8
7
  exports.yargsConnectCommand = {
9
8
  command: 'connect',
@@ -13,11 +12,6 @@ exports.yargsConnectCommand = {
13
12
  handler: async (args) => {
14
13
  const checkRemote = process.env.NX_SKIP_CHECK_REMOTE !== 'true';
15
14
  await (await (0, handle_import_1.handleImport)('./connect-to-nx-cloud.js', __dirname)).connectToNxCloudCommand({ ...args, checkRemote });
16
- await (await (0, handle_import_1.handleImport)('../../../utils/ab-testing.js', __dirname)).recordStat({
17
- command: 'connect',
18
- nxVersion: versions_1.nxVersion,
19
- useCloud: true,
20
- });
21
15
  process.exit(0);
22
16
  },
23
17
  };
@@ -64,6 +64,61 @@ async function connectWorkspaceToCloud(options, directory = workspace_root_1.wor
64
64
  return accessToken;
65
65
  }
66
66
  async function connectToNxCloudCommand(options, command) {
67
+ // `connectToNxCloudWithPrompt` (called from `migrate`) records its own stat; skip here to avoid double-counting.
68
+ const selfRecord = !command;
69
+ const baseMeta = {
70
+ nodeVersion: process.versions.node,
71
+ os: process.platform,
72
+ packageManager: (0, package_manager_1.detectPackageManager)(),
73
+ aiAgent: (0, native_1.isAiAgent)(),
74
+ isCI: (0, is_ci_1.isCI)(),
75
+ };
76
+ if (selfRecord) {
77
+ await (0, ab_testing_1.recordStat)({
78
+ command: 'connect',
79
+ nxVersion: versions_1.nxVersion,
80
+ useCloud: true,
81
+ meta: { type: 'start', ...baseMeta },
82
+ });
83
+ }
84
+ try {
85
+ const result = await runConnectToNxCloud(options, command);
86
+ if (selfRecord) {
87
+ await (0, ab_testing_1.recordStat)({
88
+ command: 'connect',
89
+ nxVersion: versions_1.nxVersion,
90
+ useCloud: result,
91
+ meta: { type: 'complete', ...baseMeta },
92
+ });
93
+ }
94
+ return result;
95
+ }
96
+ catch (error) {
97
+ if (selfRecord) {
98
+ const message = (error instanceof Error && error.message) ||
99
+ String(error ?? 'Unknown error');
100
+ const errorName = typeof error?.code === 'string'
101
+ ? error.code
102
+ : error instanceof Error
103
+ ? error.name
104
+ : typeof error;
105
+ await (0, ab_testing_1.recordStat)({
106
+ command: 'connect',
107
+ nxVersion: versions_1.nxVersion,
108
+ useCloud: false,
109
+ meta: {
110
+ type: 'error',
111
+ errorCode: 'UNKNOWN',
112
+ errorName,
113
+ errorMessage: message.slice(0, 500),
114
+ ...baseMeta,
115
+ },
116
+ });
117
+ }
118
+ throw error;
119
+ }
120
+ }
121
+ async function runConnectToNxCloud(options, command) {
67
122
  const nxJson = (0, configuration_1.readNxJson)();
68
123
  const installationSource = process.env.NX_CONSOLE
69
124
  ? 'nx-console'
@@ -103,7 +103,8 @@ function parseRunOneOptions(cwd, parsedArgs, projectGraph, nxJson) {
103
103
  let project;
104
104
  let target;
105
105
  let configuration;
106
- if (parsedArgs[PROJECT_TARGET_CONFIG]?.lastIndexOf(':') > 0) {
106
+ if (typeof parsedArgs[PROJECT_TARGET_CONFIG] === 'string' &&
107
+ parsedArgs[PROJECT_TARGET_CONFIG].lastIndexOf(':') > 0) {
107
108
  // run case
108
109
  [project, target, configuration] = (0, split_target_1.splitTarget)(parsedArgs[PROJECT_TARGET_CONFIG], projectGraph, { currentProject: defaultProjectName });
109
110
  // this is to account for "nx npmscript:dev"
@@ -115,7 +116,7 @@ function parseRunOneOptions(cwd, parsedArgs, projectGraph, nxJson) {
115
116
  else if (parsedArgs.target) {
116
117
  target = parsedArgs.target;
117
118
  }
118
- else if (parsedArgs[PROJECT_TARGET_CONFIG]) {
119
+ else if (typeof parsedArgs[PROJECT_TARGET_CONFIG] === 'string') {
119
120
  // If project:target:configuration exists but has no colon, check if it's a project with run target
120
121
  if (projectGraph.nodes[parsedArgs[PROJECT_TARGET_CONFIG]]?.data?.targets?.run) {
121
122
  target = 'run';
@@ -78,6 +78,8 @@ export declare function withRunOneOptions(yargs: Argv): Argv<{
78
78
  outputStyle: OutputStyle;
79
79
  } & RunOptions & {
80
80
  project: string;
81
+ } & {
82
+ target: string;
81
83
  } & {
82
84
  help: boolean;
83
85
  }>;
@@ -316,6 +316,13 @@ function withRunOneOptions(yargs) {
316
316
  .option('project', {
317
317
  describe: 'Target project.',
318
318
  type: 'string',
319
+ alias: 'p',
320
+ })
321
+ .option('target', {
322
+ describe: 'Target to run. Useful when the target name contains a colon, which conflicts with the positional `project:target:configuration` form.',
323
+ type: 'string',
324
+ alias: 't',
325
+ requiresArg: true,
319
326
  })
320
327
  .option('help', {
321
328
  describe: 'Show Help.',