nx 19.3.0-beta.0 → 19.3.0-beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. package/bin/post-install.js +1 -3
  2. package/migrations.json +12 -0
  3. package/package.json +12 -12
  4. package/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +38 -13
  5. package/src/command-line/init/implementation/utils.js +15 -2
  6. package/src/command-line/release/command-object.js +1 -1
  7. package/src/command-line/release/utils/git.d.ts +2 -2
  8. package/src/command-line/release/utils/git.js +19 -11
  9. package/src/command-line/release/version.d.ts +1 -1
  10. package/src/command-line/release/version.js +1 -1
  11. package/src/command-line/yargs-utils/shared-options.d.ts +1 -1
  12. package/src/core/graph/main.js +1 -1
  13. package/src/daemon/client/client.js +0 -2
  14. package/src/executors/run-commands/run-commands.impl.d.ts +6 -2
  15. package/src/executors/run-commands/run-commands.impl.js +52 -25
  16. package/src/executors/run-commands/schema.json +5 -2
  17. package/src/generators/utils/project-configuration.js +1 -1
  18. package/src/hasher/file-hasher.js +1 -1
  19. package/src/migrations/update-19-2-4/set-project-name.d.ts +2 -0
  20. package/src/migrations/update-19-2-4/set-project-name.js +34 -0
  21. package/src/plugins/js/package-json/create-package-json.js +3 -0
  22. package/src/plugins/js/project-graph/build-dependencies/target-project-locator.js +9 -4
  23. package/src/plugins/package-json-workspaces/create-nodes.d.ts +2 -2
  24. package/src/plugins/package-json-workspaces/create-nodes.js +34 -11
  25. package/src/plugins/project-json/build-nodes/project-json.d.ts +1 -0
  26. package/src/plugins/project-json/build-nodes/project-json.js +16 -4
  27. package/src/project-graph/error-types.js +10 -0
  28. package/src/project-graph/file-utils.js +1 -1
  29. package/src/project-graph/plugins/internal-api.js +1 -1
  30. package/src/project-graph/utils/normalize-project-nodes.js +24 -6
  31. package/src/project-graph/utils/project-configuration-utils.js +9 -1
  32. package/src/tasks-runner/create-task-graph.js +32 -33
  33. package/src/utils/ab-testing.d.ts +1 -1
  34. package/src/utils/find-matching-projects.js +13 -1
  35. package/src/utils/package-json.d.ts +1 -0
@@ -19,7 +19,6 @@ const nx_json_1 = require("../../config/nx-json");
19
19
  const daemon_socket_messenger_1 = require("./daemon-socket-messenger");
20
20
  const cache_1 = require("../cache");
21
21
  const error_types_1 = require("../../project-graph/error-types");
22
- const dotenv_1 = require("../../utils/dotenv");
23
22
  const get_nx_workspace_files_1 = require("../message-types/get-nx-workspace-files");
24
23
  const get_context_file_data_1 = require("../message-types/get-context-file-data");
25
24
  const get_files_in_directory_1 = require("../message-types/get-files-in-directory");
@@ -41,7 +40,6 @@ class DaemonClient {
41
40
  this._daemonReady = null;
42
41
  this._out = null;
43
42
  this._err = null;
44
- (0, dotenv_1.loadRootEnvFiles)(workspace_root_1.workspaceRoot);
45
43
  try {
46
44
  this.nxJson = (0, configuration_1.readNxJson)();
47
45
  }
@@ -19,7 +19,7 @@ export interface RunCommandsOptions extends Json {
19
19
  } | string)[];
20
20
  color?: boolean;
21
21
  parallel?: boolean;
22
- readyWhen?: string;
22
+ readyWhen?: string | string[];
23
23
  cwd?: string;
24
24
  env?: Record<string, string>;
25
25
  forwardAllArgs?: boolean;
@@ -42,9 +42,13 @@ export interface NormalizedRunCommandsOptions extends RunCommandsOptions {
42
42
  [k: string]: any;
43
43
  };
44
44
  unparsedCommandArgs?: {
45
- [k: string]: string;
45
+ [k: string]: string | string[];
46
46
  };
47
47
  args?: string;
48
+ readyWhenStatus: {
49
+ stringToMatch: string;
50
+ found: boolean;
51
+ }[];
48
52
  }
49
53
  export default function (options: RunCommandsOptions, context: ExecutorContext): Promise<{
50
54
  success: boolean;
@@ -29,7 +29,9 @@ const propKeys = [
29
29
  'command',
30
30
  'commands',
31
31
  'color',
32
+ 'no-color',
32
33
  'parallel',
34
+ 'no-parallel',
33
35
  'readyWhen',
34
36
  'cwd',
35
37
  'args',
@@ -48,7 +50,7 @@ async function default_1(options, context) {
48
50
  await loadEnvVars(options.envFile);
49
51
  }
50
52
  const normalized = normalizeOptions(options);
51
- if (options.readyWhen && !options.parallel) {
53
+ if (normalized.readyWhenStatus.length && !normalized.parallel) {
52
54
  throw new Error('ERROR: Bad executor config for run-commands - "readyWhen" can only be used when "parallel=true".');
53
55
  }
54
56
  if (options.commands.find((c) => c.prefix || c.color || c.bgColor) &&
@@ -70,12 +72,12 @@ async function default_1(options, context) {
70
72
  }
71
73
  exports.default = default_1;
72
74
  async function runInParallel(options, context) {
73
- const procs = options.commands.map((c) => createProcess(null, c, options.readyWhen, options.color, calculateCwd(options.cwd, context), options.env ?? {}, true, options.usePty, options.streamOutput, options.tty).then((result) => ({
75
+ const procs = options.commands.map((c) => createProcess(null, c, options.readyWhenStatus, options.color, calculateCwd(options.cwd, context), options.env ?? {}, true, options.usePty, options.streamOutput, options.tty).then((result) => ({
74
76
  result,
75
77
  command: c.command,
76
78
  })));
77
79
  let terminalOutput = '';
78
- if (options.readyWhen) {
80
+ if (options.readyWhenStatus.length) {
79
81
  const r = await Promise.race(procs);
80
82
  terminalOutput += r.result.terminalOutput;
81
83
  if (!r.result.success) {
@@ -116,9 +118,21 @@ async function runInParallel(options, context) {
116
118
  }
117
119
  }
118
120
  function normalizeOptions(options) {
121
+ if (options.readyWhen && typeof options.readyWhen === 'string') {
122
+ options.readyWhenStatus = [
123
+ { stringToMatch: options.readyWhen, found: false },
124
+ ];
125
+ }
126
+ else {
127
+ options.readyWhenStatus =
128
+ options.readyWhen?.map((stringToMatch) => ({
129
+ stringToMatch,
130
+ found: false,
131
+ })) ?? [];
132
+ }
119
133
  if (options.command) {
120
134
  options.commands = [{ command: options.command }];
121
- options.parallel = !!options.readyWhen;
135
+ options.parallel = options.readyWhenStatus?.length > 0;
122
136
  }
123
137
  else {
124
138
  options.commands = options.commands.map((c) => typeof c === 'string' ? { command: c } : c);
@@ -131,6 +145,7 @@ function normalizeOptions(options) {
131
145
  'parse-numbers': false,
132
146
  'parse-positional-numbers': false,
133
147
  'dot-notation': false,
148
+ 'camel-case-expansion': false,
134
149
  },
135
150
  });
136
151
  options.unknownOptions = Object.keys(options)
@@ -147,7 +162,7 @@ async function runSerially(options, context) {
147
162
  pseudoTerminal ??= pseudo_terminal_1.PseudoTerminal.isSupported() ? (0, pseudo_terminal_1.getPseudoTerminal)() : null;
148
163
  let terminalOutput = '';
149
164
  for (const c of options.commands) {
150
- const result = await createProcess(pseudoTerminal, c, undefined, options.color, calculateCwd(options.cwd, context), options.env ?? {}, false, options.usePty, options.streamOutput, options.tty);
165
+ const result = await createProcess(pseudoTerminal, c, [], options.color, calculateCwd(options.cwd, context), options.env ?? {}, false, options.usePty, options.streamOutput, options.tty);
151
166
  terminalOutput += result.terminalOutput;
152
167
  if (!result.success) {
153
168
  const output = `Warning: command "${c.command}" exited with non-zero status code`;
@@ -160,13 +175,14 @@ async function runSerially(options, context) {
160
175
  }
161
176
  return { success: true, terminalOutput };
162
177
  }
163
- async function createProcess(pseudoTerminal, commandConfig, readyWhen, color, cwd, env, isParallel, usePty = true, streamOutput = true, tty) {
178
+ async function createProcess(pseudoTerminal, commandConfig, readyWhenStatus = [], color, cwd, env, isParallel, usePty = true, streamOutput = true, tty) {
164
179
  env = processEnv(color, cwd, env);
165
180
  // The rust runCommand is always a tty, so it will not look nice in parallel and if we need prefixes
166
181
  // currently does not work properly in windows
167
182
  if (pseudoTerminal &&
168
183
  process.env.NX_NATIVE_COMMAND_RUNNER !== 'false' &&
169
184
  !commandConfig.prefix &&
185
+ readyWhenStatus.length === 0 &&
170
186
  !isParallel &&
171
187
  usePty) {
172
188
  let terminalOutput = chalk.dim('> ') + commandConfig.command + '\r\n\r\n';
@@ -183,9 +199,6 @@ async function createProcess(pseudoTerminal, commandConfig, readyWhen, color, cw
183
199
  return new Promise((res) => {
184
200
  cp.onOutput((output) => {
185
201
  terminalOutput += output;
186
- if (readyWhen && output.indexOf(readyWhen) > -1) {
187
- res({ success: true, terminalOutput });
188
- }
189
202
  });
190
203
  cp.onExit((code) => {
191
204
  if (code >= 128) {
@@ -197,9 +210,9 @@ async function createProcess(pseudoTerminal, commandConfig, readyWhen, color, cw
197
210
  });
198
211
  });
199
212
  }
200
- return nodeProcess(commandConfig, cwd, env, readyWhen, streamOutput);
213
+ return nodeProcess(commandConfig, cwd, env, readyWhenStatus, streamOutput);
201
214
  }
202
- function nodeProcess(commandConfig, cwd, env, readyWhen, streamOutput = true) {
215
+ function nodeProcess(commandConfig, cwd, env, readyWhenStatus, streamOutput = true) {
203
216
  let terminalOutput = chalk.dim('> ') + commandConfig.command + '\r\n\r\n';
204
217
  if (streamOutput) {
205
218
  process.stdout.write(terminalOutput);
@@ -217,7 +230,7 @@ function nodeProcess(commandConfig, cwd, env, readyWhen, streamOutput = true) {
217
230
  if (streamOutput) {
218
231
  process.stdout.write(output);
219
232
  }
220
- if (readyWhen && data.toString().indexOf(readyWhen) > -1) {
233
+ if (readyWhenStatus.length && isReady(readyWhenStatus, data.toString())) {
221
234
  res({ success: true, terminalOutput });
222
235
  }
223
236
  });
@@ -227,7 +240,7 @@ function nodeProcess(commandConfig, cwd, env, readyWhen, streamOutput = true) {
227
240
  if (streamOutput) {
228
241
  process.stderr.write(output);
229
242
  }
230
- if (readyWhen && err.toString().indexOf(readyWhen) > -1) {
243
+ if (readyWhenStatus.length && isReady(readyWhenStatus, err.toString())) {
231
244
  res({ success: true, terminalOutput });
232
245
  }
233
246
  });
@@ -241,7 +254,7 @@ function nodeProcess(commandConfig, cwd, env, readyWhen, streamOutput = true) {
241
254
  });
242
255
  childProcess.on('exit', (code) => {
243
256
  childProcesses.delete(childProcess);
244
- if (!readyWhen) {
257
+ if (!readyWhenStatus.length || isReady(readyWhenStatus)) {
245
258
  res({ success: code === 0, terminalOutput });
246
259
  }
247
260
  });
@@ -294,20 +307,21 @@ function interpolateArgsIntoCommand(command, opts, forwardAllArgs) {
294
307
  else if (forwardAllArgs) {
295
308
  let args = '';
296
309
  if (Object.keys(opts.unknownOptions ?? {}).length > 0) {
297
- args +=
298
- ' ' +
299
- Object.keys(opts.unknownOptions)
300
- .filter((k) => typeof opts.unknownOptions[k] !== 'object' &&
301
- opts.parsedArgs[k] === opts.unknownOptions[k])
302
- .map((k) => `--${k}=${opts.unknownOptions[k]}`)
303
- .map(wrapArgIntoQuotesIfNeeded)
304
- .join(' ');
310
+ const unknownOptionsArgs = Object.keys(opts.unknownOptions)
311
+ .filter((k) => typeof opts.unknownOptions[k] !== 'object' &&
312
+ opts.parsedArgs[k] === opts.unknownOptions[k])
313
+ .map((k) => `--${k}=${opts.unknownOptions[k]}`)
314
+ .map(wrapArgIntoQuotesIfNeeded)
315
+ .join(' ');
316
+ if (unknownOptionsArgs) {
317
+ args += ` ${unknownOptionsArgs}`;
318
+ }
305
319
  }
306
320
  if (opts.args) {
307
321
  args += ` ${opts.args}`;
308
322
  }
309
323
  if (opts.__unparsed__?.length > 0) {
310
- const filterdParsedOptions = filterPropKeysFromUnParsedOptions(opts.__unparsed__, opts.unparsedCommandArgs);
324
+ const filterdParsedOptions = filterPropKeysFromUnParsedOptions(opts.__unparsed__, opts.parsedArgs);
311
325
  if (filterdParsedOptions.length > 0) {
312
326
  args += ` ${filterdParsedOptions
313
327
  .map(wrapArgIntoQuotesIfNeeded)
@@ -335,13 +349,14 @@ function parseArgs(unparsedCommandArgs, unknownOptions, args) {
335
349
  * @param unparsedCommandArgs e.g. { prop1: 'value1', prop2: 'value2', args: 'test'}
336
350
  * @returns filtered options that are not part of the propKeys array e.g. ['--prop1', 'value1', '--prop2=value2']
337
351
  */
338
- function filterPropKeysFromUnParsedOptions(__unparsed__, unparsedCommandArgs = {}) {
352
+ function filterPropKeysFromUnParsedOptions(__unparsed__, parseArgs = {}) {
339
353
  const parsedOptions = [];
340
354
  for (let index = 0; index < __unparsed__.length; index++) {
341
355
  const element = __unparsed__[index];
342
356
  if (element.startsWith('--')) {
343
357
  const key = element.replace('--', '');
344
358
  if (element.includes('=')) {
359
+ // key can be in the format of --key=value or --key.subkey=value (e.g. env.foo=bar)
345
360
  if (!propKeys.includes(key.split('=')[0].split('.')[0])) {
346
361
  // check if the key is part of the propKeys array
347
362
  parsedOptions.push(element);
@@ -351,7 +366,8 @@ function filterPropKeysFromUnParsedOptions(__unparsed__, unparsedCommandArgs = {
351
366
  // check if the next element is a value for the key
352
367
  if (propKeys.includes(key)) {
353
368
  if (index + 1 < __unparsed__.length &&
354
- __unparsed__[index + 1] === unparsedCommandArgs[key]) {
369
+ parseArgs[key] &&
370
+ __unparsed__[index + 1].toString() === parseArgs[key].toString()) {
355
371
  index++; // skip the next element
356
372
  }
357
373
  }
@@ -437,3 +453,14 @@ function wrapArgIntoQuotesIfNeeded(arg) {
437
453
  return arg;
438
454
  }
439
455
  }
456
+ function isReady(readyWhenStatus = [], data) {
457
+ if (data) {
458
+ for (const readyWhenElement of readyWhenStatus) {
459
+ if (data.toString().indexOf(readyWhenElement.stringToMatch) > -1) {
460
+ readyWhenElement.found = true;
461
+ break;
462
+ }
463
+ }
464
+ }
465
+ return readyWhenStatus.every((readyWhenElement) => readyWhenElement.found);
466
+ }
@@ -95,8 +95,11 @@
95
95
  "x-priority": "important"
96
96
  },
97
97
  "readyWhen": {
98
- "type": "string",
99
- "description": "String to appear in `stdout` or `stderr` that indicates that the task is done. When running multiple commands, this option can only be used when `parallel` is set to `true`. If not specified, the task is done when all the child processes complete."
98
+ "description": "String or array of strings to appear in `stdout` or `stderr` that indicate that the task is done. When running multiple commands, this option can only be used when `parallel` is set to `true`. If not specified, the task is done when all the child processes complete.",
99
+ "oneOf": [
100
+ { "type": "string" },
101
+ { "type": "array", "items": { "type": "string" } }
102
+ ]
100
103
  },
101
104
  "args": {
102
105
  "oneOf": [
@@ -147,7 +147,7 @@ function readAndCombineAllProjectConfigurations(tree) {
147
147
  }
148
148
  else if ((0, path_1.basename)(projectFile) === 'package.json') {
149
149
  const packageJson = (0, json_1.readJson)(tree, projectFile);
150
- const config = (0, package_json_workspaces_1.buildProjectConfigurationFromPackageJson)(packageJson, projectFile, (0, nx_json_1.readNxJson)(tree));
150
+ const config = (0, package_json_workspaces_1.buildProjectConfigurationFromPackageJson)(packageJson, tree.root, projectFile, (0, nx_json_1.readNxJson)(tree));
151
151
  if (!rootMap[config.root]) {
152
152
  (0, project_configuration_utils_1.mergeProjectConfigurationIntoRootMap)(rootMap,
153
153
  // Inferred targets, tags, etc don't show up when running generators
@@ -10,7 +10,7 @@ exports.hashArray = hashArray;
10
10
  function hashObject(obj) {
11
11
  const { hashArray } = require('../native');
12
12
  const parts = [];
13
- for (const key of Object.keys(obj).sort()) {
13
+ for (const key of Object.keys(obj ?? {}).sort()) {
14
14
  parts.push(key);
15
15
  parts.push(JSON.stringify(obj[key]));
16
16
  }
@@ -0,0 +1,2 @@
1
+ import { Tree } from '../../generators/tree';
2
+ export default function setProjectName(tree: Tree): Promise<void>;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const to_project_name_1 = require("../../config/to-project-name");
4
+ const format_changed_files_with_prettier_if_available_1 = require("../../generators/internal-utils/format-changed-files-with-prettier-if-available");
5
+ const json_1 = require("../../generators/utils/json");
6
+ const project_configuration_1 = require("../../generators/utils/project-configuration");
7
+ async function setProjectName(tree) {
8
+ // We are explicitly looking for project.json files here, so getProjects is fine.
9
+ const projects = (0, project_configuration_1.getProjects)(tree);
10
+ for (const { root } of projects.values()) {
11
+ const projectJsonPath = `${root}/project.json`;
12
+ const packageJsonPath = `${root}/package.json`;
13
+ // If either of these files doesn't exist, theres no behavioral difference
14
+ if (!tree.exists(projectJsonPath) || !tree.exists(packageJsonPath)) {
15
+ continue;
16
+ }
17
+ const projectJson = (0, json_1.readJson)(tree, projectJsonPath);
18
+ // In Nx 19.1+, the way the project name is inferred is different.
19
+ // For existing projects, if the name is not set, we can inline it
20
+ // based on the existing logic. This makes sure folks aren't caught
21
+ // off guard by the new behavior.
22
+ if (!projectJson.name) {
23
+ const siblingPackageJson = (0, json_1.readJson)(tree, packageJsonPath);
24
+ const newName = siblingPackageJson.nx?.name ?? siblingPackageJson.name;
25
+ const oldName = (0, to_project_name_1.toProjectName)(projectJsonPath);
26
+ if (newName && oldName !== newName) {
27
+ projectJson.name = oldName;
28
+ (0, json_1.writeJson)(tree, projectJsonPath, projectJson);
29
+ }
30
+ }
31
+ }
32
+ await (0, format_changed_files_with_prettier_if_available_1.formatChangedFilesWithPrettierIfAvailable)(tree);
33
+ }
34
+ exports.default = setProjectName;
@@ -46,6 +46,9 @@ function createPackageJson(projectName, graph, options = {}, fileMap = null) {
46
46
  delete packageJson.dependencies;
47
47
  delete packageJson.devDependencies;
48
48
  }
49
+ if (options.isProduction) {
50
+ delete packageJson.devDependencies;
51
+ }
49
52
  }
50
53
  catch (e) { }
51
54
  }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TargetProjectLocator = exports.isBuiltinModuleImport = void 0;
4
4
  const node_module_1 = require("node:module");
5
5
  const node_path_1 = require("node:path");
6
+ const semver_1 = require("semver");
6
7
  const find_project_for_path_1 = require("../../../../project-graph/utils/find-project-for-path");
7
8
  const fileutils_1 = require("../../../../utils/fileutils");
8
9
  const workspace_root_1 = require("../../../../utils/workspace-root");
@@ -138,7 +139,8 @@ class TargetProjectLocator {
138
139
  this.npmResolutionCache.set(npmImportForProject, externalNodeName);
139
140
  return externalNodeName;
140
141
  }
141
- const npmProjectKey = `npm:${externalPackageJson.name}@${externalPackageJson.version}`;
142
+ const version = (0, semver_1.clean)(externalPackageJson.version);
143
+ const npmProjectKey = `npm:${externalPackageJson.name}@${version}`;
142
144
  const matchingExternalNode = this.npmProjects[npmProjectKey];
143
145
  if (!matchingExternalNode) {
144
146
  return null;
@@ -244,12 +246,15 @@ class TargetProjectLocator {
244
246
  // The package.json is directly resolvable
245
247
  const packageJsonPath = (0, resolve_relative_to_dir_1.resolveRelativeToDir)((0, node_path_1.join)(packageName, 'package.json'), relativeToDir);
246
248
  if (packageJsonPath) {
247
- return (0, fileutils_1.readJsonFile)(packageJsonPath);
249
+ const parsedPackageJson = (0, fileutils_1.readJsonFile)(packageJsonPath);
250
+ if (parsedPackageJson.name && parsedPackageJson.version) {
251
+ return parsedPackageJson;
252
+ }
248
253
  }
249
254
  try {
250
255
  // Resolve the main entry point of the package
251
- const mainPath = (0, resolve_relative_to_dir_1.resolveRelativeToDir)(packageName, relativeToDir);
252
- let dir = (0, node_path_1.dirname)(mainPath);
256
+ const pathOfFileInPackage = packageJsonPath ?? (0, resolve_relative_to_dir_1.resolveRelativeToDir)(packageName, relativeToDir);
257
+ let dir = (0, node_path_1.dirname)(pathOfFileInPackage);
253
258
  while (dir !== (0, node_path_1.parse)(dir).root) {
254
259
  const packageJsonPath = (0, node_path_1.join)(dir, 'package.json');
255
260
  try {
@@ -4,14 +4,14 @@ import { PackageJson } from '../../utils/package-json';
4
4
  import { CreateNodes } from '../../project-graph/plugins';
5
5
  export declare const createNodes: CreateNodes;
6
6
  export declare function buildPackageJsonWorkspacesMatcher(workspaceRoot: string, readJson: (string: any) => any): (p: string) => boolean;
7
- export declare function createNodeFromPackageJson(pkgJsonPath: string, root: string): {
7
+ export declare function createNodeFromPackageJson(pkgJsonPath: string, workspaceRoot: string): {
8
8
  projects: {
9
9
  [x: string]: ProjectConfiguration & {
10
10
  name: string;
11
11
  };
12
12
  };
13
13
  };
14
- export declare function buildProjectConfigurationFromPackageJson(packageJson: PackageJson, path: string, nxJson: NxJsonConfiguration): ProjectConfiguration & {
14
+ export declare function buildProjectConfigurationFromPackageJson(packageJson: PackageJson, workspaceRoot: string, packageJsonPath: string, nxJson: NxJsonConfiguration): ProjectConfiguration & {
15
15
  name: string;
16
16
  };
17
17
  /**
@@ -38,12 +38,21 @@ function buildPackageJsonWorkspacesMatcher(workspaceRoot, readJson) {
38
38
  positivePatterns.push('**/package.json');
39
39
  }
40
40
  return (p) => positivePatterns.some((positive) => (0, minimatch_1.minimatch)(p, positive)) &&
41
- !negativePatterns.some((negative) => (0, minimatch_1.minimatch)(p, negative));
41
+ /**
42
+ * minimatch will return true if the given p is NOT excluded by the negative pattern.
43
+ *
44
+ * For example if the negative pattern is "!packages/vite", then the given p "packages/vite" will return false,
45
+ * the given p "packages/something-else/package.json" will return true.
46
+ *
47
+ * Therefore, we need to ensure that every negative pattern returns true to validate that the given p is not
48
+ * excluded by any of the negative patterns.
49
+ */
50
+ negativePatterns.every((negative) => (0, minimatch_1.minimatch)(p, negative));
42
51
  }
43
52
  exports.buildPackageJsonWorkspacesMatcher = buildPackageJsonWorkspacesMatcher;
44
- function createNodeFromPackageJson(pkgJsonPath, root) {
45
- const json = (0, fileutils_1.readJsonFile)((0, node_path_1.join)(root, pkgJsonPath));
46
- const project = buildProjectConfigurationFromPackageJson(json, pkgJsonPath, (0, nx_json_1.readNxJson)(root));
53
+ function createNodeFromPackageJson(pkgJsonPath, workspaceRoot) {
54
+ const json = (0, fileutils_1.readJsonFile)((0, node_path_1.join)(workspaceRoot, pkgJsonPath));
55
+ const project = buildProjectConfigurationFromPackageJson(json, workspaceRoot, pkgJsonPath, (0, nx_json_1.readNxJson)(workspaceRoot));
47
56
  return {
48
57
  projects: {
49
58
  [project.root]: project,
@@ -51,21 +60,27 @@ function createNodeFromPackageJson(pkgJsonPath, root) {
51
60
  };
52
61
  }
53
62
  exports.createNodeFromPackageJson = createNodeFromPackageJson;
54
- function buildProjectConfigurationFromPackageJson(packageJson, path, nxJson) {
55
- const normalizedPath = path.split('\\').join('/');
56
- const directory = (0, node_path_1.dirname)(normalizedPath);
57
- if (!packageJson.name && directory === '.') {
63
+ function buildProjectConfigurationFromPackageJson(packageJson, workspaceRoot, packageJsonPath, nxJson) {
64
+ const normalizedPath = packageJsonPath.split('\\').join('/');
65
+ const projectRoot = (0, node_path_1.dirname)(normalizedPath);
66
+ const siblingProjectJson = tryReadJson((0, node_path_1.join)(workspaceRoot, projectRoot, 'project.json'));
67
+ if (siblingProjectJson) {
68
+ for (const target of Object.keys(siblingProjectJson?.targets ?? {})) {
69
+ delete packageJson.scripts?.[target];
70
+ }
71
+ }
72
+ if (!packageJson.name && projectRoot === '.') {
58
73
  throw new Error('Nx requires the root package.json to specify a name if it is being used as an Nx project.');
59
74
  }
60
75
  let name = packageJson.name ?? (0, to_project_name_1.toProjectName)(normalizedPath);
61
76
  const projectType = nxJson?.workspaceLayout?.appsDir != nxJson?.workspaceLayout?.libsDir &&
62
77
  nxJson?.workspaceLayout?.appsDir &&
63
- directory.startsWith(nxJson.workspaceLayout.appsDir)
78
+ projectRoot.startsWith(nxJson.workspaceLayout.appsDir)
64
79
  ? 'application'
65
80
  : 'library';
66
81
  return {
67
- root: directory,
68
- sourceRoot: directory,
82
+ root: projectRoot,
83
+ sourceRoot: projectRoot,
69
84
  name,
70
85
  projectType,
71
86
  ...packageJson.nx,
@@ -127,3 +142,11 @@ function normalizePatterns(patterns) {
127
142
  function removeRelativePath(pattern) {
128
143
  return pattern.startsWith('./') ? pattern.substring(2) : pattern;
129
144
  }
145
+ function tryReadJson(path) {
146
+ try {
147
+ return (0, fileutils_1.readJsonFile)(path);
148
+ }
149
+ catch {
150
+ return null;
151
+ }
152
+ }
@@ -3,3 +3,4 @@ import { NxPluginV2 } from '../../../project-graph/plugins';
3
3
  export declare const ProjectJsonProjectsPlugin: NxPluginV2;
4
4
  export default ProjectJsonProjectsPlugin;
5
5
  export declare function buildProjectFromProjectJson(json: Partial<ProjectConfiguration>, path: string): ProjectConfiguration;
6
+ export declare function readNameFromPackageJson(path: string): string;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.buildProjectFromProjectJson = exports.ProjectJsonProjectsPlugin = void 0;
3
+ exports.readNameFromPackageJson = exports.buildProjectFromProjectJson = exports.ProjectJsonProjectsPlugin = void 0;
4
4
  const node_path_1 = require("node:path");
5
5
  const to_project_name_1 = require("../../../config/to-project-name");
6
6
  const fileutils_1 = require("../../../utils/fileutils");
@@ -21,10 +21,22 @@ exports.ProjectJsonProjectsPlugin = {
21
21
  };
22
22
  exports.default = exports.ProjectJsonProjectsPlugin;
23
23
  function buildProjectFromProjectJson(json, path) {
24
+ const packageJsonPath = (0, node_path_1.join)((0, node_path_1.dirname)(path), 'package.json');
25
+ const { name, root, ...rest } = json;
24
26
  return {
25
- name: (0, to_project_name_1.toProjectName)(path),
26
- root: (0, node_path_1.dirname)(path),
27
- ...json,
27
+ name: name ?? readNameFromPackageJson(packageJsonPath) ?? (0, to_project_name_1.toProjectName)(path),
28
+ root: root ?? (0, node_path_1.dirname)(path),
29
+ ...rest,
28
30
  };
29
31
  }
30
32
  exports.buildProjectFromProjectJson = buildProjectFromProjectJson;
33
+ function readNameFromPackageJson(path) {
34
+ try {
35
+ const json = (0, fileutils_1.readJsonFile)(path);
36
+ return json.nx?.name ?? json.name;
37
+ }
38
+ catch {
39
+ return undefined;
40
+ }
41
+ }
42
+ exports.readNameFromPackageJson = readNameFromPackageJson;
@@ -161,6 +161,16 @@ class AggregateCreateNodesError extends Error {
161
161
  this.errors = errors;
162
162
  this.partialResults = partialResults;
163
163
  this.name = this.constructor.name;
164
+ if (
165
+ // Errors should be an array
166
+ !Array.isArray(errors) ||
167
+ !errors.every(
168
+ // Where every element is a tuple
169
+ (errorTuple) => Array.isArray(errorTuple) &&
170
+ // That has a length of 2
171
+ errorTuple.length === 2)) {
172
+ throw new Error('AggregateCreateNodesError must be constructed with an array of tuples where the first element is a filename or undefined and the second element is the underlying error.');
173
+ }
164
174
  }
165
175
  }
166
176
  exports.AggregateCreateNodesError = AggregateCreateNodesError;
@@ -162,7 +162,7 @@ function getProjectsSync(root, nxJson) {
162
162
  }
163
163
  else if ((0, path_1.basename)(projectFile) === 'package.json') {
164
164
  const packageJson = (0, fileutils_1.readJsonFile)(projectFile);
165
- const config = (0, package_json_workspaces_1.buildProjectConfigurationFromPackageJson)(packageJson, projectFile, nxJson);
165
+ const config = (0, package_json_workspaces_1.buildProjectConfigurationFromPackageJson)(packageJson, root, projectFile, nxJson);
166
166
  if (!rootMap[config.root]) {
167
167
  (0, project_configuration_utils_1.mergeProjectConfigurationIntoRootMap)(rootMap,
168
168
  // Inferred targets, tags, etc don't show up when running generators
@@ -45,7 +45,7 @@ class LoadedNxPlugin {
45
45
  throw e;
46
46
  }
47
47
  // The underlying plugin errored out. We can't know any partial results.
48
- throw new error_types_1.AggregateCreateNodesError([null, e], []);
48
+ throw new error_types_1.AggregateCreateNodesError([[null, e]], []);
49
49
  }
50
50
  finally {
51
51
  performance.mark(`${plugin.name}:createNodes - end`);
@@ -76,11 +76,29 @@ function normalizeImplicitDependencies(source, implicitDependencies, projects) {
76
76
  if (!implicitDependencies?.length) {
77
77
  return implicitDependencies ?? [];
78
78
  }
79
- const matches = (0, find_matching_projects_1.findMatchingProjects)(implicitDependencies, projects);
80
- return (matches
81
- .filter((x) => x !== source)
82
- // implicit dependencies that start with ! should hang around, to be processed by
83
- // implicit-project-dependencies.ts after explicit deps are added to graph.
84
- .concat(implicitDependencies.filter((x) => x.startsWith('!'))));
79
+ // Implicit dependencies handle negatives in a different
80
+ // way from most other `projects` fields. This is because
81
+ // they are used for multiple purposes.
82
+ const positivePatterns = [];
83
+ const negativePatterns = [];
84
+ for (const dep of implicitDependencies) {
85
+ if (dep.startsWith('!')) {
86
+ negativePatterns.push(dep);
87
+ }
88
+ else {
89
+ positivePatterns.push(dep);
90
+ }
91
+ }
92
+ // Finds all projects that match a positive pattern and are not excluded by a negative pattern
93
+ const deps = positivePatterns.length
94
+ ? (0, find_matching_projects_1.findMatchingProjects)(positivePatterns.concat(negativePatterns), projects).filter((x) => x !== source)
95
+ : [];
96
+ // Expands negative patterns to equal project names
97
+ const alwaysIgnoredDeps = (0, find_matching_projects_1.findMatchingProjects)(negativePatterns.map((x) => x.slice(1)), projects);
98
+ // We return the matching deps, but keep the negative patterns in the list
99
+ // so that they can be processed later by implicit-project-dependencies.ts
100
+ // This is what allows using a negative implicit dep to remove a dependency
101
+ // detected by createDependencies.
102
+ return deps.concat(alwaysIgnoredDeps.map((x) => '!' + x));
85
103
  }
86
104
  exports.normalizeImplicitDependencies = normalizeImplicitDependencies;
@@ -245,7 +245,15 @@ plugins) {
245
245
  e
246
246
  : // This represents a single plugin erroring out with a hard error.
247
247
  new error_types_1.AggregateCreateNodesError([[null, e]], []);
248
- errorBodyLines.push(...error.errors.map(([file, e]) => ` - ${file}: ${e.message}`));
248
+ const innerErrors = error.errors;
249
+ for (const [file, e] of innerErrors) {
250
+ if (file) {
251
+ errorBodyLines.push(` - ${file}: ${e.message}`);
252
+ }
253
+ else {
254
+ errorBodyLines.push(` - ${e.message}`);
255
+ }
256
+ }
249
257
  error.message = errorBodyLines.join('\n');
250
258
  // This represents a single plugin erroring out with a hard error.
251
259
  errors.push(error);