nx 23.2.0-beta.7 → 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 (188) hide show
  1. package/dist/bin/init-local.js +3 -5
  2. package/dist/release/changelog-renderer/index.js +4 -5
  3. package/dist/src/adapter/ngcli-adapter.js +60 -1
  4. package/dist/src/ai/set-up-ai-agents/set-up-ai-agents.js +2 -2
  5. package/dist/src/command-line/completion/command-object.js +7 -12
  6. package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +17 -23
  7. package/dist/src/command-line/format/format.js +84 -101
  8. package/dist/src/command-line/generate/generate.js +35 -35
  9. package/dist/src/command-line/import/import.js +30 -40
  10. package/dist/src/command-line/init/ai-agent-prompts.js +5 -11
  11. package/dist/src/command-line/init/command-object.js +4 -2
  12. package/dist/src/command-line/init/configure-plugins.js +4 -1
  13. package/dist/src/command-line/init/implementation/add-nx-to-monorepo.js +12 -32
  14. package/dist/src/command-line/init/implementation/add-nx-to-nest.js +17 -21
  15. package/dist/src/command-line/init/implementation/add-nx-to-npm-repo.js +8 -21
  16. package/dist/src/command-line/init/implementation/add-nx-to-turborepo.js +3 -17
  17. package/dist/src/command-line/init/implementation/angular/index.js +10 -15
  18. package/dist/src/command-line/init/implementation/angular/legacy-angular-versions.js +2 -0
  19. package/dist/src/command-line/init/implementation/angular/standalone-workspace.js +8 -2
  20. package/dist/src/command-line/init/implementation/check-compatible-with-plugins.js +2 -0
  21. package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +5 -0
  22. package/dist/src/command-line/init/implementation/format.d.ts +18 -0
  23. package/dist/src/command-line/init/implementation/format.js +114 -0
  24. package/dist/src/command-line/init/implementation/utils.js +8 -0
  25. package/dist/src/command-line/init/init-v1.js +15 -18
  26. package/dist/src/command-line/init/init-v2.js +37 -56
  27. package/dist/src/command-line/migrate/agentic/definitions.js +35 -8
  28. package/dist/src/command-line/migrate/agentic/handoff-gitignore.d.ts +22 -3
  29. package/dist/src/command-line/migrate/agentic/handoff-gitignore.js +13 -10
  30. package/dist/src/command-line/migrate/agentic/handoff.d.ts +3 -1
  31. package/dist/src/command-line/migrate/agentic/handoff.js +4 -2
  32. package/dist/src/command-line/migrate/agentic/run-step.js +1 -0
  33. package/dist/src/command-line/migrate/agentic/runner.js +24 -24
  34. package/dist/src/command-line/migrate/agentic/select.js +20 -30
  35. package/dist/src/command-line/migrate/agentic/types.d.ts +19 -3
  36. package/dist/src/command-line/migrate/agentic/types.js +13 -4
  37. package/dist/src/command-line/migrate/command-object.d.ts +3 -0
  38. package/dist/src/command-line/migrate/command-object.js +13 -0
  39. package/dist/src/command-line/migrate/execute-migration.d.ts +14 -0
  40. package/dist/src/command-line/migrate/execute-migration.js +30 -9
  41. package/dist/src/command-line/migrate/migrate-analytics.d.ts +28 -0
  42. package/dist/src/command-line/migrate/migrate-analytics.js +51 -1
  43. package/dist/src/command-line/migrate/migrate-commits.d.ts +8 -2
  44. package/dist/src/command-line/migrate/migrate-commits.js +66 -19
  45. package/dist/src/command-line/migrate/migrate-config.d.ts +4 -2
  46. package/dist/src/command-line/migrate/migrate-config.js +12 -4
  47. package/dist/src/command-line/migrate/migrate.d.ts +13 -2
  48. package/dist/src/command-line/migrate/migrate.js +243 -80
  49. package/dist/src/command-line/migrate/multi-major.js +7 -10
  50. package/dist/src/command-line/migrate/resolve-package-version.js +4 -8
  51. package/dist/src/command-line/migrate/run/agent-output.d.ts +20 -0
  52. package/dist/src/command-line/migrate/run/agent-output.js +65 -0
  53. package/dist/src/command-line/migrate/run/index.d.ts +7 -0
  54. package/dist/src/command-line/migrate/run/index.js +19 -1
  55. package/dist/src/command-line/migrate/run/orchestrator.d.ts +20 -0
  56. package/dist/src/command-line/migrate/run/orchestrator.js +1200 -0
  57. package/dist/src/command-line/migrate/run/run-id.d.ts +16 -0
  58. package/dist/src/command-line/migrate/run/run-id.js +56 -0
  59. package/dist/src/command-line/migrate/run/run-state.d.ts +157 -0
  60. package/dist/src/command-line/migrate/run/run-state.js +438 -0
  61. package/dist/src/command-line/migrate/run/state-lock.d.ts +25 -0
  62. package/dist/src/command-line/migrate/run/state-lock.js +76 -0
  63. package/dist/src/command-line/migrate/run/state-machine.d.ts +84 -0
  64. package/dist/src/command-line/migrate/run/state-machine.js +315 -0
  65. package/dist/src/command-line/migrate/run/util.d.ts +58 -0
  66. package/dist/src/command-line/migrate/run/util.js +139 -7
  67. package/dist/src/command-line/migrate/run/worker.d.ts +1 -0
  68. package/dist/src/command-line/migrate/run/worker.js +308 -45
  69. package/dist/src/command-line/migrate/safe-prompt.d.ts +14 -26
  70. package/dist/src/command-line/migrate/safe-prompt.js +32 -43
  71. package/dist/src/command-line/migrate/step-actions.d.ts +5 -0
  72. package/dist/src/command-line/migrate/step-actions.js +12 -0
  73. package/dist/src/command-line/migrate/text.d.ts +18 -0
  74. package/dist/src/command-line/migrate/text.js +26 -0
  75. package/dist/src/command-line/migrate/version-skew-guard.d.ts +6 -4
  76. package/dist/src/command-line/migrate/version-skew-guard.js +34 -14
  77. package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.js +16 -20
  78. package/dist/src/command-line/release/changelog.js +6 -17
  79. package/dist/src/command-line/release/plan.js +15 -28
  80. package/dist/src/command-line/release/release.js +6 -17
  81. package/dist/src/command-line/release/utils/remote-release-clients/github.js +16 -22
  82. package/dist/src/command-line/release/utils/remote-release-clients/gitlab.js +13 -22
  83. package/dist/src/command-line/release/utils/resolve-semver-specifier.js +19 -41
  84. package/dist/src/command-line/release/version/resolve-current-version.js +7 -10
  85. package/dist/src/command-line/release/version.js +2 -2
  86. package/dist/src/core/graph/main.js +1 -1
  87. package/dist/src/daemon/client/client.js +11 -2
  88. package/dist/src/devkit-internals.d.ts +7 -2
  89. package/dist/src/devkit-internals.js +22 -6
  90. package/dist/src/generators/internal-utils/{format-changed-files-with-prettier-if-available.d.ts → format-changed-files.d.ts} +6 -6
  91. package/dist/src/generators/internal-utils/format-changed-files.js +163 -0
  92. package/dist/src/generators/testing-utils/create-tree-with-empty-workspace.d.ts +15 -0
  93. package/dist/src/generators/testing-utils/create-tree-with-empty-workspace.js +21 -3
  94. package/dist/src/migrations/update-15-0-0/prefix-outputs.js +2 -2
  95. package/dist/src/migrations/update-16-0-0/remove-nrwl-cli.js +2 -2
  96. package/dist/src/migrations/update-16-0-0/update-depends-on-to-tokens.js +2 -2
  97. package/dist/src/migrations/update-16-0-0/update-nx-cloud-runner.js +2 -2
  98. package/dist/src/migrations/update-16-2-0/remove-run-commands-output-path.js +2 -2
  99. package/dist/src/migrations/update-17-0-0/rm-default-collection-npm-scope.js +2 -2
  100. package/dist/src/migrations/update-17-0-0/use-minimal-config-for-tasks-runner-options.js +2 -2
  101. package/dist/src/migrations/update-17-2-0/move-default-base.js +2 -2
  102. package/dist/src/migrations/update-18-0-0/disable-crystal-for-existing-workspaces.js +2 -2
  103. package/dist/src/migrations/update-19-2-4/set-project-name.js +2 -2
  104. package/dist/src/migrations/update-20-0-0/move-use-daemon-process.js +2 -2
  105. package/dist/src/migrations/update-20-0-1/use-legacy-cache.js +2 -2
  106. package/dist/src/migrations/update-21-0-0/release-changelog-config-changes.js +2 -2
  107. package/dist/src/migrations/update-21-0-0/release-version-config-changes.js +2 -2
  108. package/dist/src/migrations/update-21-0-0/remove-custom-tasks-runner.js +2 -2
  109. package/dist/src/migrations/update-21-0-0/remove-legacy-cache.js +2 -2
  110. package/dist/src/migrations/update-22-0-0/consolidate-release-tag-config.js +2 -2
  111. package/dist/src/migrations/update-22-0-0/release-version-config-changes.js +2 -2
  112. package/dist/src/migrations/update-22-2-0/add-self-healing-to-gitignore.js +2 -2
  113. package/dist/src/migrations/update-22-6-0/add-claude-settings-local-to-git-ignore.js +2 -2
  114. package/dist/src/migrations/update-22-6-0/add-claude-worktrees-to-git-ignore.js +2 -2
  115. package/dist/src/migrations/update-22-7-0/add-polygraph-to-git-ignore.js +2 -2
  116. package/dist/src/migrations/update-23-0-0/add-migrate-runs-to-git-ignore.js +2 -2
  117. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.d.ts +12 -0
  118. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.js +250 -0
  119. package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.md +50 -0
  120. package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
  121. package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
  122. package/dist/src/nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud.js +3 -3
  123. package/dist/src/plugins/js/lock-file/bun-parser.js +43 -10
  124. package/dist/src/project-graph/utils/project-configuration/target-normalization.js +128 -2
  125. package/dist/src/tasks-runner/run-command.js +17 -32
  126. package/dist/src/tasks-runner/task-env.js +5 -2
  127. package/dist/src/tasks-runner/utils.js +2 -6
  128. package/dist/src/utils/analytics-prompt.js +4 -7
  129. package/dist/src/utils/chunkify.d.ts +7 -1
  130. package/dist/src/utils/chunkify.js +10 -3
  131. package/dist/src/utils/exit-codes.d.ts +9 -0
  132. package/dist/src/utils/exit-codes.js +19 -0
  133. package/dist/src/utils/fileutils.d.ts +5 -0
  134. package/dist/src/utils/fileutils.js +7 -2
  135. package/dist/src/utils/formatters/index.d.ts +13 -0
  136. package/dist/src/utils/formatters/index.js +74 -0
  137. package/dist/src/utils/formatters/oxfmt.d.ts +32 -0
  138. package/dist/src/utils/formatters/oxfmt.js +764 -0
  139. package/dist/src/utils/formatters/prettier.d.ts +26 -0
  140. package/dist/src/utils/formatters/prettier.js +201 -0
  141. package/dist/src/utils/formatters/shared.d.ts +5 -0
  142. package/dist/src/utils/formatters/shared.js +8 -0
  143. package/dist/src/utils/git-utils.d.ts +33 -2
  144. package/dist/src/utils/git-utils.js +156 -8
  145. package/dist/src/utils/ignore.d.ts +47 -5
  146. package/dist/src/utils/ignore.js +93 -11
  147. package/dist/src/utils/long-running-target.d.ts +10 -0
  148. package/dist/src/utils/long-running-target.js +19 -0
  149. package/dist/src/utils/min-release-age/behavior/bun.js +7 -11
  150. package/dist/src/utils/min-release-age/behavior/npm.js +5 -2
  151. package/dist/src/utils/min-release-age/packument.js +1 -1
  152. package/dist/src/utils/nx-console-prompt.js +3 -6
  153. package/dist/src/utils/package-manager-config/bunfig.d.ts +14 -0
  154. package/dist/src/utils/package-manager-config/bunfig.js +49 -0
  155. package/dist/src/utils/package-manager-config/npmrc.d.ts +23 -0
  156. package/dist/src/utils/package-manager-config/npmrc.js +124 -0
  157. package/dist/src/utils/package-manager-config/pnpm-config.d.ts +17 -0
  158. package/dist/src/utils/package-manager-config/pnpm-config.js +60 -0
  159. package/dist/src/utils/package-manager.d.ts +21 -2
  160. package/dist/src/utils/package-manager.js +244 -47
  161. package/dist/src/utils/params.d.ts +7 -1
  162. package/dist/src/utils/params.js +64 -6
  163. package/dist/src/utils/prompt-helpers.d.ts +53 -0
  164. package/dist/src/utils/prompt-helpers.js +111 -0
  165. package/dist/src/utils/provenance.js +6 -14
  166. package/dist/src/utils/registry-config/bun.d.ts +2 -0
  167. package/dist/src/utils/registry-config/bun.js +257 -0
  168. package/dist/src/utils/registry-config/index.d.ts +13 -0
  169. package/dist/src/utils/registry-config/index.js +102 -0
  170. package/dist/src/utils/registry-config/pnpm.d.ts +2 -0
  171. package/dist/src/utils/registry-config/pnpm.js +1551 -0
  172. package/dist/src/utils/registry-config/utils.d.ts +195 -0
  173. package/dist/src/utils/registry-config/utils.js +496 -0
  174. package/dist/src/utils/registry-config/yarn-berry.d.ts +2 -0
  175. package/dist/src/utils/registry-config/yarn-berry.js +612 -0
  176. package/dist/src/utils/registry-config/yarn-classic.d.ts +2 -0
  177. package/dist/src/utils/registry-config/yarn-classic.js +1001 -0
  178. package/dist/src/utils/safe-spawn.d.ts +24 -0
  179. package/dist/src/utils/safe-spawn.js +104 -0
  180. package/dist/src/utils/write-formatted-json-file.d.ts +3 -2
  181. package/dist/src/utils/write-formatted-json-file.js +5 -4
  182. package/migrations.json +6 -0
  183. package/package.json +17 -13
  184. package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.js +0 -88
  185. package/dist/src/utils/is-using-prettier.d.ts +0 -3
  186. package/dist/src/utils/is-using-prettier.js +0 -62
  187. package/dist/src/utils/min-release-age/npmrc.d.ts +0 -15
  188. package/dist/src/utils/min-release-age/npmrc.js +0 -45
@@ -0,0 +1,26 @@
1
+ import type { Tree } from '../../generators/tree';
2
+ /**
3
+ * Config filenames prettier discovers. Exported because generator setup must
4
+ * agree with detection - a format missing from one side gets a second,
5
+ * redundant config written next to it.
6
+ * https://prettier.io/docs/configuration
7
+ */
8
+ export declare const prettierConfigFiles: string[];
9
+ export declare function isUsingPrettier(root: string): boolean;
10
+ export declare function isUsingPrettierInTree(tree: Tree): boolean;
11
+ /**
12
+ * Keeps only the files prettier can format. oxfmt needs no equivalent - it
13
+ * silently skips file types it does not handle.
14
+ */
15
+ export declare function filterToPrettierSupportedFiles(files: string[]): Promise<string[]>;
16
+ export declare function writeWithPrettier(patterns: string[], cwd?: string): void;
17
+ export declare function checkWithPrettier(patterns: string[]): Promise<string[]>;
18
+ export declare function getPrettierPath(): string;
19
+ /**
20
+ * Quote a pattern for prettier's shell-based exec calls; oxfmt uses execFile
21
+ * and takes raw paths.
22
+ *
23
+ * Exported so `nx format` can size its chunks against the quoted length -
24
+ * patterns are chunked before they get here, and quoting grows each one.
25
+ */
26
+ export declare function quoteForShell(pattern: string): string;
@@ -0,0 +1,201 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.prettierConfigFiles = void 0;
4
+ exports.isUsingPrettier = isUsingPrettier;
5
+ exports.isUsingPrettierInTree = isUsingPrettierInTree;
6
+ exports.filterToPrettierSupportedFiles = filterToPrettierSupportedFiles;
7
+ exports.writeWithPrettier = writeWithPrettier;
8
+ exports.checkWithPrettier = checkWithPrettier;
9
+ exports.getPrettierPath = getPrettierPath;
10
+ exports.quoteForShell = quoteForShell;
11
+ const node_child_process_1 = require("node:child_process");
12
+ const node_fs_1 = require("node:fs");
13
+ const node_path_1 = require("node:path");
14
+ const semver_1 = require("semver");
15
+ const json_1 = require("../../generators/utils/json");
16
+ const fileutils_1 = require("../fileutils");
17
+ const handle_import_1 = require("../handle-import");
18
+ const package_json_1 = require("../package-json");
19
+ const shared_1 = require("./shared");
20
+ /**
21
+ * Config filenames prettier discovers. Exported because generator setup must
22
+ * agree with detection - a format missing from one side gets a second,
23
+ * redundant config written next to it.
24
+ * https://prettier.io/docs/configuration
25
+ */
26
+ exports.prettierConfigFiles = [
27
+ '.prettierrc',
28
+ '.prettierrc.json',
29
+ '.prettierrc.yml',
30
+ '.prettierrc.yaml',
31
+ '.prettierrc.json5',
32
+ '.prettierrc.js',
33
+ 'prettier.config.js',
34
+ '.prettierrc.ts',
35
+ 'prettier.config.ts',
36
+ '.prettierrc.mjs',
37
+ 'prettier.config.mjs',
38
+ '.prettierrc.mts',
39
+ 'prettier.config.mts',
40
+ '.prettierrc.cjs',
41
+ 'prettier.config.cjs',
42
+ '.prettierrc.cts',
43
+ 'prettier.config.cts',
44
+ '.prettierrc.toml',
45
+ ];
46
+ function isUsingPrettier(root) {
47
+ for (const file of exports.prettierConfigFiles) {
48
+ if ((0, node_fs_1.existsSync)((0, node_path_1.join)(root, file))) {
49
+ return true;
50
+ }
51
+ }
52
+ // Even if no file is present, it is possible the user is configuring prettier via their package.json
53
+ const packageJsonPath = (0, node_path_1.join)(root, 'package.json');
54
+ if ((0, node_fs_1.existsSync)(packageJsonPath)) {
55
+ const packageJson = (0, fileutils_1.readJsonFile)(packageJsonPath);
56
+ if (packageJson.prettier) {
57
+ return true;
58
+ }
59
+ }
60
+ return false;
61
+ }
62
+ function isUsingPrettierInTree(tree) {
63
+ for (const file of exports.prettierConfigFiles) {
64
+ if (tree.exists(file)) {
65
+ return true;
66
+ }
67
+ }
68
+ // Even if no file is present, it is possible the user is configuring prettier via their package.json
69
+ if (tree.exists('package.json')) {
70
+ const packageJson = (0, json_1.readJson)(tree, 'package.json');
71
+ if (packageJson.prettier) {
72
+ return true;
73
+ }
74
+ }
75
+ return false;
76
+ }
77
+ /**
78
+ * Keeps only the files prettier can format. oxfmt needs no equivalent - it
79
+ * silently skips file types it does not handle.
80
+ */
81
+ async function filterToPrettierSupportedFiles(files) {
82
+ const prettier = await (0, handle_import_1.handleImport)('prettier');
83
+ const supportInfo = await prettier.getSupportInfo();
84
+ const supportedExtensions = new Set(supportInfo.languages
85
+ .flatMap((language) => language.extensions)
86
+ .filter((extension) => !!extension));
87
+ // Prettier matches ~30 files by *name* rather than extension (`.swcrc`,
88
+ // `Jakefile`). It publishes that list next to the extensions, so read it
89
+ // rather than hardcoding.
90
+ const supportedFilenames = new Set(supportInfo.languages.flatMap((language) => language.filenames ?? []));
91
+ return files.filter((file) => supportedExtensions.has((0, node_path_1.extname)(file)) ||
92
+ supportedFilenames.has((0, node_path_1.basename)(file)));
93
+ }
94
+ function writeWithPrettier(patterns,
95
+ // Defaults to the caller's cwd. `nx init` sets it so it can pass paths
96
+ // relative to the repo root rather than absolute ones the user has to read.
97
+ cwd) {
98
+ if (patterns.length === 0) {
99
+ // Prettier with no file arguments reads stdin, and `stdio: [0, 1, 2]` hands
100
+ // it nx's own - from a terminal it blocks forever with nothing on screen. At
101
+ // EOF it exits 0 under `--list-different` and 2 (which `execSync` throws on)
102
+ // without it, so which failure you get depends on `shouldUseListDifferent`.
103
+ return;
104
+ }
105
+ const prettierPath = getPrettierPath();
106
+ const listDifferentArg = shouldUseListDifferent() ? '--list-different ' : '';
107
+ // No `--parser json` special case for `.swcrc`: prettier's own language table
108
+ // maps it to the json parser, so it formats correctly on its own (measured).
109
+ // Splitting the batch also meant one of the two spawns could receive zero
110
+ // files, which is the error above.
111
+ (0, node_child_process_1.execSync)(`node ${quoteForShell(prettierPath)} --write ${listDifferentArg}-- ${patterns
112
+ .map(quoteForShell)
113
+ .join(' ')}`, {
114
+ cwd,
115
+ stdio: [0, 1, 2],
116
+ windowsHide: true,
117
+ });
118
+ }
119
+ function checkWithPrettier(patterns) {
120
+ const prettierPath = getPrettierPath();
121
+ return new Promise((resolve, reject) => {
122
+ (0, node_child_process_1.exec)(`node ${quoteForShell(prettierPath)} --list-different -- ${patterns
123
+ .map(quoteForShell)
124
+ .join(' ')}`, { encoding: 'utf-8', windowsHide: true, maxBuffer: shared_1.FORMATTER_MAX_BUFFER }, (error, stdout) => {
125
+ if (error) {
126
+ // As the oxfmt sibling: a spawn failure, kill or maxBuffer overrun reports a
127
+ // string `code` or none. Prettier signals "files differ" numerically, so
128
+ // treating these as a file list would pass `format:check` on a formatter
129
+ // that never ran.
130
+ if (typeof error['code'] !== 'number') {
131
+ reject(new Error(`prettier could not be run to completion (${error['code'] ?? error.signal ?? 'unknown'}): ${error.message}`));
132
+ return;
133
+ }
134
+ // Only `Mismatch` means "files differ", as in `checkWithOxfmt`. `Failure`
135
+ // still prints the files prettier got through - measured, one differing plus
136
+ // one unparseable exits 2 with the differing file on stdout - so reading
137
+ // stdout there would swallow the syntax error.
138
+ if (error['code'] !== 1 /* PrettierExitCode.Mismatch */ ||
139
+ stdout.length === 0) {
140
+ reject(error);
141
+ return;
142
+ }
143
+ resolve(stdout.trim().split('\n'));
144
+ }
145
+ else {
146
+ resolve([]);
147
+ }
148
+ });
149
+ });
150
+ }
151
+ let prettierPath;
152
+ function getPrettierPath() {
153
+ if (prettierPath) {
154
+ return prettierPath;
155
+ }
156
+ const { packageJson, path: packageJsonPath } = (0, package_json_1.readModulePackageJson)('prettier');
157
+ const bin = packageJson.bin;
158
+ const binPath = typeof bin === 'string' ? bin : bin?.['prettier'];
159
+ if (!binPath) {
160
+ throw new Error(`Could not find prettier binary in ${packageJsonPath}`);
161
+ }
162
+ prettierPath = (0, node_path_1.resolve)((0, node_path_1.dirname)(packageJsonPath), binPath);
163
+ return prettierPath;
164
+ }
165
+ let useListDifferent;
166
+ /**
167
+ * Determines if --list-different should be used with --write.
168
+ * Prettier 4+ and 3.6.x with experimental CLI don't support combining these flags.
169
+ */
170
+ function shouldUseListDifferent() {
171
+ if (useListDifferent !== undefined) {
172
+ return useListDifferent;
173
+ }
174
+ try {
175
+ const { packageJson } = (0, package_json_1.readModulePackageJson)('prettier');
176
+ const prettierMajor = (0, semver_1.major)(packageJson.version);
177
+ const isExperimentalCli = process.env.PRETTIER_EXPERIMENTAL_CLI === '1';
178
+ useListDifferent = prettierMajor < 4 && !isExperimentalCli;
179
+ }
180
+ catch {
181
+ useListDifferent = false;
182
+ }
183
+ return useListDifferent;
184
+ }
185
+ /**
186
+ * Quote a pattern for prettier's shell-based exec calls; oxfmt uses execFile
187
+ * and takes raw paths.
188
+ *
189
+ * Exported so `nx format` can size its chunks against the quoted length -
190
+ * patterns are chunked before they get here, and quoting grows each one.
191
+ */
192
+ function quoteForShell(pattern) {
193
+ // Interpolated into a command string, so every character special *inside
194
+ // double quotes* needs escaping, not just `$`: a backtick substitutes, `"`
195
+ // closes the quoting, `\` escapes what follows. One pass over the original,
196
+ // since `String.replace` never re-scans what it inserted.
197
+ const escaped = process.platform !== 'win32'
198
+ ? pattern.replace(/([\\"`$])/g, '\\$1')
199
+ : pattern;
200
+ return `"${escaped}"`;
201
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Formatters list every mismatching path on stdout, which overruns Node's 1MB
3
+ * default on a large workspace.
4
+ */
5
+ export declare const FORMATTER_MAX_BUFFER: number;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FORMATTER_MAX_BUFFER = void 0;
4
+ /**
5
+ * Formatters list every mismatching path on stdout, which overruns Node's 1MB
6
+ * default on a large workspace.
7
+ */
8
+ exports.FORMATTER_MAX_BUFFER = 50 * 1024 * 1024;
@@ -52,8 +52,21 @@ export declare function isShallowRepository(directory?: string): boolean;
52
52
  */
53
53
  export declare function getFirstCommitSha(directory?: string): string | null;
54
54
  export declare function isGitRepository(directory?: string): boolean;
55
+ export type GitRepositoryStatus = 'git' | 'not-git' | 'unknown';
56
+ /**
57
+ * Like `isGitRepository`, but separates "this is not a git repository" from
58
+ * "the probe itself failed" (git not installed, permissions). Callers gating
59
+ * destructive or unverifiable behavior on the answer must fail closed on
60
+ * 'unknown' instead of reading a broken probe as a missing repository.
61
+ */
62
+ export declare function getGitRepositoryStatus(directory?: string): GitRepositoryStatus;
55
63
  export declare function getGitCurrentBranch(directory?: string): string | null;
56
- export declare function hasUncommittedChanges(directory?: string): boolean;
64
+ export declare function getGitRemoteNames(directory?: string): string[];
65
+ export type WorkingTreeStatus = 'dirty' | 'clean' | 'unknown';
66
+ export declare function getWorkingTreeStatus(directory?: string, excludePaths?: string[]): WorkingTreeStatus;
67
+ export declare function hasUncommittedChanges(directory?: string, excludePaths?: string[]): boolean;
68
+ export type PathCommitExposure = 'ignored' | 'tracked' | 'unignored' | 'unknown';
69
+ export declare function getPathCommitExposure(dirPath: string, directory?: string): PathCommitExposure;
57
70
  export declare function getUncommittedChangesSnapshot(directory?: string): string;
58
71
  export declare function commitChanges(commitMessage: string, directory?: string): string | null;
59
72
  /**
@@ -66,6 +79,24 @@ export declare function commitChanges(commitMessage: string, directory?: string)
66
79
  * Returns `null` (rather than throwing) when the commit itself succeeded
67
80
  * but `git rev-parse HEAD` failed transiently — by contract the diff is
68
81
  * no longer in the working tree, so callers must NOT report it as such.
82
+ *
83
+ * `excludePaths` are `directory`-relative paths the commit must not capture,
84
+ * whatever the ignore rules say. Their working-tree files are left intact;
85
+ * only their index entries are put back to HEAD's state. Paths come from
86
+ * callers' own constants, never from user input.
69
87
  */
70
- export declare function tryCommitChanges(commitMessage: string, directory: string): string | null;
88
+ export declare function tryCommitChanges(commitMessage: string, directory: string, excludePaths?: string[]): string | null;
71
89
  export declare function getLatestCommitSha(directory?: string): string | null;
90
+ /**
91
+ * The shape of a recorded `git rev-parse` output: 40 hex chars, or 64 in a
92
+ * sha256 repository. Anything a caller persists and later interpolates into a
93
+ * command line has to be checked against this first.
94
+ */
95
+ export declare const GIT_SHA: RegExp;
96
+ /**
97
+ * Whether `ancestor` is reachable from `descendant`, i.e. resetting to
98
+ * `descendant` keeps `ancestor` in history. Returns false when the answer
99
+ * cannot be established (invalid input, not a repository, unknown commits),
100
+ * so callers treat an unverifiable commit as not preserved.
101
+ */
102
+ export declare function isAncestorCommit(ancestor: string, descendant: string, directory?: string): boolean;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.GitRepository = void 0;
3
+ exports.GIT_SHA = exports.GitRepository = void 0;
4
4
  exports.cloneFromUpstream = cloneFromUpstream;
5
5
  exports.parseVcsRemoteUrl = parseVcsRemoteUrl;
6
6
  exports.getVcsRemoteInfo = getVcsRemoteInfo;
@@ -9,12 +9,17 @@ exports.getGitRootRelativePath = getGitRootRelativePath;
9
9
  exports.isShallowRepository = isShallowRepository;
10
10
  exports.getFirstCommitSha = getFirstCommitSha;
11
11
  exports.isGitRepository = isGitRepository;
12
+ exports.getGitRepositoryStatus = getGitRepositoryStatus;
12
13
  exports.getGitCurrentBranch = getGitCurrentBranch;
14
+ exports.getGitRemoteNames = getGitRemoteNames;
15
+ exports.getWorkingTreeStatus = getWorkingTreeStatus;
13
16
  exports.hasUncommittedChanges = hasUncommittedChanges;
17
+ exports.getPathCommitExposure = getPathCommitExposure;
14
18
  exports.getUncommittedChangesSnapshot = getUncommittedChangesSnapshot;
15
19
  exports.commitChanges = commitChanges;
16
20
  exports.tryCommitChanges = tryCommitChanges;
17
21
  exports.getLatestCommitSha = getLatestCommitSha;
22
+ exports.isAncestorCommit = isAncestorCommit;
18
23
  const tslib_1 = require("tslib");
19
24
  const child_process_1 = require("child_process");
20
25
  const crypto = tslib_1.__importStar(require("crypto"));
@@ -368,6 +373,29 @@ function isGitRepository(directory) {
368
373
  return false;
369
374
  }
370
375
  }
376
+ /**
377
+ * Like `isGitRepository`, but separates "this is not a git repository" from
378
+ * "the probe itself failed" (git not installed, permissions). Callers gating
379
+ * destructive or unverifiable behavior on the answer must fail closed on
380
+ * 'unknown' instead of reading a broken probe as a missing repository.
381
+ */
382
+ function getGitRepositoryStatus(directory) {
383
+ try {
384
+ (0, child_process_1.execSync)('git rev-parse --is-inside-work-tree', {
385
+ stdio: 'pipe',
386
+ cwd: directory,
387
+ windowsHide: true,
388
+ // Force untranslated messages; the classification matches on the
389
+ // English "not a git repository".
390
+ env: { ...process.env, LC_ALL: 'C' },
391
+ });
392
+ return 'git';
393
+ }
394
+ catch (err) {
395
+ const stderr = err?.stderr?.toString() ?? '';
396
+ return /not a git repository/i.test(stderr) ? 'not-git' : 'unknown';
397
+ }
398
+ }
371
399
  // Checked-out branch name, or null when there isn't one to act on: a detached
372
400
  // HEAD reports the literal "HEAD" (treated as no branch), and any git error
373
401
  // (not a repo, no commits yet) also yields null.
@@ -385,21 +413,94 @@ function getGitCurrentBranch(directory) {
385
413
  return null;
386
414
  }
387
415
  }
416
+ // Names of the remotes configured in the repository, empty when there are
417
+ // none or the probe itself failed.
418
+ function getGitRemoteNames(directory) {
419
+ try {
420
+ return (0, child_process_1.execSync)('git remote', {
421
+ encoding: 'utf8',
422
+ cwd: directory,
423
+ stdio: ['ignore', 'pipe', 'ignore'],
424
+ windowsHide: true,
425
+ })
426
+ .split('\n')
427
+ .map((name) => name.trim())
428
+ .filter(Boolean);
429
+ }
430
+ catch {
431
+ return [];
432
+ }
433
+ }
434
+ // Tri-state working-tree probe: 'unknown' means the probe itself failed (git
435
+ // missing, spawn failure, permissions), not that the tree is clean. Callers
436
+ // that gate destructive actions on tree cleanliness must treat 'unknown' as
437
+ // unsafe rather than clean.
438
+ // `excludePaths` are left out of the probe the way `tryCommitChanges` leaves
439
+ // them out of the commit, so a tree dirty only under them reads as clean. An
440
+ // exclude-only pathspec still covers the whole tree, matching `git add -A`.
441
+ function getWorkingTreeStatus(directory, excludePaths = []) {
442
+ const pathspecs = excludePaths
443
+ .map((excludePath) => ` ":(exclude)${excludePath}"`)
444
+ .join('');
445
+ try {
446
+ const out = (0, child_process_1.execSync)(`git status --porcelain${pathspecs ? ` --${pathspecs}` : ''}`, {
447
+ encoding: 'utf8',
448
+ cwd: directory,
449
+ stdio: ['ignore', 'pipe', 'pipe'],
450
+ windowsHide: true,
451
+ });
452
+ return out.trim() === '' ? 'clean' : 'dirty';
453
+ }
454
+ catch {
455
+ return 'unknown';
456
+ }
457
+ }
388
458
  // Sync companion to `GitRepository.hasUncommittedChanges` for callers that
389
- // can't drop into the async class (e.g. the migrate orchestrator, which
390
- // branches on this before spawning subprocesses synchronously).
391
- function hasUncommittedChanges(directory) {
459
+ // can't drop into the async class. A failed probe reads as false; callers for
460
+ // whom that tolerance is unsafe use `getWorkingTreeStatus` instead.
461
+ function hasUncommittedChanges(directory, excludePaths = []) {
462
+ return getWorkingTreeStatus(directory, excludePaths) === 'dirty';
463
+ }
464
+ // Classifies whether `git add -A` commits made in `directory` can sweep in
465
+ // the directory at `dirPath`. Tracked files stay committable no matter what
466
+ // the ignore rules say (ignore rules never apply to tracked files), so
467
+ // `git ls-files` decides 'tracked' first; `git check-ignore` then splits the
468
+ // untracked remainder into 'ignored' (covered) vs 'unignored' (no
469
+ // coverage). 'unknown' means the probe itself failed (not a git repository,
470
+ // git missing); callers gating destructive behavior on the result must
471
+ // treat it as unsafe.
472
+ function getPathCommitExposure(dirPath, directory) {
392
473
  try {
393
- const out = (0, child_process_1.execSync)('git status --porcelain', {
474
+ const tracked = (0, child_process_1.execSync)(`git ls-files -- ${dirPath}`, {
394
475
  encoding: 'utf8',
395
476
  cwd: directory,
396
477
  stdio: ['ignore', 'pipe', 'pipe'],
397
478
  windowsHide: true,
398
479
  });
399
- return out.trim() !== '';
480
+ if (tracked.trim() !== '') {
481
+ return 'tracked';
482
+ }
400
483
  }
401
484
  catch {
402
- return false;
485
+ return 'unknown';
486
+ }
487
+ // Query with a trailing slash so git treats the path as a directory even
488
+ // when it does not exist on disk yet: a directory-only ignore rule (a
489
+ // trailing-slash .gitignore entry) does not match a bare query for an
490
+ // absent path, which would misreport covered workspaces as unignored.
491
+ const asDir = dirPath.endsWith('/') ? dirPath : `${dirPath}/`;
492
+ try {
493
+ (0, child_process_1.execSync)(`git check-ignore -q -- ${asDir}`, {
494
+ cwd: directory,
495
+ stdio: ['ignore', 'pipe', 'pipe'],
496
+ windowsHide: true,
497
+ });
498
+ return 'ignored';
499
+ }
500
+ catch (e) {
501
+ // check-ignore exits 1 for "not ignored"; anything else is a probe
502
+ // failure.
503
+ return e?.status === 1 ? 'unignored' : 'unknown';
403
504
  }
404
505
  }
405
506
  // Returns a content-sensitive sha1 snapshot of the working tree state for
@@ -503,8 +604,13 @@ function commitChanges(commitMessage, directory) {
503
604
  * Returns `null` (rather than throwing) when the commit itself succeeded
504
605
  * but `git rev-parse HEAD` failed transiently — by contract the diff is
505
606
  * no longer in the working tree, so callers must NOT report it as such.
607
+ *
608
+ * `excludePaths` are `directory`-relative paths the commit must not capture,
609
+ * whatever the ignore rules say. Their working-tree files are left intact;
610
+ * only their index entries are put back to HEAD's state. Paths come from
611
+ * callers' own constants, never from user input.
506
612
  */
507
- function tryCommitChanges(commitMessage, directory) {
613
+ function tryCommitChanges(commitMessage, directory, excludePaths = []) {
508
614
  try {
509
615
  (0, child_process_1.execSync)('git add -A', {
510
616
  encoding: 'utf8',
@@ -512,6 +618,20 @@ function tryCommitChanges(commitMessage, directory) {
512
618
  cwd: directory,
513
619
  windowsHide: true,
514
620
  });
621
+ // Exclusion happens as an unstage rather than an add-time pathspec:
622
+ // `git add` refuses a pathspec naming an ignored directory (exit 1) even
623
+ // as an exclusion, and an add-time pathspec cannot cover entries that
624
+ // were already staged before this call. The reset is relative to cwd, so
625
+ // a workspace nested inside a larger repo excludes its own path; a path
626
+ // with no index entry is a quiet no-op, unborn HEAD included.
627
+ for (const excludePath of excludePaths) {
628
+ (0, child_process_1.execSync)(`git reset -q -- "${excludePath}"`, {
629
+ encoding: 'utf8',
630
+ stdio: 'pipe',
631
+ cwd: directory,
632
+ windowsHide: true,
633
+ });
634
+ }
515
635
  (0, child_process_1.execSync)('git commit --no-verify -F -', {
516
636
  encoding: 'utf8',
517
637
  stdio: 'pipe',
@@ -546,3 +666,31 @@ function getLatestCommitSha(directory) {
546
666
  return null;
547
667
  }
548
668
  }
669
+ /**
670
+ * The shape of a recorded `git rev-parse` output: 40 hex chars, or 64 in a
671
+ * sha256 repository. Anything a caller persists and later interpolates into a
672
+ * command line has to be checked against this first.
673
+ */
674
+ exports.GIT_SHA = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/i;
675
+ /**
676
+ * Whether `ancestor` is reachable from `descendant`, i.e. resetting to
677
+ * `descendant` keeps `ancestor` in history. Returns false when the answer
678
+ * cannot be established (invalid input, not a repository, unknown commits),
679
+ * so callers treat an unverifiable commit as not preserved.
680
+ */
681
+ function isAncestorCommit(ancestor, descendant, directory) {
682
+ if (!exports.GIT_SHA.test(ancestor) || !exports.GIT_SHA.test(descendant)) {
683
+ return false;
684
+ }
685
+ try {
686
+ (0, child_process_1.execSync)(`git merge-base --is-ancestor ${ancestor} ${descendant}`, {
687
+ stdio: 'pipe',
688
+ windowsHide: true,
689
+ cwd: directory,
690
+ });
691
+ return true;
692
+ }
693
+ catch {
694
+ return false;
695
+ }
696
+ }
@@ -62,7 +62,7 @@ export declare function createIgnoreChainResolver(read: (path: string) => string
62
62
  * that same note. Here they are simply the entry's matchers: any one excluding
63
63
  * wins, and a negation counts only if none excluded.
64
64
  *
65
- * Two preconditions, both satisfied by a pruning walk and neither enforced:
65
+ * Two preconditions, neither enforced here:
66
66
  *
67
67
  * - `filePath` is workspace-relative POSIX and must sit under every `dir` in the
68
68
  * chain, which holds when the chain came from that file's own directory.
@@ -70,11 +70,28 @@ export declare function createIgnoreChainResolver(read: (path: string) => string
70
70
  * re-include a file inside an excluded directory, and this does not implement
71
71
  * that rule: asked directly about `dist/keep.ts` with a root `dist/` and a
72
72
  * nested `dist/.gitignore` holding `!keep.ts`, it answers "not ignored" where
73
- * git says ignored (measured). `visitNotIgnoredFiles` never asks, because it
74
- * prunes `dist/` before descending - which is what makes its answers match
75
- * git, and why that pruning is load-bearing for correctness rather than speed.
73
+ * git says ignored (measured). A pruning walk like `visitNotIgnoredFiles`
74
+ * satisfies it by never asking about anything under `dist/`; a per-file
75
+ * caller cannot, so it goes through `createAncestorAwareIgnoreChecker`,
76
+ * which checks the ancestors before asking the chain.
76
77
  */
77
78
  export declare function isIgnoredByChain(chain: ScopedIgnoreMatcher[], filePath: string): boolean;
79
+ /**
80
+ * The chain's answers plus git's excluded-ancestor rule: nothing inside an
81
+ * ignored directory can be re-included, so a nested negation must not
82
+ * resurrect a file whose ancestor an outer file excluded - the case
83
+ * `isIgnoredByChain` alone gets wrong (see its second precondition). The
84
+ * oxfmt CLI follows the same rule (measured against 0.60.0: a scan skips a
85
+ * nested `!keep.ts` under a root-ignored `dist/`), so every per-file caller -
86
+ * the cascading tree checkers and the disk-backed resolver in
87
+ * `formatters/oxfmt.ts` - goes through here.
88
+ *
89
+ * A directory's own ignore files cannot un-ignore the directory itself, so
90
+ * its verdict comes from its parent's chain - probed with a trailing slash,
91
+ * which is what makes a directory-only pattern like `dist/` match. Verdicts
92
+ * are memoized per directory, so a batch of files shares its ancestor walks.
93
+ */
94
+ export declare function createAncestorAwareIgnoreChecker(resolve: (dir: string) => ScopedIgnoreMatcher[]): TreeIgnoreChecker;
78
95
  /**
79
96
  * Directories that should never be walked, whatever the workspace's own ignore
80
97
  * files say - `node_modules`, `.git`, the nx caches.
@@ -88,7 +105,7 @@ export declare function isIgnoredByChain(chain: ScopedIgnoreMatcher[], filePath:
88
105
  */
89
106
  export declare function isAlwaysIgnored(path: string): boolean;
90
107
  /**
91
- * The chain bound to a tree, as predicates over workspace-relative POSIX paths.
108
+ * A chain's answers as predicates over workspace-relative POSIX paths.
92
109
  *
93
110
  * Files and directories are asked separately because the answers differ: a
94
111
  * pattern is only directory-only if it ends in a slash, and `ignore` will not
@@ -123,6 +140,31 @@ export declare function createGitIgnoreChecker(tree: Tree): TreeIgnoreChecker;
123
140
  * Reads from the tree rather than disk, as above.
124
141
  */
125
142
  export declare function createPrettierIgnoreChecker(tree: Tree): TreeIgnoreChecker;
143
+ /**
144
+ * What oxfmt ignores: prettier's two files, but resolved from each file's own
145
+ * directory upwards rather than the workspace root - measured against the
146
+ * oxfmt 0.60.0 CLI, which differs from prettier on exactly that axis. Still
147
+ * one matcher per file rather than merged.
148
+ *
149
+ * A config's `ignorePatterns` is not an ignore file and is not read here;
150
+ * `formatFilesWithOxfmt` applies it rooted at that config's directory.
151
+ */
152
+ export declare function createOxfmtIgnoreChecker(tree: Tree): TreeIgnoreChecker;
153
+ /**
154
+ * Exported, unlike git's and prettier's, because oxfmt has two consumers:
155
+ * this tree-backed checker and the disk-backed resolver in
156
+ * `formatters/oxfmt.ts`. A shared value is the only thing that keeps them
157
+ * agreeing, so do not restate these three anywhere.
158
+ *
159
+ * `satisfies` rather than an annotation keeps the values literal - an
160
+ * annotation widens `cascade` and `merge` to `boolean` (measured in the
161
+ * declaration emit).
162
+ */
163
+ export declare const OXFMT_IGNORE_OPTIONS: {
164
+ filenames: string[];
165
+ cascade: true;
166
+ merge: false;
167
+ };
126
168
  /**
127
169
  * `path.dirname` for the workspace-relative POSIX paths the chain is keyed by,
128
170
  * except that the workspace root is `''` rather than `.` - that is the key