nx 23.2.0-beta.8 → 23.2.0-beta.9

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.
Files changed (71) hide show
  1. package/dist/src/ai/set-up-ai-agents/set-up-ai-agents.js +2 -2
  2. package/dist/src/command-line/format/format.js +84 -101
  3. package/dist/src/command-line/import/import.js +12 -0
  4. package/dist/src/command-line/init/configure-plugins.js +4 -1
  5. package/dist/src/command-line/init/implementation/add-nx-to-nest.js +9 -0
  6. package/dist/src/command-line/init/implementation/add-nx-to-turborepo.js +3 -17
  7. package/dist/src/command-line/init/implementation/angular/index.js +4 -0
  8. package/dist/src/command-line/init/implementation/angular/legacy-angular-versions.js +2 -0
  9. package/dist/src/command-line/init/implementation/angular/standalone-workspace.js +8 -2
  10. package/dist/src/command-line/init/implementation/check-compatible-with-plugins.js +2 -0
  11. package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +5 -0
  12. package/dist/src/command-line/init/implementation/format.d.ts +18 -0
  13. package/dist/src/command-line/init/implementation/format.js +114 -0
  14. package/dist/src/command-line/init/implementation/utils.js +8 -0
  15. package/dist/src/command-line/init/init-v1.js +7 -0
  16. package/dist/src/command-line/init/init-v2.js +11 -0
  17. package/dist/src/command-line/migrate/migrate.d.ts +4 -0
  18. package/dist/src/command-line/migrate/migrate.js +64 -24
  19. package/dist/src/command-line/release/version.js +2 -2
  20. package/dist/src/daemon/client/client.js +11 -2
  21. package/dist/src/devkit-internals.d.ts +5 -2
  22. package/dist/src/devkit-internals.js +14 -6
  23. package/dist/src/generators/internal-utils/{format-changed-files-with-prettier-if-available.d.ts → format-changed-files.d.ts} +6 -6
  24. package/dist/src/generators/internal-utils/format-changed-files.js +163 -0
  25. package/dist/src/generators/testing-utils/create-tree-with-empty-workspace.d.ts +15 -0
  26. package/dist/src/generators/testing-utils/create-tree-with-empty-workspace.js +21 -3
  27. package/dist/src/migrations/update-15-0-0/prefix-outputs.js +2 -2
  28. package/dist/src/migrations/update-16-0-0/remove-nrwl-cli.js +2 -2
  29. package/dist/src/migrations/update-16-0-0/update-depends-on-to-tokens.js +2 -2
  30. package/dist/src/migrations/update-16-0-0/update-nx-cloud-runner.js +2 -2
  31. package/dist/src/migrations/update-16-2-0/remove-run-commands-output-path.js +2 -2
  32. package/dist/src/migrations/update-17-0-0/rm-default-collection-npm-scope.js +2 -2
  33. package/dist/src/migrations/update-17-0-0/use-minimal-config-for-tasks-runner-options.js +2 -2
  34. package/dist/src/migrations/update-17-2-0/move-default-base.js +2 -2
  35. package/dist/src/migrations/update-18-0-0/disable-crystal-for-existing-workspaces.js +2 -2
  36. package/dist/src/migrations/update-19-2-4/set-project-name.js +2 -2
  37. package/dist/src/migrations/update-20-0-0/move-use-daemon-process.js +2 -2
  38. package/dist/src/migrations/update-20-0-1/use-legacy-cache.js +2 -2
  39. package/dist/src/migrations/update-21-0-0/release-changelog-config-changes.js +2 -2
  40. package/dist/src/migrations/update-21-0-0/release-version-config-changes.js +2 -2
  41. package/dist/src/migrations/update-21-0-0/remove-custom-tasks-runner.js +2 -2
  42. package/dist/src/migrations/update-21-0-0/remove-legacy-cache.js +2 -2
  43. package/dist/src/migrations/update-22-0-0/consolidate-release-tag-config.js +2 -2
  44. package/dist/src/migrations/update-22-0-0/release-version-config-changes.js +2 -2
  45. package/dist/src/migrations/update-22-2-0/add-self-healing-to-gitignore.js +2 -2
  46. package/dist/src/migrations/update-22-6-0/add-claude-settings-local-to-git-ignore.js +2 -2
  47. package/dist/src/migrations/update-22-6-0/add-claude-worktrees-to-git-ignore.js +2 -2
  48. package/dist/src/migrations/update-22-7-0/add-polygraph-to-git-ignore.js +2 -2
  49. package/dist/src/migrations/update-23-0-0/add-migrate-runs-to-git-ignore.js +2 -2
  50. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.js +2 -2
  51. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  52. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  53. package/dist/src/nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud.js +3 -3
  54. package/dist/src/utils/chunkify.d.ts +7 -1
  55. package/dist/src/utils/chunkify.js +10 -3
  56. package/dist/src/utils/formatters/index.d.ts +13 -0
  57. package/dist/src/utils/formatters/index.js +74 -0
  58. package/dist/src/utils/formatters/oxfmt.d.ts +32 -0
  59. package/dist/src/utils/formatters/oxfmt.js +764 -0
  60. package/dist/src/utils/formatters/prettier.d.ts +26 -0
  61. package/dist/src/utils/formatters/prettier.js +201 -0
  62. package/dist/src/utils/formatters/shared.d.ts +5 -0
  63. package/dist/src/utils/formatters/shared.js +8 -0
  64. package/dist/src/utils/ignore.d.ts +47 -5
  65. package/dist/src/utils/ignore.js +93 -11
  66. package/dist/src/utils/write-formatted-json-file.d.ts +3 -2
  67. package/dist/src/utils/write-formatted-json-file.js +5 -4
  68. package/package.json +11 -11
  69. package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.js +0 -88
  70. package/dist/src/utils/is-using-prettier.d.ts +0 -3
  71. package/dist/src/utils/is-using-prettier.js +0 -62
@@ -7,7 +7,7 @@ const fs_1 = require("fs");
7
7
  const path_1 = require("path");
8
8
  const semver_1 = require("semver");
9
9
  const smol_toml_1 = tslib_1.__importDefault(require("smol-toml"));
10
- const format_changed_files_with_prettier_if_available_1 = require("../../generators/internal-utils/format-changed-files-with-prettier-if-available");
10
+ const format_changed_files_1 = require("../../generators/internal-utils/format-changed-files");
11
11
  const generate_files_1 = require("../../generators/utils/generate-files");
12
12
  const json_1 = require("../../generators/utils/json");
13
13
  const native_1 = require("../../native");
@@ -234,7 +234,7 @@ async function setupAiAgentsGeneratorImpl(tree, options) {
234
234
  (0, ignore_1.addEntryToGitIgnore)(tree, (0, path_1.join)(options.directory, '.gitignore'), '.nx/polygraph');
235
235
  (0, ignore_1.addEntryToGitIgnore)(tree, (0, path_1.join)(options.directory, '.gitignore'), '.claude/worktrees');
236
236
  (0, ignore_1.addEntryToGitIgnore)(tree, (0, path_1.join)(options.directory, '.gitignore'), '.claude/settings.local.json');
237
- await (0, format_changed_files_with_prettier_if_available_1.formatChangedFilesWithPrettierIfAvailable)(tree);
237
+ await (0, format_changed_files_1.formatChangedFiles)(tree);
238
238
  // we use the check variable to determine if we should actually make changes or just report what would be changed
239
239
  return async (check = false) => {
240
240
  const messages = [];
@@ -2,9 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.format = format;
4
4
  const tslib_1 = require("tslib");
5
- const node_child_process_1 = require("node:child_process");
6
5
  const path = tslib_1.__importStar(require("node:path"));
7
- const semver_1 = require("semver");
8
6
  const configuration_1 = require("../../config/configuration");
9
7
  const typescript_1 = require("../../plugins/js/utils/typescript");
10
8
  const affected_project_graph_1 = require("../../project-graph/affected/affected-project-graph");
@@ -13,59 +11,81 @@ const project_graph_1 = require("../../project-graph/project-graph");
13
11
  const chunkify_1 = require("../../utils/chunkify");
14
12
  const command_line_utils_1 = require("../../utils/command-line-utils");
15
13
  const fileutils_1 = require("../../utils/fileutils");
16
- const handle_import_1 = require("../../utils/handle-import");
14
+ const formatters_1 = require("../../utils/formatters");
15
+ const oxfmt_1 = require("../../utils/formatters/oxfmt");
16
+ const prettier_1 = require("../../utils/formatters/prettier");
17
17
  const ignore_1 = require("../../utils/ignore");
18
18
  const object_sort_1 = require("../../utils/object-sort");
19
19
  const output_1 = require("../../utils/output");
20
- const package_json_1 = require("../../utils/package-json");
21
20
  const workspace_root_1 = require("../../utils/workspace-root");
21
+ /**
22
+ * A table, not a `switch`: this lookup sits inside a `try` whose `catch`
23
+ * reports "configured but not installed", and a `never` arm would throw into
24
+ * that catch and be misreported. A missing member is a compile error here.
25
+ */
26
+ const resolveFormatterBin = {
27
+ oxfmt: oxfmt_1.getOxfmtBinPath,
28
+ prettier: prettier_1.getPrettierPath,
29
+ };
22
30
  async function format(command, args) {
23
- let prettier;
31
+ const formatterType = (0, formatters_1.detectFormatter)(workspace_root_1.workspaceRoot);
32
+ if (!formatterType) {
33
+ output_1.output.warn({
34
+ title: 'No formatter configured.',
35
+ bodyLines: ['Install oxfmt or prettier to enable formatting.'],
36
+ });
37
+ return;
38
+ }
39
+ // Detection reads configuration only, so a workspace can be configured for a
40
+ // formatter that is not installed - a fresh clone, `--omit=dev` CI, a pruned
41
+ // node_modules. Resolving now turns a raw MODULE_NOT_FOUND into something
42
+ // actionable.
24
43
  try {
25
- prettier = await (0, handle_import_1.handleImport)('prettier');
44
+ resolveFormatterBin[formatterType]();
26
45
  }
27
46
  catch {
28
47
  output_1.output.error({
29
- title: 'Prettier is not installed.',
48
+ title: `${formatterType} is configured for this workspace but is not installed.`,
30
49
  bodyLines: [
31
- `Please install "prettier" and try again, or don't run the "nx format:${command}" command.`,
50
+ `Install "${formatterType}" and try again, or remove its configuration to disable "nx format:${command}".`,
32
51
  ],
33
52
  });
34
53
  process.exit(1);
35
54
  }
36
55
  const { nxArgs } = (0, command_line_utils_1.splitArgsIntoNxArgsAndOverrides)(args, 'affected', { printWarnings: false }, (0, configuration_1.readNxJson)());
37
- const patterns = (await getPatterns(prettier, { ...args, ...nxArgs })).map((p) => {
38
- // On non-Windows, escape $ to prevent shell variable interpolation
39
- // (the shell consumes one \, so \\$ becomes \$ which the shell treats as literal $)
40
- // On Windows (cmd.exe), $ is not a special character, so escaping it would
41
- // cause prettier to look for a file with a literal \$ in the name
42
- // prettier-ignore
43
- const escaped = process.platform !== 'win32' ? p.replace(/\$/g, '\\\$') : p;
44
- return `"${escaped}"`;
56
+ // Patterns are kept raw here. Prettier is invoked through a shell so it
57
+ // quotes them at the call site; oxfmt is invoked with execFile and needs
58
+ // the unquoted paths.
59
+ const patterns = await getPatterns(formatterType, {
60
+ ...args,
61
+ ...nxArgs,
45
62
  });
46
- // Chunkify the patterns array to prevent crashing the windows terminal
47
- const chunkList = (0, chunkify_1.chunkify)(patterns);
63
+ // Chunkify the patterns array to prevent crashing the windows terminal.
64
+ // The prettier path quotes each pattern on its way to the shell, so size the
65
+ // chunks against that; oxfmt goes through execFile and gets them raw.
66
+ const chunkList = (0, chunkify_1.chunkify)(patterns, undefined, formatterType === 'prettier'
67
+ ? (pattern) => (0, prettier_1.quoteForShell)(pattern).length
68
+ : undefined);
48
69
  switch (command) {
49
70
  case 'write':
50
71
  if (nxArgs.sortRootTsconfigPaths) {
51
72
  sortTsConfig();
52
73
  }
53
74
  addRootConfigFiles(chunkList, nxArgs);
54
- chunkList.forEach((chunk) => write(prettier, chunk));
75
+ chunkList.forEach((chunk) => write(formatterType, chunk));
55
76
  break;
56
77
  case 'check': {
57
78
  const filesWithDifferentFormatting = [];
58
79
  for (const chunk of chunkList) {
59
- const files = await check(chunk);
80
+ const files = await check(formatterType, chunk);
60
81
  filesWithDifferentFormatting.push(...files);
61
82
  }
62
83
  if (filesWithDifferentFormatting.length > 0) {
63
84
  if (nxArgs.verbose) {
64
85
  output_1.output.error({
65
- title: 'The following files are not formatted correctly based on your Prettier configuration',
86
+ title: 'The following files are not formatted correctly',
66
87
  bodyLines: [
67
88
  '- Run "nx format:write" and commit the resulting diff to fix these files.',
68
- '- Please note, Prettier does not support a native way to diff the output of its check logic (https://github.com/prettier/prettier/issues/6885).',
69
89
  '',
70
90
  ...filesWithDifferentFormatting,
71
91
  ],
@@ -80,7 +100,7 @@ async function format(command, args) {
80
100
  }
81
101
  }
82
102
  }
83
- async function getPatterns(prettier, args) {
103
+ async function getPatterns(formatterType, args) {
84
104
  const allFilesPattern = ['.'];
85
105
  if (args.all) {
86
106
  return allFilesPattern;
@@ -91,16 +111,16 @@ async function getPatterns(prettier, args) {
91
111
  return getPatternsFromProjects(args.projects, graph);
92
112
  }
93
113
  const p = (0, command_line_utils_1.parseFiles)(args);
94
- const supportedExtensions = new Set((await prettier.getSupportInfo()).languages
95
- .flatMap((language) => language.extensions)
96
- .filter((extension) => !!extension)
97
- // Prettier supports ".swcrc" as a file instead of an extension
98
- // So we add ".swcrc" as a supported extension manually
99
- // which allows it to be considered for calculating "patterns"
100
- .concat('.swcrc'));
101
- const patterns = p.files
114
+ // Deleted files still show up in the changed-file set, and neither
115
+ // formatter should be handed a path that is no longer there.
116
+ let patterns = p.files
102
117
  .map((f) => path.relative(workspace_root_1.workspaceRoot, f))
103
- .filter((f) => (0, fileutils_1.fileExists)(f) && supportedExtensions.has(path.extname(f)));
118
+ .filter((f) => (0, fileutils_1.fileExists)(f));
119
+ if (formatterType === 'prettier') {
120
+ // oxfmt needs no equivalent filter - it silently skips file types it
121
+ // does not handle, and its base args keep an all-skipped run green.
122
+ patterns = await (0, prettier_1.filterToPrettierSupportedFiles)(patterns);
123
+ }
104
124
  // exclude patterns in .nxignore or .gitignore
105
125
  const nonIgnoredPatterns = (0, ignore_1.getIgnoreObject)().filter(patterns);
106
126
  if (args.libsAndApps) {
@@ -130,13 +150,10 @@ function addRootConfigFiles(chunkList, nxArgs) {
130
150
  }
131
151
  const chunk = [];
132
152
  const addToChunkIfNeeded = (file) => {
133
- if (chunkList.every((c) => !c.includes(`"${file}"`))) {
153
+ if (chunkList.every((c) => !c.includes(file))) {
134
154
  chunk.push(file);
135
155
  }
136
156
  };
137
- // if (workspaceJsonPath) {
138
- // addToChunkIfNeeded(workspaceJsonPath);
139
- // }
140
157
  ['nx.json', (0, typescript_1.getRootTsConfigFileName)()]
141
158
  .filter(Boolean)
142
159
  .forEach(addToChunkIfNeeded);
@@ -147,49 +164,43 @@ function addRootConfigFiles(chunkList, nxArgs) {
147
164
  function getPatternsFromProjects(projects, projectGraph) {
148
165
  return (0, command_line_utils_1.getProjectRoots)(projects, projectGraph);
149
166
  }
150
- function write(prettier, patterns) {
151
- if (patterns.length > 0) {
152
- const [swcrcPatterns, regularPatterns] = patterns.reduce((result, pattern) => {
153
- result[pattern.includes('.swcrc') ? 0 : 1].push(pattern);
154
- return result;
155
- }, [[], []]);
156
- const prettierPath = getPrettierPath();
157
- const listDifferentArg = shouldUseListDifferent(prettier.version)
158
- ? '--list-different '
159
- : '';
160
- (0, node_child_process_1.execSync)(`node "${prettierPath}" --write ${listDifferentArg}${regularPatterns.join(' ')}`, {
161
- stdio: [0, 1, 2],
162
- windowsHide: true,
163
- });
164
- if (swcrcPatterns.length > 0) {
165
- (0, node_child_process_1.execSync)(`node "${prettierPath}" --write ${listDifferentArg}${swcrcPatterns.join(' ')} --parser json`, {
166
- stdio: [0, 1, 2],
167
- windowsHide: true,
168
- });
167
+ function write(formatterType, patterns) {
168
+ if (patterns.length === 0) {
169
+ return;
170
+ }
171
+ switch (formatterType) {
172
+ case 'oxfmt':
173
+ (0, oxfmt_1.writeWithOxfmt)(patterns);
174
+ break;
175
+ case 'prettier':
176
+ (0, prettier_1.writeWithPrettier)(patterns);
177
+ break;
178
+ default: {
179
+ // Without this, an unhandled formatter makes `nx format:write` exit 0
180
+ // having formatted nothing, while `check()` throws - the two halves of
181
+ // the same command disagreeing.
182
+ const unhandled = formatterType;
183
+ throw new Error(`Unhandled formatter: ${unhandled}`);
169
184
  }
170
185
  }
171
186
  }
172
- async function check(patterns) {
187
+ async function check(formatterType, patterns) {
173
188
  if (patterns.length === 0) {
174
189
  return [];
175
190
  }
176
- const prettierPath = getPrettierPath();
177
- return new Promise((resolve, reject) => {
178
- (0, node_child_process_1.exec)(`node "${prettierPath}" --list-different ${patterns.join(' ')}`, { encoding: 'utf-8', windowsHide: true }, (error, stdout) => {
179
- if (error) {
180
- // The command failed because Prettier threw an error.
181
- if (stdout.length === 0) {
182
- reject(error);
183
- }
184
- // The command failed so there are files with different formatting. Prettier writes them to stdout, newline separated.
185
- resolve(stdout.trim().split('\n'));
186
- }
187
- else {
188
- // The command succeeded so there are no files with different formatting
189
- resolve([]);
190
- }
191
- });
192
- });
191
+ switch (formatterType) {
192
+ case 'oxfmt':
193
+ return (0, oxfmt_1.checkWithOxfmt)(patterns);
194
+ case 'prettier':
195
+ return (0, prettier_1.checkWithPrettier)(patterns);
196
+ default: {
197
+ // `strict: false` does not make a missing case an error on its own, but
198
+ // it does reject this assignment - so adding a formatter fails to compile
199
+ // here instead of returning undefined into a caller that spreads it.
200
+ const unhandled = formatterType;
201
+ throw new Error(`Unhandled formatter: ${unhandled}`);
202
+ }
203
+ }
193
204
  }
194
205
  function sortTsConfig() {
195
206
  try {
@@ -203,31 +214,3 @@ function sortTsConfig() {
203
214
  // catch noop
204
215
  }
205
216
  }
206
- let prettierPath;
207
- function getPrettierPath() {
208
- if (prettierPath) {
209
- return prettierPath;
210
- }
211
- const { packageJson, path: packageJsonPath } = (0, package_json_1.readModulePackageJson)('prettier');
212
- const bin = packageJson.bin;
213
- const binPath = typeof bin === 'string' ? bin : bin?.['prettier'];
214
- if (!binPath) {
215
- throw new Error(`Could not find prettier binary in ${packageJsonPath}`);
216
- }
217
- prettierPath = path.resolve(path.dirname(packageJsonPath), binPath);
218
- return prettierPath;
219
- }
220
- let useListDifferent;
221
- /**
222
- * Determines if --list-different should be used with --write.
223
- * Prettier 4+ and 3.6.x with experimental CLI don't support combining these flags.
224
- */
225
- function shouldUseListDifferent(prettierVersion) {
226
- if (useListDifferent !== undefined) {
227
- return useListDifferent;
228
- }
229
- const prettierMajor = (0, semver_1.major)(prettierVersion);
230
- const isExperimentalCli = process.env.PRETTIER_EXPERIMENTAL_CLI === '1';
231
- useListDifferent = prettierMajor < 4 && !isExperimentalCli;
232
- return useListDifferent;
233
- }
@@ -23,6 +23,7 @@ const prepare_source_repo_1 = require("./utils/prepare-source-repo");
23
23
  const merge_remote_source_1 = require("./utils/merge-remote-source");
24
24
  const minimatch_1 = require("minimatch");
25
25
  const configure_plugins_1 = require("../init/configure-plugins");
26
+ const format_1 = require("../init/implementation/format");
26
27
  const check_compatible_with_plugins_1 = require("../init/implementation/check-compatible-with-plugins");
27
28
  const native_1 = require("../../native");
28
29
  const ai_output_1 = require("./utils/ai-output");
@@ -260,6 +261,7 @@ async function importHandler(options) {
260
261
  const incompatiblePlugins = await (0, check_compatible_with_plugins_1.checkCompatibleWithPlugins)();
261
262
  if (Object.keys(incompatiblePlugins).length > 0) {
262
263
  (0, check_compatible_with_plugins_1.updatePluginsInNxJson)(workspace_root_1.workspaceRoot, incompatiblePlugins);
264
+ await (0, format_1.formatInitWrites)(workspace_root_1.workspaceRoot, 'nx import');
263
265
  await destinationGitClient.amendCommit();
264
266
  }
265
267
  }
@@ -268,6 +270,7 @@ async function importHandler(options) {
268
270
  if (installed) {
269
271
  const { succeededPlugins } = await (0, configure_plugins_1.configurePlugins)(plugins, updatePackageScripts, pmc, workspace_root_1.workspaceRoot, verbose);
270
272
  if (succeededPlugins.length > 0) {
273
+ await (0, format_1.formatInitWrites)(workspace_root_1.workspaceRoot, 'nx import');
271
274
  await destinationGitClient.amendCommit();
272
275
  }
273
276
  }
@@ -434,6 +437,7 @@ async function handlePluginOnlyMode(options, destinationGitClient, verbose) {
434
437
  if (installed) {
435
438
  const { succeededPlugins } = await (0, configure_plugins_1.configurePlugins)(plugins, updatePackageScripts, pmc, workspace_root_1.workspaceRoot, verbose);
436
439
  if (succeededPlugins.length > 0) {
440
+ await (0, format_1.formatInitWrites)(workspace_root_1.workspaceRoot, 'nx import');
437
441
  await destinationGitClient.amendCommit();
438
442
  }
439
443
  }
@@ -468,6 +472,7 @@ async function runInstallDestinationRepo(packageManager, destinationGitClient) {
468
472
  title: 'Installing dependencies for imported code',
469
473
  });
470
474
  (0, utils_1.runInstall)(workspace_root_1.workspaceRoot, packageManager, (0, package_manager_1.getPackageManagerCommand)(packageManager));
475
+ await (0, format_1.formatInitWrites)(workspace_root_1.workspaceRoot, 'nx import');
471
476
  await destinationGitClient.amendCommit();
472
477
  }
473
478
  catch (e) {
@@ -484,6 +489,7 @@ async function runPluginsInstall(plugins, pmc, destinationGitClient) {
484
489
  output_1.output.log({ title: 'Installing Plugins' });
485
490
  try {
486
491
  (0, configure_plugins_1.installPluginPackages)(workspace_root_1.workspaceRoot, pmc, plugins);
492
+ await (0, format_1.formatInitWrites)(workspace_root_1.workspaceRoot, 'nx import');
487
493
  await destinationGitClient.amendCommit();
488
494
  }
489
495
  catch (e) {
@@ -561,6 +567,12 @@ async function handleMissingWorkspacesEntry(pm, pmc, pkgPath, destinationGitClie
561
567
  return;
562
568
  }
563
569
  (0, package_manager_1.addPackagePathToWorkspaces)(pkgPath, pm, workspaces, workspace_root_1.workspaceRoot);
570
+ // That helper is shared, so it does not record for us - without this the
571
+ // drain below has nothing to do and the rewritten file ships unformatted.
572
+ // It writes pnpm-workspace.yaml for pnpm and package.json for the rest, so
573
+ // recording package.json unconditionally records a file it never touched.
574
+ (0, format_1.recordInitWrite)((0, path_1.join)(workspace_root_1.workspaceRoot, pm === 'pnpm' ? 'pnpm-workspace.yaml' : 'package.json'));
575
+ await (0, format_1.formatInitWrites)(workspace_root_1.workspaceRoot, 'nx import');
564
576
  await destinationGitClient.amendCommit();
565
577
  output_1.output.success({
566
578
  title: `Project added in workspaces`,
@@ -19,6 +19,7 @@ const configuration_1 = require("../../config/configuration");
19
19
  const versions_1 = require("../../utils/versions");
20
20
  const child_process_1 = require("../../utils/child-process");
21
21
  const fileutils_1 = require("../../utils/fileutils");
22
+ const format_1 = require("./implementation/format");
22
23
  const spinner_1 = require("../../utils/spinner");
23
24
  function installPluginPackages(repoRoot, pmc = (0, package_manager_1.getPackageManagerCommand)(), plugins) {
24
25
  if (plugins.length === 0) {
@@ -35,7 +36,9 @@ function installPluginPackages(repoRoot, pmc = (0, package_manager_1.getPackageM
35
36
  for (const plugin of plugins) {
36
37
  nxJson.installation.plugins[plugin] = versions_1.nxVersion;
37
38
  }
38
- (0, fileutils_1.writeJsonFile)((0, path_1.join)(repoRoot, 'nx.json'), nxJson);
39
+ const nxJsonPath = (0, path_1.join)(repoRoot, 'nx.json');
40
+ (0, fileutils_1.writeJsonFile)(nxJsonPath, nxJson);
41
+ (0, format_1.recordInitWrite)(nxJsonPath);
39
42
  try {
40
43
  (0, child_process_1.runNxSync)('--version', { stdio: 'pipe' });
41
44
  }
@@ -4,6 +4,7 @@ exports.addNxToNest = addNxToNest;
4
4
  const prompt_helpers_1 = require("../../../utils/prompt-helpers");
5
5
  const node_fs_1 = require("node:fs");
6
6
  const path_1 = require("path");
7
+ const format_1 = require("./format");
7
8
  const fileutils_1 = require("../../../utils/fileutils");
8
9
  const output_1 = require("../../../utils/output");
9
10
  const package_manager_1 = require("../../../utils/package-manager");
@@ -101,6 +102,7 @@ function addNestPluginToPackageJson(repoRoot) {
101
102
  json.devDependencies['@nx/nest'] = versions_1.nxVersion;
102
103
  json.devDependencies['@nx/jest'] = versions_1.nxVersion;
103
104
  (0, fileutils_1.writeJsonFile)(path, json);
105
+ (0, format_1.recordInitWrite)(path);
104
106
  }
105
107
  function createProjectJson(repoRoot, packageJson, nestCLIOptions) {
106
108
  const packageName = packageJson.name;
@@ -181,6 +183,7 @@ function createProjectJson(repoRoot, packageJson, nestCLIOptions) {
181
183
  addJestTargets(repoRoot, packageName, json, packageJson);
182
184
  }
183
185
  (0, fileutils_1.writeJsonFile)(path, json);
186
+ (0, format_1.recordInitWrite)(path);
184
187
  }
185
188
  function getJestOptions(isE2E, repoRoot, packageName, existingOptions) {
186
189
  // try get the e2e json if we find it
@@ -217,6 +220,7 @@ function tryCreateJestPreset(repoRoot) {
217
220
  const nxPreset = require('@nx/jest/preset').default;
218
221
  module.exports = {...nxPreset};
219
222
  `, 'utf8');
223
+ (0, format_1.recordInitWrite)(jestPresetPath);
220
224
  return true;
221
225
  }
222
226
  return false;
@@ -231,7 +235,9 @@ function addJestTargets(repoRoot, packageName, projectJson, packageJson) {
231
235
  unitTestOptions['preset'] = e2eTestOptions['preset'] = './jest.preset.js';
232
236
  }
233
237
  (0, node_fs_1.writeFileSync)(unitTestConfigPath, `export default ${JSON.stringify(unitTestOptions, null, 2)}`, 'utf8');
238
+ (0, format_1.recordInitWrite)(unitTestConfigPath);
234
239
  (0, node_fs_1.writeFileSync)(e2eTestConfigPath, `export default ${JSON.stringify(e2eTestOptions, null, 2)}`, 'utf8');
240
+ (0, format_1.recordInitWrite)(e2eTestConfigPath);
235
241
  projectJson.targets['test'] = {
236
242
  executor: '@nx/jest:jest',
237
243
  outputs: [`{workspaceRoot}/coverage/${packageName}`],
@@ -261,6 +267,7 @@ function addNrwlJsPluginsConfig(repoRoot) {
261
267
  };
262
268
  }
263
269
  (0, fileutils_1.writeJsonFile)(path, json);
270
+ (0, format_1.recordInitWrite)(path);
264
271
  }
265
272
  function updatePackageJsonScripts(repoRoot, isJS) {
266
273
  const path = (0, path_1.join)(repoRoot, `package.json`);
@@ -297,6 +304,7 @@ function updatePackageJsonScripts(repoRoot, isJS) {
297
304
  }
298
305
  }
299
306
  (0, fileutils_1.writeJsonFile)(path, json);
307
+ (0, format_1.recordInitWrite)(path);
300
308
  }
301
309
  function updateTsConfig(repoRoot, sourceRoot) {
302
310
  const path = (0, path_1.join)(repoRoot, `tsconfig.build.json`);
@@ -308,6 +316,7 @@ function updateTsConfig(repoRoot, sourceRoot) {
308
316
  json.include = [];
309
317
  json.include.push(`${sourceRoot}/**/*.ts`);
310
318
  (0, fileutils_1.writeJsonFile)(path, json);
319
+ (0, format_1.recordInitWrite)(path);
311
320
  }
312
321
  function removeFile(repoRoot, file) {
313
322
  const path = (0, path_1.join)(repoRoot, file);
@@ -1,12 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.addNxToTurborepo = addNxToTurborepo;
4
- const node_fs_1 = require("node:fs");
5
4
  const node_path_1 = require("node:path");
6
5
  const fileutils_1 = require("../../../utils/fileutils");
7
- const handle_import_1 = require("../../../utils/handle-import");
8
6
  const output_1 = require("../../../utils/output");
9
7
  const package_manager_1 = require("../../../utils/package-manager");
8
+ const format_1 = require("./format");
10
9
  const utils_1 = require("./utils");
11
10
  async function addNxToTurborepo(_options) {
12
11
  const repoRoot = process.cwd();
@@ -27,21 +26,8 @@ async function addNxToTurborepo(_options) {
27
26
  });
28
27
  let nxJson = (0, utils_1.createNxJsonFromTurboJson)((0, fileutils_1.readJsonFile)('turbo.json'));
29
28
  const nxJsonPath = (0, node_path_1.join)(repoRoot, 'nx.json');
30
- // Turborepo workspaces usually have prettier installed, so try and match the formatting before writing the file
31
- try {
32
- const prettier = await (0, handle_import_1.handleImport)('prettier');
33
- const config = await prettier.resolveConfig(repoRoot);
34
- (0, node_fs_1.writeFileSync)(nxJsonPath,
35
- // @ts-ignore - Always await prettier.format, in modern versions it's async
36
- await prettier.format(JSON.stringify(nxJson, null, 2), {
37
- ...(config ?? {}),
38
- parser: 'json',
39
- }));
40
- }
41
- catch (err) {
42
- // Apply fallback JSON write
43
- (0, fileutils_1.writeJsonFile)(nxJsonPath, nxJson);
44
- }
29
+ (0, fileutils_1.writeJsonFile)(nxJsonPath, nxJson);
30
+ (0, format_1.recordInitWrite)(nxJsonPath);
45
31
  const packageManager = (0, package_manager_1.detectPackageManager)(repoRoot);
46
32
  const pmc = (0, package_manager_1.getPackageManagerCommand)(packageManager);
47
33
  (0, utils_1.updateGitIgnore)(repoRoot);
@@ -14,6 +14,7 @@ const integrated_workspace_1 = require("./integrated-workspace");
14
14
  const legacy_angular_versions_1 = require("./legacy-angular-versions");
15
15
  const standalone_workspace_1 = require("./standalone-workspace");
16
16
  const connect_to_nx_cloud_1 = require("../../../nx-cloud/connect/connect-to-nx-cloud");
17
+ const format_1 = require("../format");
17
18
  const defaultCacheableOperations = [
18
19
  'build',
19
20
  'server',
@@ -29,6 +30,8 @@ async function addNxToAngularCliRepo(options) {
29
30
  if (legacyMigrationFn) {
30
31
  output_1.output.log({ title: '💽 Running migration for a legacy Angular version' });
31
32
  await legacyMigrationFn();
33
+ // The exit skips the caller's drain, so format the recorded writes here.
34
+ await (0, format_1.formatInitWrites)(repoRoot);
32
35
  process.exit(0);
33
36
  }
34
37
  output_1.output.success({
@@ -104,6 +107,7 @@ function addPluginDependencies() {
104
107
  }
105
108
  packageJson.devDependencies = (0, object_sort_1.sortObjectByKeys)(packageJson.devDependencies);
106
109
  (0, fileutils_1.writeJsonFile)(packageJsonPath, packageJson);
110
+ (0, format_1.recordInitWrite)(packageJsonPath);
107
111
  }
108
112
  async function setupWorkspace(cacheableOperations, isIntegratedMigration) {
109
113
  (0, utils_1.updateGitIgnore)(repoRoot);
@@ -12,6 +12,7 @@ const package_json_1 = require("../../../../utils/package-json");
12
12
  const package_manager_1 = require("../../../../utils/package-manager");
13
13
  const connect_to_nx_cloud_1 = require("../../../nx-cloud/connect/connect-to-nx-cloud");
14
14
  const utils_1 = require("../utils");
15
+ const format_1 = require("../format");
15
16
  // map of Angular major versions to Nx versions to use for legacy `nx init` migrations,
16
17
  // key is major Angular version and value is Nx version to use
17
18
  const nxAngularLegacyVersionMap = {
@@ -141,6 +142,7 @@ async function installDependencies(repoRoot, pkgInfo, pmc) {
141
142
  json.dependencies = (0, object_sort_1.sortObjectByKeys)(json.dependencies);
142
143
  }
143
144
  (0, fileutils_1.writeJsonFile)(`package.json`, json);
145
+ (0, format_1.recordInitWrite)('package.json');
144
146
  (0, child_process_1.execSync)(pmc.install, { stdio: [0, 1, 2], windowsHide: true });
145
147
  }
146
148
  async function resolvePackageVersion(packageName, version) {
@@ -7,6 +7,7 @@ const angular_json_1 = require("../../../../adapter/angular-json");
7
7
  const fileutils_1 = require("../../../../utils/fileutils");
8
8
  const path_1 = require("../../../../utils/path");
9
9
  const utils_1 = require("../utils");
10
+ const format_1 = require("../format");
10
11
  async function setupStandaloneWorkspace(repoRoot, cacheableOperations, workspaceTargets) {
11
12
  const angularJsonPath = (0, node_path_1.join)(repoRoot, 'angular.json');
12
13
  const angularJson = (0, fileutils_1.readJsonFile)(angularJsonPath);
@@ -25,12 +26,14 @@ async function setupStandaloneWorkspace(repoRoot, cacheableOperations, workspace
25
26
  const projects = (0, angular_json_1.toNewFormat)(angularJson).projects;
26
27
  for (const [projectName, project] of Object.entries(projects ?? {})) {
27
28
  updateProjectOutputs(repoRoot, projectName, project, cacheableOperations);
28
- (0, fileutils_1.writeJsonFile)((0, node_path_1.join)(project.root, 'project.json'), {
29
+ const projectJsonPath = (0, node_path_1.join)(project.root, 'project.json');
30
+ (0, fileutils_1.writeJsonFile)(projectJsonPath, {
29
31
  $schema: (0, path_1.normalizePath)((0, node_path_1.relative)((0, node_path_1.join)(repoRoot, project.root), (0, node_path_1.join)(repoRoot, 'node_modules/nx/schemas/project-schema.json'))),
30
32
  name: projectName,
31
33
  ...project,
32
34
  root: undefined,
33
35
  });
36
+ (0, format_1.recordInitWrite)(projectJsonPath);
34
37
  }
35
38
  (0, fs_1.unlinkSync)(angularJsonPath);
36
39
  }
@@ -91,7 +94,9 @@ function createNxJson(repoRoot, angularJson, cacheableOperations, { eslintProjec
91
94
  if (Object.keys(defaults).length > 0) {
92
95
  nxJson.targetDefaults = defaults;
93
96
  }
94
- (0, fileutils_1.writeJsonFile)((0, node_path_1.join)(repoRoot, 'nx.json'), nxJson);
97
+ const nxJsonPath = (0, node_path_1.join)(repoRoot, 'nx.json');
98
+ (0, fileutils_1.writeJsonFile)(nxJsonPath, nxJson);
99
+ (0, format_1.recordInitWrite)(nxJsonPath);
95
100
  }
96
101
  function updateProjectOutputs(repoRoot, projectName, project, cacheableOperations) {
97
102
  Object.entries(project.targets ?? {}).forEach(([targetName, target]) => {
@@ -195,4 +200,5 @@ function replaceNgWithNxInPackageJsonScripts(repoRoot) {
195
200
  .replace(/ ng /g, ' nx ');
196
201
  });
197
202
  (0, fileutils_1.writeJsonFile)(packageJsonPath, packageJson);
203
+ (0, format_1.recordInitWrite)(packageJsonPath);
198
204
  }
@@ -8,6 +8,7 @@ const picocolors_1 = require("picocolors");
8
8
  const error_types_1 = require("../../../project-graph/error-types");
9
9
  const workspace_root_1 = require("../../../utils/workspace-root");
10
10
  const fileutils_1 = require("../../../utils/fileutils");
11
+ const format_1 = require("./format");
11
12
  const output_1 = require("../../../utils/output");
12
13
  const project_graph_1 = require("../../../project-graph/project-graph");
13
14
  /**
@@ -131,4 +132,5 @@ function updatePluginsInNxJson(root = workspace_root_1.workspaceRoot, pluginToEx
131
132
  nxJson.plugins[pluginIndex] = plugin;
132
133
  });
133
134
  (0, fileutils_1.writeJsonFile)(nxJsonPath, nxJson);
135
+ (0, format_1.recordInitWrite)(nxJsonPath);
134
136
  }
@@ -12,6 +12,7 @@ exports.getBatchScriptContents = getBatchScriptContents;
12
12
  exports.sanitizeWrapperScript = sanitizeWrapperScript;
13
13
  const tslib_1 = require("tslib");
14
14
  const child_process_1 = require("child_process");
15
+ const format_1 = require("../format");
15
16
  const fs_1 = require("fs");
16
17
  const path = tslib_1.__importStar(require("path"));
17
18
  const semver_1 = require("semver");
@@ -101,6 +102,10 @@ function writeMinimalNxJson(host, version) {
101
102
  version: normalizeVersionForNxJson('nx', version),
102
103
  },
103
104
  });
105
+ (0, format_1.recordInitWrite)('nx.json');
106
+ // Only this file. The wrapper scripts written by `generateDotNxSetup`
107
+ // above (`.nx/nxw.js`, `nx`, `nx.bat`) are deliberately left out: they are
108
+ // vendored artifacts, and two of them have no formatter at all.
104
109
  }
105
110
  }
106
111
  function updateGitIgnore(host) {
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Records a file for `formatInitWrites`. Only for files a formatter handles -
3
+ * `.gitignore` and the vendored `.nx` scripts are left out rather than
4
+ * filtered later.
5
+ *
6
+ * Two recording helpers are shared with `nx import`, which drains before each
7
+ * commit amend; draining after one would leave the formatting uncommitted.
8
+ * The drain is a no-op when empty.
9
+ */
10
+ export declare function recordInitWrite(filePath: string): void;
11
+ /**
12
+ * Formats what init just wrote and nothing else: an existing repo's other
13
+ * files are not init's to reformat.
14
+ *
15
+ * Never fatal - the repo is already initialised, so a formatter that cannot
16
+ * run costs a `nx format` the user can run themselves, not their setup.
17
+ */
18
+ export declare function formatInitWrites(repoRoot: string, command?: string): Promise<void>;