nx 19.3.0-canary.20240607-7495f06 → 19.3.0-canary.20240611-1600875
Sign up to get free protection for your applications and to get access to all the features.
- package/migrations.json +6 -0
- package/package.json +12 -12
- package/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +38 -13
- package/src/command-line/release/utils/git.d.ts +2 -2
- package/src/command-line/release/utils/git.js +19 -11
- package/src/command-line/release/version.d.ts +1 -1
- package/src/command-line/release/version.js +1 -1
- package/src/command-line/yargs-utils/shared-options.d.ts +1 -1
- package/src/core/graph/main.js +1 -1
- package/src/generators/utils/project-configuration.js +1 -1
- package/src/hasher/file-hasher.js +1 -1
- package/src/plugins/js/project-graph/build-dependencies/target-project-locator.js +3 -1
- package/src/plugins/package-json-workspaces/create-nodes.d.ts +2 -2
- package/src/plugins/package-json-workspaces/create-nodes.js +34 -11
- package/src/project-graph/error-types.js +10 -0
- package/src/project-graph/file-utils.js +1 -1
- package/src/project-graph/plugins/internal-api.js +1 -1
- package/src/project-graph/utils/normalize-project-nodes.js +24 -6
- package/src/project-graph/utils/project-configuration-utils.js +9 -1
- package/src/tasks-runner/create-task-graph.js +32 -33
- package/src/utils/ab-testing.d.ts +1 -1
- package/src/utils/find-matching-projects.js +13 -1
@@ -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
|
}
|
@@ -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
|
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;
|
@@ -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,
|
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,
|
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
|
-
|
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,
|
45
|
-
const json = (0, fileutils_1.readJsonFile)((0, node_path_1.join)(
|
46
|
-
const project = buildProjectConfigurationFromPackageJson(json, pkgJsonPath, (0, nx_json_1.readNxJson)(
|
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,
|
55
|
-
const normalizedPath =
|
56
|
-
const
|
57
|
-
|
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
|
-
|
78
|
+
projectRoot.startsWith(nxJson.workspaceLayout.appsDir)
|
64
79
|
? 'application'
|
65
80
|
: 'library';
|
66
81
|
return {
|
67
|
-
root:
|
68
|
-
sourceRoot:
|
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
|
+
}
|
@@ -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
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
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
|
-
|
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);
|
@@ -64,7 +64,26 @@ class ProcessTasks {
|
|
64
64
|
? overrides
|
65
65
|
: { __overrides_unparsed__: [] };
|
66
66
|
if (dependencyConfig.projects) {
|
67
|
-
|
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,
|
96
|
+
processTasksForMatchingProjects(dependencyConfig, configuration, task, taskOverrides, overrides) {
|
78
97
|
const targetProjectSpecifiers = typeof dependencyConfig.projects === 'string'
|
79
98
|
? [dependencyConfig.projects]
|
80
99
|
: dependencyConfig.projects;
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
}
|
89
|
-
|
90
|
-
|
91
|
-
|
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
|
155
|
+
const isExclude = isExcludePattern(pattern);
|
144
156
|
// Support for things like: `!{type}:value`
|
145
157
|
if (isExclude) {
|
146
158
|
pattern = pattern.substring(1);
|