nx 17.1.0-beta.0 → 17.1.0-beta.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nx",
3
- "version": "17.1.0-beta.0",
3
+ "version": "17.1.0-beta.2",
4
4
  "private": false,
5
5
  "description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.",
6
6
  "repository": {
@@ -67,7 +67,7 @@
67
67
  "yargs": "^17.6.2",
68
68
  "yargs-parser": "21.1.1",
69
69
  "node-machine-id": "1.1.12",
70
- "@nrwl/tao": "17.1.0-beta.0"
70
+ "@nrwl/tao": "17.1.0-beta.2"
71
71
  },
72
72
  "peerDependencies": {
73
73
  "@swc-node/register": "^1.6.7",
@@ -82,16 +82,16 @@
82
82
  }
83
83
  },
84
84
  "optionalDependencies": {
85
- "@nx/nx-darwin-x64": "17.1.0-beta.0",
86
- "@nx/nx-darwin-arm64": "17.1.0-beta.0",
87
- "@nx/nx-linux-x64-gnu": "17.1.0-beta.0",
88
- "@nx/nx-linux-x64-musl": "17.1.0-beta.0",
89
- "@nx/nx-win32-x64-msvc": "17.1.0-beta.0",
90
- "@nx/nx-linux-arm64-gnu": "17.1.0-beta.0",
91
- "@nx/nx-linux-arm64-musl": "17.1.0-beta.0",
92
- "@nx/nx-linux-arm-gnueabihf": "17.1.0-beta.0",
93
- "@nx/nx-win32-arm64-msvc": "17.1.0-beta.0",
94
- "@nx/nx-freebsd-x64": "17.1.0-beta.0"
85
+ "@nx/nx-darwin-x64": "17.1.0-beta.2",
86
+ "@nx/nx-darwin-arm64": "17.1.0-beta.2",
87
+ "@nx/nx-linux-x64-gnu": "17.1.0-beta.2",
88
+ "@nx/nx-linux-x64-musl": "17.1.0-beta.2",
89
+ "@nx/nx-win32-x64-msvc": "17.1.0-beta.2",
90
+ "@nx/nx-linux-arm64-gnu": "17.1.0-beta.2",
91
+ "@nx/nx-linux-arm64-musl": "17.1.0-beta.2",
92
+ "@nx/nx-linux-arm-gnueabihf": "17.1.0-beta.2",
93
+ "@nx/nx-win32-arm64-msvc": "17.1.0-beta.2",
94
+ "@nx/nx-freebsd-x64": "17.1.0-beta.2"
95
95
  },
96
96
  "nx-migrations": {
97
97
  "migrations": "./migrations.json",
@@ -57,6 +57,7 @@ async function addNxToMonorepo(options) {
57
57
  (options.interactive ? await (0, utils_1.askAboutNxCloud)() : false);
58
58
  }
59
59
  (0, utils_1.createNxJsonFile)(repoRoot, targetDefaults, cacheableOperations, scriptOutputs);
60
+ (0, utils_1.updateGitIgnore)(repoRoot);
60
61
  (0, utils_1.addDepsToPackageJson)(repoRoot);
61
62
  output_1.output.log({ title: '📦 Installing dependencies' });
62
63
  (0, utils_1.runInstall)(repoRoot);
@@ -71,6 +71,7 @@ async function addNxToNest(options, packageJson) {
71
71
  }
72
72
  (0, utils_1.createNxJsonFile)(repoRoot, [], [...cacheableOperations, ...nestCacheableScripts], {});
73
73
  const pmc = (0, package_manager_1.getPackageManagerCommand)();
74
+ (0, utils_1.updateGitIgnore)(repoRoot);
74
75
  (0, utils_1.addDepsToPackageJson)(repoRoot);
75
76
  addNestPluginToPackageJson(repoRoot);
76
77
  (0, utils_1.markRootPackageJsonAsNxProject)(repoRoot, cacheableOperations, scriptOutputs, pmc);
@@ -46,6 +46,7 @@ async function addNxToNpmRepo(options) {
46
46
  }
47
47
  (0, utils_1.createNxJsonFile)(repoRoot, [], cacheableOperations, {});
48
48
  const pmc = (0, package_manager_1.getPackageManagerCommand)();
49
+ (0, utils_1.updateGitIgnore)(repoRoot);
49
50
  (0, utils_1.addDepsToPackageJson)(repoRoot);
50
51
  (0, utils_1.markRootPackageJsonAsNxProject)(repoRoot, cacheableOperations, scriptOutputs, pmc);
51
52
  output_1.output.log({ title: '📦 Installing dependencies' });
@@ -4,6 +4,7 @@ export declare function createNxJsonFile(repoRoot: string, topologicalTargets: s
4
4
  [name: string]: string;
5
5
  }): void;
6
6
  export declare function addDepsToPackageJson(repoRoot: string): void;
7
+ export declare function updateGitIgnore(root: string): void;
7
8
  export declare function runInstall(repoRoot: string, pmc?: PackageManagerCommands): void;
8
9
  export declare function initCloud(repoRoot: string, installationSource: 'nx-init-angular' | 'nx-init-cra' | 'nx-init-monorepo' | 'nx-init-nest' | 'nx-init-npm-repo'): void;
9
10
  export declare function addVsCodeRecommendedExtensions(repoRoot: string, extensions: string[]): void;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.printFinalMessage = exports.markRootPackageJsonAsNxProject = exports.addVsCodeRecommendedExtensions = exports.initCloud = exports.runInstall = exports.addDepsToPackageJson = exports.createNxJsonFile = exports.askAboutNxCloud = void 0;
3
+ exports.printFinalMessage = exports.markRootPackageJsonAsNxProject = exports.addVsCodeRecommendedExtensions = exports.initCloud = exports.runInstall = exports.updateGitIgnore = exports.addDepsToPackageJson = exports.createNxJsonFile = exports.askAboutNxCloud = void 0;
4
4
  const child_process_1 = require("child_process");
5
5
  const enquirer = require("enquirer");
6
6
  const path_1 = require("path");
@@ -10,6 +10,7 @@ const output_1 = require("../../../utils/output");
10
10
  const package_manager_1 = require("../../../utils/package-manager");
11
11
  const path_2 = require("../../../utils/path");
12
12
  const versions_1 = require("../../../utils/versions");
13
+ const fs_1 = require("fs");
13
14
  async function askAboutNxCloud() {
14
15
  return await enquirer
15
16
  .prompt([
@@ -108,6 +109,18 @@ function addDepsToPackageJson(repoRoot) {
108
109
  (0, fileutils_1.writeJsonFile)(path, json);
109
110
  }
110
111
  exports.addDepsToPackageJson = addDepsToPackageJson;
112
+ function updateGitIgnore(root) {
113
+ const ignorePath = (0, path_1.join)(root, '.gitignore');
114
+ try {
115
+ let contents = (0, fs_1.readFileSync)(ignorePath, 'utf-8');
116
+ if (!contents.includes('.nx/cache')) {
117
+ contents = [contents, '', '.nx/cache'].join('\n');
118
+ (0, fs_1.writeFileSync)(ignorePath, contents, 'utf-8');
119
+ }
120
+ }
121
+ catch { }
122
+ }
123
+ exports.updateGitIgnore = updateGitIgnore;
111
124
  function runInstall(repoRoot, pmc = (0, package_manager_1.getPackageManagerCommand)()) {
112
125
  (0, child_process_1.execSync)(pmc.install, { stdio: [0, 1, 2], cwd: repoRoot });
113
126
  }
@@ -14,4 +14,5 @@ export { sortObjectByKeys } from './utils/object-sort';
14
14
  export { stripIndent } from './utils/logger';
15
15
  export { readModulePackageJson } from './utils/package-json';
16
16
  export { splitByColons } from './utils/split-target';
17
+ export { hashObject } from './hasher/file-hasher';
17
18
  export { createProjectRootMappingsFromProjectConfigurations, findProjectForPath, } from './project-graph/utils/find-project-for-path';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.findProjectForPath = exports.createProjectRootMappingsFromProjectConfigurations = exports.splitByColons = exports.readModulePackageJson = exports.stripIndent = exports.sortObjectByKeys = exports.combineOptionsForExecutor = exports.splitTarget = exports.retrieveProjectConfigurationsWithAngularProjects = exports.calculateDefaultProjectName = exports.readNxJsonFromDisk = exports.getExecutorInformation = exports.createTempNpmDirectory = void 0;
3
+ exports.findProjectForPath = exports.createProjectRootMappingsFromProjectConfigurations = exports.hashObject = exports.splitByColons = exports.readModulePackageJson = exports.stripIndent = exports.sortObjectByKeys = exports.combineOptionsForExecutor = exports.splitTarget = exports.retrieveProjectConfigurationsWithAngularProjects = exports.calculateDefaultProjectName = exports.readNxJsonFromDisk = exports.getExecutorInformation = exports.createTempNpmDirectory = void 0;
4
4
  /**
5
5
  * Note to developers: STOP! These exports are available via requireNx in @nx/devkit.
6
6
  *
@@ -28,6 +28,8 @@ var package_json_1 = require("./utils/package-json");
28
28
  Object.defineProperty(exports, "readModulePackageJson", { enumerable: true, get: function () { return package_json_1.readModulePackageJson; } });
29
29
  var split_target_2 = require("./utils/split-target");
30
30
  Object.defineProperty(exports, "splitByColons", { enumerable: true, get: function () { return split_target_2.splitByColons; } });
31
+ var file_hasher_1 = require("./hasher/file-hasher");
32
+ Object.defineProperty(exports, "hashObject", { enumerable: true, get: function () { return file_hasher_1.hashObject; } });
31
33
  var find_project_for_path_1 = require("./project-graph/utils/find-project-for-path");
32
34
  Object.defineProperty(exports, "createProjectRootMappingsFromProjectConfigurations", { enumerable: true, get: function () { return find_project_for_path_1.createProjectRootMappingsFromProjectConfigurations; } });
33
35
  Object.defineProperty(exports, "findProjectForPath", { enumerable: true, get: function () { return find_project_for_path_1.findProjectForPath; } });
@@ -35,9 +35,6 @@ function addCommonFiles(tree, addAppsAndLibsFolders) {
35
35
  lint: {
36
36
  cache: true,
37
37
  },
38
- test: {
39
- cache: true,
40
- },
41
38
  e2e: {
42
39
  cache: true,
43
40
  },
@@ -6,7 +6,10 @@ const logger_1 = require("../../utils/logger");
6
6
  const project_configuration_utils_1 = require("../utils/project-configuration-utils");
7
7
  async function normalizeProjectNodes(ctx, builder, nxJson) {
8
8
  const toAdd = [];
9
- const projects = Object.keys(ctx.projects);
9
+ // Sorting projects by name to make sure that the order of projects in the graph is deterministic.
10
+ // This is important to ensure that expanded properties referencing projects (e.g. implicit dependencies)
11
+ // are also deterministic, and thus don't cause the calculated project configuration hash to shift.
12
+ const projects = Object.keys(ctx.projects).sort();
10
13
  // Used for expanding implicit dependencies (e.g. `@proj/*` or `tag:foo`)
11
14
  const partialProjectGraphNodes = projects.reduce((graph, project) => {
12
15
  const projectConfiguration = ctx.projects[project];
@@ -71,7 +74,7 @@ function normalizeProjectTargets(project, targetDefaults, projectName) {
71
74
  const defaults = resolveCommandSyntacticSugar((0, project_configuration_utils_1.readTargetDefaultsForTarget)(target, targetDefaults, executor), `targetDefaults:${target}`);
72
75
  targets[target] = resolveCommandSyntacticSugar(targets[target], `${projectName}:${target}`);
73
76
  if (defaults) {
74
- targets[target] = (0, project_configuration_utils_1.mergeTargetConfigurations)(project, target, defaults);
77
+ targets[target] = (0, project_configuration_utils_1.mergeTargetConfigurations)(targets[target], defaults);
75
78
  }
76
79
  targets[target].options = (0, project_configuration_utils_1.resolveNxTokensInOptions)(targets[target].options, project, `${projectName}:${target}`);
77
80
  targets[target].configurations ??= {};
@@ -9,6 +9,16 @@ plugins: LoadedNxPlugin[], root?: string): {
9
9
  externalNodes: Record<string, ProjectGraphExternalNode>;
10
10
  };
11
11
  export declare function readProjectConfigurationsFromRootMap(projectRootMap: Map<string, ProjectConfiguration>): Record<string, ProjectConfiguration>;
12
- export declare function mergeTargetConfigurations(projectConfiguration: ProjectConfiguration, target: string, targetDefaults: TargetDefaults[string]): TargetConfiguration;
12
+ /**
13
+ * Merges two configurations for a target.
14
+ *
15
+ * Most properties from `target` will overwrite any properties from `baseTarget`.
16
+ * Options and configurations are treated differently - they are merged together if the executor definition is compatible.
17
+ *
18
+ * @param target The configuration for the target with higher priority
19
+ * @param baseTarget The configuration for the target that should be overwritten.
20
+ * @returns A merged target configuration
21
+ */
22
+ export declare function mergeTargetConfigurations(target: TargetConfiguration, baseTarget: TargetConfiguration): TargetConfiguration;
13
23
  export declare function resolveNxTokensInOptions<T extends Object | Array<unknown>>(object: T, project: ProjectConfiguration, key: string): T;
14
24
  export declare function readTargetDefaultsForTarget(targetName: string, targetDefaults: TargetDefaults, executor?: string): TargetDefaults[string];
@@ -21,16 +21,28 @@ function mergeProjectConfigurationIntoRootMap(projectRootMap, project) {
21
21
  };
22
22
  // The next blocks handle properties that should be themselves merged (e.g. targets, tags, and implicit dependencies)
23
23
  if (project.tags && matchingProject.tags) {
24
- updatedProjectConfiguration.tags = matchingProject.tags.concat(project.tags);
24
+ updatedProjectConfiguration.tags = Array.from(new Set(matchingProject.tags.concat(project.tags)));
25
25
  }
26
26
  if (project.implicitDependencies && matchingProject.implicitDependencies) {
27
27
  updatedProjectConfiguration.implicitDependencies =
28
28
  matchingProject.implicitDependencies.concat(project.implicitDependencies);
29
29
  }
30
30
  if (project.generators && matchingProject.generators) {
31
- updatedProjectConfiguration.generators = {
32
- ...matchingProject.generators,
33
- ...project.generators,
31
+ // Start with generators config in new project.
32
+ updatedProjectConfiguration.generators = { ...project.generators };
33
+ // For each generator that was already defined, shallow merge the options.
34
+ // Project contains the new info, so it has higher priority.
35
+ for (const generator in matchingProject.generators) {
36
+ updatedProjectConfiguration.generators[generator] = {
37
+ ...matchingProject.generators[generator],
38
+ ...project.generators[generator],
39
+ };
40
+ }
41
+ }
42
+ if (project.namedInputs && matchingProject.namedInputs) {
43
+ updatedProjectConfiguration.namedInputs = {
44
+ ...matchingProject.namedInputs,
45
+ ...project.namedInputs,
34
46
  };
35
47
  }
36
48
  if (project.targets && matchingProject.targets) {
@@ -38,6 +50,14 @@ function mergeProjectConfigurationIntoRootMap(projectRootMap, project) {
38
50
  ...matchingProject.targets,
39
51
  ...project.targets,
40
52
  };
53
+ for (const target in matchingProject.targets) {
54
+ if (target in matchingProject.targets && target in project.targets) {
55
+ // If the target is defined in both places, merge the options
56
+ // Project contains the new info, so it has higher priority.
57
+ // Options from matchingProject are used as defaults.
58
+ updatedProjectConfiguration.targets[target] = mergeTargetConfigurations(project.targets[target], matchingProject.targets[target]);
59
+ }
60
+ }
41
61
  }
42
62
  projectRootMap.set(updatedProjectConfiguration.root, updatedProjectConfiguration);
43
63
  }
@@ -104,27 +124,41 @@ function readProjectConfigurationsFromRootMap(projectRootMap) {
104
124
  return projects;
105
125
  }
106
126
  exports.readProjectConfigurationsFromRootMap = readProjectConfigurationsFromRootMap;
107
- function mergeTargetConfigurations(projectConfiguration, target, targetDefaults) {
108
- const targetConfiguration = projectConfiguration.targets?.[target];
109
- if (!targetConfiguration) {
110
- throw new Error(`Attempted to merge targetDefaults for ${projectConfiguration.name}.${target}, which doesn't exist.`);
111
- }
112
- const { configurations: defaultConfigurations, options: defaultOptions, ...defaults } = targetDefaults;
127
+ /**
128
+ * Merges two configurations for a target.
129
+ *
130
+ * Most properties from `target` will overwrite any properties from `baseTarget`.
131
+ * Options and configurations are treated differently - they are merged together if the executor definition is compatible.
132
+ *
133
+ * @param target The configuration for the target with higher priority
134
+ * @param baseTarget The configuration for the target that should be overwritten.
135
+ * @returns A merged target configuration
136
+ */
137
+ function mergeTargetConfigurations(target, baseTarget) {
138
+ const { configurations: defaultConfigurations, options: defaultOptions, ...defaults } = baseTarget;
113
139
  const result = {
114
140
  ...defaults,
115
- ...targetConfiguration,
141
+ ...target,
116
142
  };
117
143
  // Target is "compatible", e.g. executor is defined only once or is the same
118
144
  // in both places. This means that it is likely safe to merge options
119
- if (!targetDefaults.executor ||
120
- !targetConfiguration.executor ||
121
- targetDefaults.executor === targetConfiguration.executor) {
122
- result.options = { ...defaultOptions, ...targetConfiguration?.options };
123
- result.configurations = mergeConfigurations(defaultConfigurations, targetConfiguration.configurations);
145
+ if (isCompatibleTarget(defaults, target)) {
146
+ result.options = { ...defaultOptions, ...target?.options };
147
+ result.configurations = mergeConfigurations(defaultConfigurations, target.configurations);
124
148
  }
125
149
  return result;
126
150
  }
127
151
  exports.mergeTargetConfigurations = mergeTargetConfigurations;
152
+ /**
153
+ * Checks if targets options are compatible - used when merging configurations
154
+ * to avoid merging options for @nx/js:tsc into something like @nx/webpack:webpack.
155
+ *
156
+ * If the executors are both specified and don't match, the options aren't considered
157
+ * "compatible" and shouldn't be merged.
158
+ */
159
+ function isCompatibleTarget(a, b) {
160
+ return !a.executor || !b.executor || a.executor === b.executor;
161
+ }
128
162
  function mergeConfigurations(defaultConfigurations, projectDefinedConfigurations) {
129
163
  const result = {};
130
164
  const configurations = new Set([
@@ -121,7 +121,9 @@ exports.retrieveProjectConfigurationsWithoutPluginInference = retrieveProjectCon
121
121
  function buildAllWorkspaceFiles(projectFileMap, globalFiles) {
122
122
  perf_hooks_1.performance.mark('get-all-workspace-files:start');
123
123
  let fileData = Object.values(projectFileMap).flat();
124
- fileData = fileData.concat(globalFiles).sort();
124
+ fileData = fileData
125
+ .concat(globalFiles)
126
+ .sort((a, b) => a.file.localeCompare(b.file));
125
127
  perf_hooks_1.performance.mark('get-all-workspace-files:end');
126
128
  perf_hooks_1.performance.measure('get-all-workspace-files', 'get-all-workspace-files:start', 'get-all-workspace-files:end');
127
129
  return fileData;
@@ -7,6 +7,7 @@ export interface PackageManagerCommands {
7
7
  addDev: string;
8
8
  rm: string;
9
9
  exec: string;
10
+ dlx: string;
10
11
  list: string;
11
12
  run: (script: string, args: string) => string;
12
13
  }
@@ -55,13 +55,14 @@ function getPackageManagerCommand(packageManager = detectPackageManager(), root
55
55
  addDev: useBerry ? 'yarn add -D' : 'yarn add -D -W',
56
56
  rm: 'yarn remove',
57
57
  exec: 'yarn',
58
+ dlx: useBerry ? 'yarn dlx' : 'yarn',
58
59
  run: (script, args) => `yarn ${script} ${args}`,
59
60
  list: useBerry ? 'yarn info --name-only' : 'yarn list',
60
61
  };
61
62
  },
62
63
  pnpm: () => {
63
64
  const pnpmVersion = getPackageManagerVersion('pnpm', root);
64
- const useExec = (0, semver_1.gte)(pnpmVersion, '6.13.0');
65
+ const modernPnpm = (0, semver_1.gte)(pnpmVersion, '6.13.0');
65
66
  const includeDoubleDashBeforeArgs = (0, semver_1.lt)(pnpmVersion, '7.0.0');
66
67
  const isPnpmWorkspace = (0, fs_1.existsSync)((0, path_1.join)(root, 'pnpm-workspace.yaml'));
67
68
  return {
@@ -70,7 +71,8 @@ function getPackageManagerCommand(packageManager = detectPackageManager(), root
70
71
  add: isPnpmWorkspace ? 'pnpm add -w' : 'pnpm add',
71
72
  addDev: isPnpmWorkspace ? 'pnpm add -Dw' : 'pnpm add -D',
72
73
  rm: 'pnpm rm',
73
- exec: useExec ? 'pnpm exec' : 'pnpx',
74
+ exec: modernPnpm ? 'pnpm exec' : 'pnpx',
75
+ dlx: modernPnpm ? 'pnpm dlx' : 'pnpx',
74
76
  run: (script, args) => includeDoubleDashBeforeArgs
75
77
  ? `pnpm run ${script} -- ${args}`
76
78
  : `pnpm run ${script} ${args}`,
@@ -87,6 +89,7 @@ function getPackageManagerCommand(packageManager = detectPackageManager(), root
87
89
  addDev: 'npm install -D',
88
90
  rm: 'npm rm',
89
91
  exec: 'npx',
92
+ dlx: 'npx',
90
93
  run: (script, args) => `npm run ${script} -- ${args}`,
91
94
  list: 'npm ls',
92
95
  };
@@ -532,10 +532,25 @@ function getPromptsForSchema(opts, schema, projectsConfigurations) {
532
532
  // Normalize x-prompt
533
533
  if (typeof v['x-prompt'] === 'string') {
534
534
  const message = v['x-prompt'];
535
- v['x-prompt'] = {
536
- type: v.type === 'boolean' ? 'confirm' : 'input',
537
- message,
538
- };
535
+ if (v.type === 'boolean') {
536
+ v['x-prompt'] = {
537
+ type: 'confirm',
538
+ message,
539
+ };
540
+ }
541
+ else if (v.type === 'array' && v.items?.enum) {
542
+ v['x-prompt'] = {
543
+ type: 'multiselect',
544
+ items: v.items.enum,
545
+ message,
546
+ };
547
+ }
548
+ else {
549
+ v['x-prompt'] = {
550
+ type: 'input',
551
+ message,
552
+ };
553
+ }
539
554
  }
540
555
  question.message = v['x-prompt'].message;
541
556
  question.validate = (s) => {