nx 19.2.1 → 19.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  }
@@ -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;
@@ -38,7 +38,16 @@ 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
53
  function createNodeFromPackageJson(pkgJsonPath, root) {
@@ -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;
@@ -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);
@@ -9,12 +9,12 @@ import { LoadedNxPlugin } from '../plugins/internal-api';
9
9
  * @param nxJson
10
10
  */
11
11
  export declare function retrieveWorkspaceFiles(workspaceRoot: string, projectRootMap: Record<string, string>): Promise<{
12
- allWorkspaceFiles: import("nx/src/devkit-exports").FileData[];
12
+ allWorkspaceFiles: import("../file-utils").FileData[];
13
13
  fileMap: {
14
14
  projectFileMap: ProjectFiles;
15
- nonProjectFiles: import("nx/src/native").FileData[];
15
+ nonProjectFiles: import("../../native").FileData[];
16
16
  };
17
- rustReferences: import("nx/src/native").NxWorkspaceFilesExternals;
17
+ rustReferences: import("../../native").NxWorkspaceFilesExternals;
18
18
  }>;
19
19
  /**
20
20
  * Walk through the workspace and return `ProjectConfigurations`. Only use this if the projectFileMap is not needed.
@@ -64,7 +64,26 @@ class ProcessTasks {
64
64
  ? overrides
65
65
  : { __overrides_unparsed__: [] };
66
66
  if (dependencyConfig.projects) {
67
- this.processTasksForMatchingProjects(dependencyConfig, projectUsedToDeriveDependencies, configuration, task, taskOverrides, overrides);
67
+ /** LERNA SUPPORT START - Remove in v20 */
68
+ // Lerna uses `dependencies` in `prepNxOptions`, so we need to maintain
69
+ // support for it until lerna can be updated to use the syntax.
70
+ //
71
+ // This should have been removed in v17, but the updates to lerna had not
72
+ // been made yet.
73
+ //
74
+ // TODO(@agentender): Remove this part in v20
75
+ if (typeof dependencyConfig.projects === 'string') {
76
+ if (dependencyConfig.projects === 'self') {
77
+ this.processTasksForSingleProject(task, task.target.project, dependencyConfig, configuration, taskOverrides, overrides);
78
+ continue;
79
+ }
80
+ else if (dependencyConfig.projects === 'dependencies') {
81
+ this.processTasksForDependencies(projectUsedToDeriveDependencies, dependencyConfig, configuration, task, taskOverrides, overrides);
82
+ continue;
83
+ }
84
+ }
85
+ /** LERNA SUPPORT END - Remove in v17 */
86
+ this.processTasksForMatchingProjects(dependencyConfig, configuration, task, taskOverrides, overrides);
68
87
  }
69
88
  else if (dependencyConfig.dependencies) {
70
89
  this.processTasksForDependencies(projectUsedToDeriveDependencies, dependencyConfig, configuration, task, taskOverrides, overrides);
@@ -74,41 +93,21 @@ class ProcessTasks {
74
93
  }
75
94
  }
76
95
  }
77
- processTasksForMatchingProjects(dependencyConfig, projectUsedToDeriveDependencies, configuration, task, taskOverrides, overrides) {
96
+ processTasksForMatchingProjects(dependencyConfig, configuration, task, taskOverrides, overrides) {
78
97
  const targetProjectSpecifiers = typeof dependencyConfig.projects === 'string'
79
98
  ? [dependencyConfig.projects]
80
99
  : dependencyConfig.projects;
81
- for (const projectSpecifier of targetProjectSpecifiers) {
82
- // Lerna uses `dependencies` in `prepNxOptions`, so we need to maintain
83
- // support for it until lerna can be updated to use the syntax.
84
- // TODO(@agentender): Remove this part in v17
85
- if (projectSpecifier === 'dependencies' &&
86
- !this.projectGraph.nodes[projectSpecifier]) {
87
- this.processTasksForDependencies(projectUsedToDeriveDependencies, dependencyConfig, configuration, task, taskOverrides, overrides);
88
- }
89
- else {
90
- // Since we need to maintain support for dependencies, it is more coherent
91
- // that we also support self.
92
- // TODO(@agentender): Remove this part in v17
93
- const matchingProjects =
94
- /** LERNA SUPPORT START - Remove in v17 */
95
- projectSpecifier === 'self' &&
96
- !this.projectGraph.nodes[projectSpecifier]
97
- ? [task.target.project]
98
- : /** LERNA SUPPORT END */
99
- (0, find_matching_projects_1.findMatchingProjects)([projectSpecifier], this.projectGraph.nodes);
100
- if (matchingProjects.length === 0) {
101
- output_1.output.warn({
102
- title: `\`dependsOn\` is misconfigured for ${task.target.project}:${task.target.target}`,
103
- bodyLines: [
104
- `Project pattern "${projectSpecifier}" does not match any projects.`,
105
- ],
106
- });
107
- }
108
- for (const projectName of matchingProjects) {
109
- this.processTasksForSingleProject(task, projectName, dependencyConfig, configuration, taskOverrides, overrides);
110
- }
111
- }
100
+ const matchingProjects = (0, find_matching_projects_1.findMatchingProjects)(targetProjectSpecifiers, this.projectGraph.nodes);
101
+ if (matchingProjects.length === 0) {
102
+ output_1.output.warn({
103
+ title: `\`dependsOn\` is misconfigured for ${task.target.project}:${task.target.target}`,
104
+ bodyLines: [
105
+ `Project patterns "${targetProjectSpecifiers}" does not match any projects.`,
106
+ ],
107
+ });
108
+ }
109
+ for (const projectName of matchingProjects) {
110
+ this.processTasksForSingleProject(task, projectName, dependencyConfig, configuration, taskOverrides, overrides);
112
111
  }
113
112
  }
114
113
  processTasksForSingleProject(task, projectName, dependencyConfig, configuration, taskOverrides, overrides) {
@@ -31,7 +31,7 @@ declare const messageOptions: {
31
31
  }];
32
32
  };
33
33
  export type MessageKey = keyof typeof messageOptions;
34
- export type MessageData = typeof messageOptions[MessageKey][number];
34
+ export type MessageData = (typeof messageOptions)[MessageKey][number];
35
35
  export declare class PromptMessages {
36
36
  private selectedMessages;
37
37
  getPrompt(key: MessageKey): MessageData;
@@ -22,6 +22,15 @@ function findMatchingProjects(patterns = [], projects) {
22
22
  }
23
23
  const projectNames = Object.keys(projects);
24
24
  const matchedProjects = new Set();
25
+ // If the first pattern is an exclude pattern,
26
+ // we add a wildcard pattern at the first to select
27
+ // all projects, except the ones that match the exclude pattern.
28
+ // e.g. ['!tag:someTag', 'project2'] will match all projects except
29
+ // the ones with the tag 'someTag', and also match the project 'project2',
30
+ // regardless of its tags.
31
+ if (isExcludePattern(patterns[0])) {
32
+ patterns.unshift('*');
33
+ }
25
34
  for (const stringPattern of patterns) {
26
35
  if (!stringPattern.length) {
27
36
  continue;
@@ -139,8 +148,11 @@ function addMatchingProjectsByTag(projectNames, projects, pattern, matchedProjec
139
148
  }
140
149
  }
141
150
  }
151
+ function isExcludePattern(pattern) {
152
+ return pattern.startsWith('!');
153
+ }
142
154
  function parseStringPattern(pattern, projects) {
143
- const isExclude = pattern.startsWith('!');
155
+ const isExclude = isExcludePattern(pattern);
144
156
  // Support for things like: `!{type}:value`
145
157
  if (isExclude) {
146
158
  pattern = pattern.substring(1);