@nx/js 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.
@@ -6,7 +6,6 @@ const internal_1 = require("@nx/devkit/internal");
6
6
  const node_fs_1 = require("node:fs");
7
7
  const path_1 = require("path");
8
8
  const fs_1 = require("fs");
9
- const internal_2 = require("@nx/devkit/internal");
10
9
  const strip_glob_to_base_dir_1 = require("../../utils/strip-glob-to-base-dir");
11
10
  async function copyWorkspaceModules(schema, context) {
12
11
  devkit_1.logger.log('Copying Workspace Modules to Build Directory...');
@@ -21,7 +20,7 @@ function handleWorkspaceModules(outputDirectory, packageJson, projectGraph) {
21
20
  if (!packageJson.dependencies) {
22
21
  return;
23
22
  }
24
- const workspaceModules = (0, internal_2.getWorkspacePackagesFromGraph)(projectGraph);
23
+ const workspaceModules = (0, internal_1.getWorkspacePackagesFromGraph)(projectGraph);
25
24
  const processedModules = new Set();
26
25
  const workspaceModulesDir = (0, path_1.join)(outputDirectory, 'workspace_modules');
27
26
  function calculateRelativePath(fromPkgName, toPkgName) {
@@ -6,16 +6,12 @@ const internal_1 = require("@nx/devkit/internal");
6
6
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
7
  const child_process_1 = require("child_process");
8
8
  const devkit_1 = require("@nx/devkit");
9
- const internal_2 = require("@nx/devkit/internal");
10
9
  const crypto_1 = require("crypto");
11
10
  const path = tslib_1.__importStar(require("path"));
12
11
  const path_1 = require("path");
13
12
  const buildable_libs_utils_1 = require("../../utils/buildable-libs-utils");
14
- const internal_3 = require("@nx/devkit/internal");
15
13
  const line_aware_writer_1 = require("./lib/line-aware-writer");
16
14
  const coalescing_debounce_1 = require("./lib/coalescing-debounce");
17
- const internal_4 = require("@nx/devkit/internal");
18
- const internal_5 = require("@nx/devkit/internal");
19
15
  const detect_module_format_1 = require("./lib/detect-module-format");
20
16
  const output_file_1 = require("./lib/output-file");
21
17
  const strip_glob_to_base_dir_1 = require("../../utils/strip-glob-to-base-dir");
@@ -175,7 +171,7 @@ async function* nodeExecutor(options, context) {
175
171
  // Windows cannot deliver graceful signals through this API, so
176
172
  // skip the grace period and force-kill immediately (matching the
177
173
  // previous taskkill /F behavior).
178
- await (0, internal_3.killProcessTreeGraceful)(task.childProcess.pid, signal, process.platform === 'win32' ? 0 : undefined);
174
+ await (0, internal_1.killProcessTreeGraceful)(task.childProcess.pid, signal, process.platform === 'win32' ? 0 : undefined);
179
175
  }
180
176
  if (task.id === globalLineAwareWriter.currentProcessId) {
181
177
  globalLineAwareWriter.setActiveProcess(null);
@@ -237,7 +233,7 @@ async function* nodeExecutor(options, context) {
237
233
  await debouncedProcessQueue.trigger();
238
234
  };
239
235
  if ((0, devkit_1.isDaemonEnabled)()) {
240
- additionalExitHandler = await internal_2.daemonClient.registerFileWatcher({
236
+ additionalExitHandler = await internal_1.daemonClient.registerFileWatcher({
241
237
  watchProjects: [context.projectName],
242
238
  includeDependencies: true,
243
239
  }, async (err, data) => {
@@ -279,9 +275,12 @@ async function* nodeExecutor(options, context) {
279
275
  }, context);
280
276
  while (true) {
281
277
  const event = await output.next();
278
+ if (event.done) {
279
+ break;
280
+ }
282
281
  await addToQueue(null, Promise.resolve(event.value));
283
282
  await debouncedProcessQueue.trigger();
284
- if (event.done && !options.watch) {
283
+ if (!options.watch) {
285
284
  break;
286
285
  }
287
286
  }
@@ -337,7 +336,7 @@ function getFileToRun(context, project, buildOptions, buildTargetExecutor) {
337
336
  // {workspaceRoot}/dist/{projectRoot} -> dist/my-app
338
337
  const outputPath = project.data.targets[buildOptions.target]?.outputs?.[0];
339
338
  if (outputPath) {
340
- const outputFilePath = (0, internal_5.interpolate)(outputPath, {
339
+ const outputFilePath = (0, internal_1.interpolate)(outputPath, {
341
340
  projectName: project.name,
342
341
  projectRoot: project.data.root,
343
342
  workspaceRoot: context.root,
@@ -366,12 +365,12 @@ function getFileToRun(context, project, buildOptions, buildTargetExecutor) {
366
365
  return (0, path_1.join)(context.root, buildOptions.outputPath, outputFileName);
367
366
  }
368
367
  function fileToRunCorrectPath(fileToRun) {
369
- if ((0, internal_4.fileExists)(fileToRun))
368
+ if ((0, internal_1.fileExists)(fileToRun))
370
369
  return fileToRun;
371
370
  const extensionsToTry = ['.cjs', '.mjs', '.cjs.js', '.esm.js'];
372
371
  for (const ext of extensionsToTry) {
373
372
  const file = fileToRun.replace(/\.js$/, ext);
374
- if ((0, internal_4.fileExists)(file))
373
+ if ((0, internal_1.fileExists)(file))
375
374
  return file;
376
375
  }
377
376
  throw new Error(`Could not find ${fileToRun}. Make sure your build succeeded.`);
@@ -6,9 +6,6 @@ const devkit_1 = require("@nx/devkit");
6
6
  const internal_1 = require("@nx/devkit/internal");
7
7
  const fs_1 = require("fs");
8
8
  const path_1 = require("path");
9
- const internal_2 = require("@nx/devkit/internal");
10
- const internal_3 = require("@nx/devkit/internal");
11
- const internal_4 = require("@nx/devkit/internal");
12
9
  const strip_glob_to_base_dir_1 = require("../../utils/strip-glob-to-base-dir");
13
10
  async function pruneLockfileExecutor(schema, context) {
14
11
  devkit_1.logger.log('Pruning lockfile...');
@@ -33,9 +30,9 @@ async function pruneLockfileExecutor(schema, context) {
33
30
  }
34
31
  function createPrunedLockfile(packageJson, graph) {
35
32
  const packageManager = (0, devkit_1.detectPackageManager)(devkit_1.workspaceRoot);
36
- const lockfileName = (0, internal_3.getLockFileName)(packageManager);
37
- const lockFile = (0, internal_3.createLockFile)(packageJson, graph, packageManager);
38
- const workspacePackages = (0, internal_4.getWorkspacePackagesFromGraph)(graph);
33
+ const lockfileName = (0, internal_1.getLockFileName)(packageManager);
34
+ const lockFile = (0, internal_1.createLockFile)(packageJson, graph, packageManager);
35
+ const workspacePackages = (0, internal_1.getWorkspacePackagesFromGraph)(graph);
39
36
  for (const [pkgName, pkgVersion] of Object.entries(packageJson.dependencies ?? {})) {
40
37
  if (pkgVersion.startsWith('workspace:') ||
41
38
  pkgVersion.startsWith('file:') ||
@@ -125,7 +122,7 @@ function getOutputDir(schema, context) {
125
122
  if (!maybeOutputPath) {
126
123
  throw new Error(`Could not infer an output directory from the '${schema.buildTarget}' target. Please provide 'outputPath'.`);
127
124
  }
128
- maybeOutputPath = (0, internal_2.interpolate)(maybeOutputPath, {
125
+ maybeOutputPath = (0, internal_1.interpolate)(maybeOutputPath, {
129
126
  workspaceRoot: devkit_1.workspaceRoot,
130
127
  projectRoot: project.root,
131
128
  projectName: project.name,
@@ -7,7 +7,6 @@ const internal_1 = require("@nx/devkit/internal");
7
7
  const child_process_1 = require("child_process");
8
8
  const detect_port_1 = tslib_1.__importDefault(require("detect-port"));
9
9
  const node_fs_1 = require("node:fs");
10
- const internal_2 = require("@nx/devkit/internal");
11
10
  const path_1 = require("path");
12
11
  const semver_1 = require("semver");
13
12
  let childProcess;
@@ -68,7 +67,7 @@ async function verdaccioExecutor(options, context) {
68
67
  };
69
68
  }
70
69
  function getVerdaccioBinPath() {
71
- const { packageJson, path: packageJsonPath } = (0, internal_2.readModulePackageJson)('verdaccio');
70
+ const { packageJson, path: packageJsonPath } = (0, internal_1.readModulePackageJson)('verdaccio');
72
71
  const bin = typeof packageJson.bin === 'string'
73
72
  ? packageJson.bin
74
73
  : packageJson.bin['verdaccio'];
@@ -7,15 +7,27 @@ const devkit_1 = require("@nx/devkit");
7
7
  const path_1 = require("path");
8
8
  const plugin_1 = require("../../plugins/typescript/plugin");
9
9
  const assert_supported_typescript_version_1 = require("../../utils/assert-supported-typescript-version");
10
- const prettier_1 = require("../../utils/prettier");
10
+ const formatter_setup_1 = require("../../utils/formatter-setup");
11
+ const nx_formatter_internals_1 = require("../../utils/nx-formatter-internals");
11
12
  const create_ts_config_1 = require("../../utils/typescript/create-ts-config");
12
13
  const ts_config_1 = require("../../utils/typescript/ts-config");
13
14
  const ts_solution_setup_1 = require("../../utils/typescript/ts-solution-setup");
14
15
  const versions_1 = require("../../utils/versions");
15
16
  async function initGenerator(tree, schema) {
16
17
  schema.addTsPlugin ??= false;
17
- const isUsingNewTsSetup = schema.addTsPlugin || (0, ts_solution_setup_1.isUsingTsSolutionSetup)(tree);
18
- schema.formatter ??= isUsingNewTsSetup ? 'none' : 'prettier';
18
+ // Detection is the only thing here that needs the nx-side helpers, so the
19
+ // assert belongs with it: `'none'` must still work on an older peer-compatible
20
+ // nx, and it reaches no formatter code at all. An explicit `'prettier'` or
21
+ // `'oxfmt'` does not - both setups assert for themselves.
22
+ if (schema.formatter == null) {
23
+ (0, nx_formatter_internals_1.assertNxSupportsFormatters)();
24
+ // Defer to `detectFormatterInTree` rather than re-deriving: it encodes the
25
+ // oxfmt-over-prettier precedence, which a prettier-first check gets
26
+ // backwards for a workspace configured with both. Falling back to "none"
27
+ // rather than a formatter keeps this from installing one the caller never
28
+ // asked for.
29
+ schema.formatter = (0, internal_1.detectFormatterInTree)(tree) ?? 'none';
30
+ }
19
31
  return initGeneratorInternal(tree, {
20
32
  addTsConfigBase: true,
21
33
  ...schema,
@@ -90,11 +102,13 @@ async function initGeneratorInternal(tree, schema) {
90
102
  if (!schema.js) {
91
103
  devDependencies['typescript'] = versions_1.typescriptVersion;
92
104
  }
93
- if (schema.formatter === 'prettier') {
94
- const prettierTask = (0, prettier_1.generatePrettierSetup)(tree, {
95
- skipPackageJson: schema.skipPackageJson,
96
- });
97
- tasks.push(prettierTask);
105
+ // One table drives both halves of formatter setup - writing the config and
106
+ // making the package resolvable further down. They were separate `if` chains
107
+ // over the same union, forty lines apart, so a third formatter meant finding
108
+ // both.
109
+ const formatterSetup = (0, formatter_setup_1.getFormatterSetup)(schema.formatter);
110
+ if (formatterSetup) {
111
+ tasks.push(formatterSetup.setUp(tree, { skipPackageJson: schema.skipPackageJson }));
98
112
  }
99
113
  const rootTsConfigFileName = (0, ts_config_1.getRootTsConfigFileName)(tree);
100
114
  // If the root tsconfig file uses `importHelpers` then we must install tslib
@@ -109,15 +123,18 @@ async function initGeneratorInternal(tree, schema) {
109
123
  ? (0, devkit_1.addDependenciesToPackageJson)(tree, {}, devDependencies, undefined, schema.keepExistingVersions ?? true)
110
124
  : () => { };
111
125
  tasks.push(installTask);
112
- if (!schema.skipPackageJson &&
113
- // For `create-nx-workspace` or `nx g @nx/js:init`, we want to make sure users didn't set formatter to none.
114
- // For programmatic usage, the formatter is normally undefined, and we want prettier to continue to be ensured, even if not ultimately installed.
115
- schema.formatter !== 'none') {
116
- (0, devkit_1.ensurePackage)('prettier', versions_1.prettierVersion);
126
+ // `installTask` is queued, not run, so the formatter just added to
127
+ // package.json is not on disk yet; ensurePackage installs it out of band.
128
+ // Not gated on `skipFormat` - callers that pass it format later in this same
129
+ // process.
130
+ const isDryRun = !!process.env.NX_DRY_RUN && process.env.NX_DRY_RUN !== 'false';
131
+ if (formatterSetup &&
132
+ !schema.skipPackageJson &&
133
+ !isDryRun &&
134
+ process.env.NX_SKIP_FORMAT !== 'true') {
135
+ (0, devkit_1.ensurePackage)(schema.formatter, formatterSetup.version);
117
136
  }
118
137
  if (!schema.skipFormat) {
119
- // even if skipPackageJson === true, we can safely run formatFiles, prettier might
120
- // have been installed earlier and if not, the formatFiles function still handles it
121
138
  await (0, devkit_1.formatFiles)(tree);
122
139
  }
123
140
  return (0, devkit_1.runTasksInSerial)(...tasks);
@@ -1,6 +1,6 @@
1
1
  export interface InitSchema {
2
2
  addTsConfigBase?: boolean;
3
- formatter?: 'none' | 'prettier';
3
+ formatter?: 'none' | 'prettier' | 'oxfmt';
4
4
  js?: boolean;
5
5
  keepExistingVersions?: boolean;
6
6
  skipFormat?: boolean;
@@ -8,7 +8,7 @@
8
8
  "formatter": {
9
9
  "description": "The tool to use for code formatting.",
10
10
  "type": "string",
11
- "enum": ["none", "prettier"],
11
+ "enum": ["none", "prettier", "oxfmt"],
12
12
  "default": "none"
13
13
  },
14
14
  "js": {
@@ -41,8 +41,6 @@ async function libraryGeneratorInternal(tree, schema) {
41
41
  tsConfigName: schema.rootProject ? 'tsconfig.json' : 'tsconfig.base.json',
42
42
  addTsConfigBase: true,
43
43
  addTsPlugin,
44
- // In the new setup, Prettier is prompted for and installed during `create-nx-workspace`.
45
- formatter: (0, ts_solution_setup_1.isUsingTsSolutionSetup)(tree) ? 'none' : 'prettier',
46
44
  }));
47
45
  const options = await normalizeOptions(tree, schema);
48
46
  createFiles(tree, options);
@@ -111,6 +109,8 @@ async function libraryGeneratorInternal(tree, schema) {
111
109
  testEnvironment: options.testEnvironment,
112
110
  runtimeTsconfigFileName: 'tsconfig.lib.json',
113
111
  compiler: options.compiler === 'swc' ? 'swc' : 'babel',
112
+ passWithNoTests: options.passWithNoTests,
113
+ skipPackageJson: options.skipPackageJson,
114
114
  addPlugin: options.addPlugin,
115
115
  });
116
116
  tasks.push(vitestTask);
@@ -560,22 +560,20 @@ async function normalizeOptions(tree, options) {
560
560
  const hasPlugin = (0, ts_solution_setup_1.isUsingTypeScriptPlugin)(tree);
561
561
  const isUsingTsSolutionConfig = (0, ts_solution_setup_1.isUsingTsSolutionSetup)(tree);
562
562
  if (isUsingTsSolutionConfig) {
563
- options.unitTestRunner ??= await (0, internal_1.promptWhenInteractive)({
564
- type: 'autocomplete',
565
- name: 'unitTestRunner',
566
- message: `Which unit test runner would you like to use?`,
567
- choices: [{ name: 'none' }, { name: 'vitest' }, { name: 'jest' }],
568
- initial: 0,
569
- }, { unitTestRunner: 'none' }).then(({ unitTestRunner }) => unitTestRunner);
563
+ options.unitTestRunner ??= (0, internal_1.isInteractive)()
564
+ ? await (0, internal_1.selectPrompt)({
565
+ message: `Which unit test runner would you like to use?`,
566
+ choices: [{ value: 'none' }, { value: 'vitest' }, { value: 'jest' }],
567
+ })
568
+ : 'none';
570
569
  }
571
570
  else {
572
- options.unitTestRunner ??= await (0, internal_1.promptWhenInteractive)({
573
- type: 'autocomplete',
574
- name: 'unitTestRunner',
575
- message: `Which unit test runner would you like to use?`,
576
- choices: [{ name: 'jest' }, { name: 'vitest' }, { name: 'none' }],
577
- initial: 0,
578
- }, { unitTestRunner: undefined }).then(({ unitTestRunner }) => unitTestRunner);
571
+ options.unitTestRunner ??= (0, internal_1.isInteractive)()
572
+ ? await (0, internal_1.selectPrompt)({
573
+ message: `Which unit test runner would you like to use?`,
574
+ choices: [{ value: 'jest' }, { value: 'vitest' }, { value: 'none' }],
575
+ })
576
+ : undefined;
579
577
  if (!options.unitTestRunner && options.bundler === 'vite') {
580
578
  options.unitTestRunner = 'vitest';
581
579
  }
@@ -15,6 +15,7 @@ export interface LibraryGeneratorSchema {
15
15
  includeBabelRc?: boolean;
16
16
  unitTestRunner?: 'jest' | 'vitest' | 'none';
17
17
  linter?: LinterType;
18
+ formatter?: 'none' | 'prettier' | 'oxfmt';
18
19
  testEnvironment?: 'jsdom' | 'node';
19
20
  importPath?: string;
20
21
  js?: boolean;
@@ -36,6 +37,8 @@ export interface LibraryGeneratorSchema {
36
37
  addPlugin?: boolean;
37
38
  useProjectJson?: boolean;
38
39
  useTscExecutor?: boolean;
40
+ /** @internal Only honored by the vitest setup. */
41
+ passWithNoTests?: boolean;
39
42
  }
40
43
 
41
44
  export interface NormalizedLibraryGeneratorOptions
@@ -34,6 +34,11 @@
34
34
  "enum": ["none", "eslint", "oxlint"],
35
35
  "x-priority": "important"
36
36
  },
37
+ "formatter": {
38
+ "description": "The tool to use for code formatting.",
39
+ "type": "string",
40
+ "enum": ["none", "prettier", "oxfmt"]
41
+ },
37
42
  "unitTestRunner": {
38
43
  "description": "Test runner to use for unit tests.",
39
44
  "type": "string",
@@ -13,6 +13,7 @@ export * from './utils/package-json/update-package-json';
13
13
  export * from './utils/package-json/create-entry-points';
14
14
  export { libraryGenerator } from './generators/library/library';
15
15
  export { initGenerator } from './generators/init/init';
16
+ export { setUpFormatter } from './utils/formatter-setup';
16
17
  export { setupPrettierGenerator } from './generators/setup-prettier/generator';
17
18
  export { setupVerdaccio } from './generators/setup-verdaccio/generator';
18
19
  export { isValidVariable } from './utils/is-valid-variable';
package/dist/src/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createPackageJson = exports.getLockFileName = exports.createLockFile = exports.isValidVariable = exports.setupVerdaccio = exports.setupPrettierGenerator = exports.initGenerator = exports.libraryGenerator = void 0;
3
+ exports.createPackageJson = exports.getLockFileName = exports.createLockFile = exports.isValidVariable = exports.setupVerdaccio = exports.setupPrettierGenerator = exports.setUpFormatter = exports.initGenerator = exports.libraryGenerator = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  tslib_1.__exportStar(require("./utils/typescript/add-tslib-dependencies"), exports);
6
6
  tslib_1.__exportStar(require("./utils/typescript/load-ts-transformers"), exports);
@@ -19,6 +19,8 @@ var library_1 = require("./generators/library/library");
19
19
  Object.defineProperty(exports, "libraryGenerator", { enumerable: true, get: function () { return library_1.libraryGenerator; } });
20
20
  var init_1 = require("./generators/init/init");
21
21
  Object.defineProperty(exports, "initGenerator", { enumerable: true, get: function () { return init_1.initGenerator; } });
22
+ var formatter_setup_1 = require("./utils/formatter-setup");
23
+ Object.defineProperty(exports, "setUpFormatter", { enumerable: true, get: function () { return formatter_setup_1.setUpFormatter; } });
22
24
  var generator_1 = require("./generators/setup-prettier/generator");
23
25
  Object.defineProperty(exports, "setupPrettierGenerator", { enumerable: true, get: function () { return generator_1.setupPrettierGenerator; } });
24
26
  var generator_2 = require("./generators/setup-verdaccio/generator");
@@ -5,12 +5,7 @@ const internal_1 = require("@nx/devkit/internal");
5
5
  const devkit_1 = require("@nx/devkit");
6
6
  const node_fs_1 = require("node:fs");
7
7
  const node_path_1 = require("node:path");
8
- const devkit_2 = require("@nx/devkit");
9
- const internal_2 = require("@nx/devkit/internal");
10
8
  const picomatch = require("picomatch");
11
- const internal_3 = require("@nx/devkit/internal");
12
- const internal_4 = require("@nx/devkit/internal");
13
- const internal_5 = require("@nx/devkit/internal");
14
9
  const util_1 = require("./util");
15
10
  let ts;
16
11
  const resolvedTypescriptPaths = {};
@@ -20,12 +15,12 @@ function resolveTypescriptPath(projectRoot, workspaceRoot) {
20
15
  // path is outside the workspace tree (e.g. pnpm's enableGlobalVirtualStore),
21
16
  // since typescript is not a declared dep.
22
17
  resolvedTypescriptPaths[projectRoot] ??= require.resolve('typescript', {
23
- paths: [projectRoot, ...(0, internal_5.getNxRequirePaths)(workspaceRoot), __dirname],
18
+ paths: [projectRoot, ...(0, internal_1.getNxRequirePaths)(workspaceRoot), __dirname],
24
19
  });
25
20
  return resolvedTypescriptPaths[projectRoot];
26
21
  }
27
22
  const TSCONFIG_CACHE_VERSION = 2;
28
- const TS_CONFIG_CACHE_PATH = (0, node_path_1.join)(internal_4.workspaceDataDirectory, 'tsconfig-files.hash');
23
+ const TS_CONFIG_CACHE_PATH = (0, node_path_1.join)(internal_1.workspaceDataDirectory, 'tsconfig-files.hash');
29
24
  // Module-level cache store — each invocation gets a unique Symbol key
30
25
  const cacheStore = new Map();
31
26
  // Shared tsconfig cache — initialized once per batch, persisted to disk
@@ -117,8 +112,8 @@ const tsConfigGlob = '**/tsconfig*.json';
117
112
  exports.createNodesV2 = [
118
113
  tsConfigGlob,
119
114
  async (configFilePaths, options, context) => {
120
- const optionsHash = (0, internal_2.hashObject)(options);
121
- const targetsCachePath = (0, node_path_1.join)(internal_4.workspaceDataDirectory, `tsc-${optionsHash}.hash`);
115
+ const optionsHash = (0, internal_1.hashObject)(options);
116
+ const targetsCachePath = (0, node_path_1.join)(internal_1.workspaceDataDirectory, `tsc-${optionsHash}.hash`);
122
117
  const targetsCache = readFromCache(targetsCachePath);
123
118
  // Each invocation gets a unique Symbol key — guaranteed no collisions
124
119
  const cacheKey = Symbol('tsc-invocation');
@@ -136,7 +131,7 @@ exports.createNodesV2 = [
136
131
  const normalizedOptions = normalizePluginOptions(options);
137
132
  const packageManager = (0, devkit_1.detectPackageManager)(context.workspaceRoot);
138
133
  const pmc = (0, devkit_1.getPackageManagerCommand)(packageManager);
139
- const lockFileName = (0, internal_3.getLockFileName)(packageManager);
134
+ const lockFileName = (0, internal_1.getLockFileName)(packageManager);
140
135
  const { configFilePaths: validConfigFilePaths, hashes, projectRoots, } = await resolveValidConfigFilesAndHashes(configFilePaths, normalizedOptions, optionsHash, context, cache, lockFileName);
141
136
  try {
142
137
  return await (0, devkit_1.createNodesFromFiles)((configFilePath, options, context, idx) => {
@@ -171,7 +166,7 @@ exports.createNodesV2 = [
171
166
  ];
172
167
  exports.createNodes = exports.createNodesV2;
173
168
  async function resolveValidConfigFilesAndHashes(configFilePaths, options, optionsHash, context, cache, lockFileName) {
174
- const lockFileHash = (0, internal_2.hashFile)((0, node_path_1.join)(context.workspaceRoot, lockFileName)) ?? '';
169
+ const lockFileHash = (0, internal_1.hashFile)((0, node_path_1.join)(context.workspaceRoot, lockFileName)) ?? '';
175
170
  const validConfigFilePaths = [];
176
171
  const hashes = [];
177
172
  const projectRoots = [];
@@ -218,7 +213,7 @@ async function getConfigFileHash(configFilePath, workspaceRoot, project, options
218
213
  packageJson = (0, devkit_1.readJsonFile)((0, node_path_1.join)(workspaceRoot, project.root, 'package.json'));
219
214
  }
220
215
  catch { }
221
- return (0, devkit_2.hashArray)([
216
+ return (0, devkit_1.hashArray)([
222
217
  ...[
223
218
  fullConfigPath,
224
219
  ...extendedConfigFiles.files.sort(),
@@ -228,7 +223,7 @@ async function getConfigFileHash(configFilePath, workspaceRoot, project, options
228
223
  ...extendedConfigFiles.packages.sort(),
229
224
  lockFileHash,
230
225
  optionsHash,
231
- ...(packageJson ? [(0, internal_2.hashObject)(packageJson)] : []),
226
+ ...(packageJson ? [(0, internal_1.hashObject)(packageJson)] : []),
232
227
  ]);
233
228
  }
234
229
  function checkIfConfigFileShouldBeProject(config, cache) {
@@ -956,7 +951,7 @@ function getFileHash(filePath, workspaceRoot, cache) {
956
951
  const relativePath = posixRelative(workspaceRoot, filePath);
957
952
  if (!cache.fileHashes[relativePath]) {
958
953
  const content = readFile(filePath, workspaceRoot, cache);
959
- cache.fileHashes[relativePath] = (0, devkit_2.hashArray)([content]);
954
+ cache.fileHashes[relativePath] = (0, devkit_1.hashArray)([content]);
960
955
  }
961
956
  return cache.fileHashes[relativePath];
962
957
  }
@@ -4,7 +4,6 @@ exports.updateLockFile = updateLockFile;
4
4
  const devkit_1 = require("@nx/devkit");
5
5
  const child_process_1 = require("child_process");
6
6
  const internal_1 = require("@nx/devkit/internal");
7
- const internal_2 = require("@nx/devkit/internal");
8
7
  const semver_1 = require("semver");
9
8
  async function updateLockFile(cwd, { dryRun, verbose, options, }) {
10
9
  if (options?.skipLockFileUpdate) {
@@ -47,7 +46,7 @@ async function updateLockFile(cwd, { dryRun, verbose, options, }) {
47
46
  installArgs = `${installArgs} --ignore-scripts`.trim();
48
47
  }
49
48
  }
50
- const lockFile = (0, internal_2.getLockFileName)(packageManager);
49
+ const lockFile = (0, internal_1.getLockFileName)(packageManager);
51
50
  const command = `${packageManagerCommands.updateLockFile} ${installArgs}`.trim();
52
51
  if (verbose) {
53
52
  if (dryRun) {
@@ -0,0 +1,26 @@
1
+ import type { GeneratorCallback, Tree } from '@nx/devkit';
2
+ type FormatterSetup = {
3
+ setUp: (tree: Tree, options: {
4
+ skipPackageJson?: boolean;
5
+ }) => GeneratorCallback;
6
+ version: string;
7
+ };
8
+ /**
9
+ * The setup for a formatter name that came from a schema, or `undefined` for
10
+ * `'none'` and anything unrecognised.
11
+ *
12
+ * `hasOwnProperty` rather than `in`, which would answer `true` for inherited
13
+ * members like `'constructor'` and hand back an `Object.prototype` function.
14
+ */
15
+ export declare function getFormatterSetup(formatter: string | undefined): FormatterSetup | undefined;
16
+ /**
17
+ * Writes the chosen formatter's config and queues its install.
18
+ *
19
+ * For callers that only need the formatter configured - a preset that creates
20
+ * an empty workspace, say - rather than the whole of `@nx/js:init`. Does
21
+ * nothing for `'none'` or an unrecognised value.
22
+ */
23
+ export declare function setUpFormatter(tree: Tree, formatter: string | undefined, options?: {
24
+ skipPackageJson?: boolean;
25
+ }): GeneratorCallback;
26
+ export {};
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getFormatterSetup = getFormatterSetup;
4
+ exports.setUpFormatter = setUpFormatter;
5
+ const oxfmt_1 = require("./oxfmt");
6
+ const prettier_1 = require("./prettier");
7
+ const versions_1 = require("./versions");
8
+ /**
9
+ * Not `Partial`, so a new `FormatterType` member fails to compile here until it
10
+ * is set up - but only after `packages/nx` is rebuilt, since the type comes
11
+ * from its emitted declarations. The guard must stay structural: under
12
+ * `strict: false` an untyped lookup yields `any` instead of an error.
13
+ *
14
+ * The key doubles as the npm package name; callers install by it.
15
+ */
16
+ const formatterSetups = {
17
+ prettier: { setUp: prettier_1.generatePrettierSetup, version: versions_1.prettierVersion },
18
+ oxfmt: { setUp: oxfmt_1.generateOxfmtSetup, version: versions_1.oxfmtVersion },
19
+ };
20
+ /**
21
+ * The setup for a formatter name that came from a schema, or `undefined` for
22
+ * `'none'` and anything unrecognised.
23
+ *
24
+ * `hasOwnProperty` rather than `in`, which would answer `true` for inherited
25
+ * members like `'constructor'` and hand back an `Object.prototype` function.
26
+ */
27
+ function getFormatterSetup(formatter) {
28
+ return formatter !== undefined &&
29
+ Object.prototype.hasOwnProperty.call(formatterSetups, formatter)
30
+ ? formatterSetups[formatter]
31
+ : undefined;
32
+ }
33
+ /**
34
+ * Writes the chosen formatter's config and queues its install.
35
+ *
36
+ * For callers that only need the formatter configured - a preset that creates
37
+ * an empty workspace, say - rather than the whole of `@nx/js:init`. Does
38
+ * nothing for `'none'` or an unrecognised value.
39
+ */
40
+ function setUpFormatter(tree, formatter, options = {}) {
41
+ const setup = getFormatterSetup(formatter);
42
+ return setup ? setup.setUp(tree, options) : () => { };
43
+ }
@@ -16,30 +16,26 @@ async function normalizeLinterOption(tree, linter) {
16
16
  if (detected) {
17
17
  return detected;
18
18
  }
19
- // Nothing to follow, so this is a real choice. `{ linter: 'none' }` is the
20
- // non-interactive answer; `none` leads so the interactive default matches it.
21
- return await (0, internal_1.promptWhenInteractive)({
22
- type: 'autocomplete',
23
- name: 'linter',
24
- message: `Which linter would you like to use?`,
25
- choices: [{ name: 'none' }, { name: 'eslint' }, { name: 'oxlint' }],
26
- initial: 0,
27
- }, { linter: 'none' }).then(({ linter }) => linter);
19
+ // Nothing to follow, so this is a real choice. `none` is the non-interactive
20
+ // answer, and leads the list so the interactive default matches it.
21
+ return (0, internal_1.isInteractive)()
22
+ ? (0, internal_1.selectPrompt)({
23
+ message: `Which linter would you like to use?`,
24
+ choices: [{ value: 'none' }, { value: 'eslint' }, { value: 'oxlint' }],
25
+ })
26
+ : 'none';
28
27
  }
29
28
  async function normalizeUnitTestRunnerOption(tree, unitTestRunner, testRunners = ['jest', 'vitest']) {
30
29
  if (unitTestRunner) {
31
30
  return unitTestRunner;
32
31
  }
33
32
  const isTsSolutionSetup = (0, ts_solution_setup_1.isUsingTsSolutionSetup)(tree);
34
- const choices = isTsSolutionSetup
35
- ? [{ name: 'none' }, ...testRunners.map((runner) => ({ name: runner }))]
36
- : [...testRunners.map((runner) => ({ name: runner })), { name: 'none' }];
33
+ const choices = (isTsSolutionSetup ? ['none', ...testRunners] : [...testRunners, 'none']).map((value) => ({ value: value }));
37
34
  const defaultValue = (isTsSolutionSetup ? 'none' : testRunners[0]);
38
- return await (0, internal_1.promptWhenInteractive)({
39
- type: 'autocomplete',
40
- name: 'unitTestRunner',
41
- message: `Which unit test runner would you like to use?`,
42
- choices,
43
- initial: 0,
44
- }, { unitTestRunner: defaultValue }).then(({ unitTestRunner }) => unitTestRunner);
35
+ return (0, internal_1.isInteractive)()
36
+ ? (0, internal_1.selectPrompt)({
37
+ message: `Which unit test runner would you like to use?`,
38
+ choices,
39
+ })
40
+ : defaultValue;
45
41
  }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * `@nx/js` inherits `@nx/devkit`'s `nx` peer, which spans a major either
3
+ * side, so an older nx without these helpers can legally be installed. A
4
+ * missing CommonJS named export arrives as `undefined`, so the first use
5
+ * would otherwise be a bare `undefined.every` naming neither package nor
6
+ * cause.
7
+ */
8
+ export declare function assertNxSupportsFormatters(): void;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assertNxSupportsFormatters = assertNxSupportsFormatters;
4
+ const internal_1 = require("@nx/devkit/internal");
5
+ /**
6
+ * `@nx/js` inherits `@nx/devkit`'s `nx` peer, which spans a major either
7
+ * side, so an older nx without these helpers can legally be installed. A
8
+ * missing CommonJS named export arrives as `undefined`, so the first use
9
+ * would otherwise be a bare `undefined.every` naming neither package nor
10
+ * cause.
11
+ */
12
+ function assertNxSupportsFormatters() {
13
+ if (internal_1.detectFormatterInTree && internal_1.oxfmtConfigFiles && internal_1.prettierConfigFiles) {
14
+ return;
15
+ }
16
+ throw new Error('The installed version of nx does not export the formatter helpers that @nx/js needs to detect and set up a formatter. ' +
17
+ 'This happens when nx and @nx/js are on different major versions. Run `nx migrate latest` to bring them into line.');
18
+ }
@@ -0,0 +1,4 @@
1
+ import { type GeneratorCallback, type Tree } from '@nx/devkit';
2
+ export declare function generateOxfmtSetup(tree: Tree, options: {
3
+ skipPackageJson?: boolean;
4
+ }): GeneratorCallback;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateOxfmtSetup = generateOxfmtSetup;
4
+ const devkit_1 = require("@nx/devkit");
5
+ // Imported rather than copied: detection ("is this workspace using oxfmt?")
6
+ // and setup ("should a config be written?") have to agree on the same list, or
7
+ // a workspace that already has a config gets a second, redundant one.
8
+ const internal_1 = require("@nx/devkit/internal");
9
+ const nx_formatter_internals_1 = require("./nx-formatter-internals");
10
+ const versions_1 = require("./versions");
11
+ function generateOxfmtSetup(tree, options) {
12
+ (0, nx_formatter_internals_1.assertNxSupportsFormatters)();
13
+ if (internal_1.oxfmtConfigFiles.every((name) => !tree.exists(name))) {
14
+ // oxfmt defaults to double quotes and we prefer single, so that is the one
15
+ // option worth setting. Line width is left at oxfmt's default.
16
+ (0, devkit_1.writeJson)(tree, '.oxfmtrc.json', { singleQuote: true });
17
+ }
18
+ // The oxc extension is what drives oxfmt in the editor, so recommend it for
19
+ // the same reason the prettier setup recommends its own. Only when the file
20
+ // is already there - creating it would push an editor choice on a workspace
21
+ // that has not made one.
22
+ if (tree.exists('.vscode/extensions.json')) {
23
+ (0, devkit_1.updateJson)(tree, '.vscode/extensions.json', (json) => {
24
+ json.recommendations ??= [];
25
+ const extension = 'oxc.oxc-vscode';
26
+ if (!json.recommendations.includes(extension)) {
27
+ json.recommendations.push(extension);
28
+ }
29
+ return json;
30
+ });
31
+ }
32
+ return options.skipPackageJson
33
+ ? () => { }
34
+ : (0, devkit_1.addDependenciesToPackageJson)(tree, {}, { oxfmt: versions_1.oxfmtVersion });
35
+ }
@@ -5,21 +5,18 @@ exports.getExports = getExports;
5
5
  exports.getUpdatedPackageJsonContent = getUpdatedPackageJsonContent;
6
6
  exports.getOutputDir = getOutputDir;
7
7
  const internal_1 = require("@nx/devkit/internal");
8
- const internal_2 = require("@nx/devkit/internal");
9
8
  const devkit_1 = require("@nx/devkit");
10
9
  const node_fs_1 = require("node:fs");
11
10
  const path_1 = require("path");
12
- const internal_3 = require("@nx/devkit/internal");
13
- const internal_4 = require("@nx/devkit/internal");
14
11
  const get_main_file_dir_1 = require("../get-main-file-dir");
15
12
  const strip_glob_to_base_dir_1 = require("../strip-glob-to-base-dir");
16
13
  function updatePackageJson(options, context, target, dependencies, fileMap = null) {
17
14
  let packageJson;
18
15
  if (fileMap == null) {
19
- fileMap = (0, internal_4.readFileMapCache)()?.fileMap?.projectFileMap || {};
16
+ fileMap = (0, internal_1.readFileMapCache)()?.fileMap?.projectFileMap || {};
20
17
  }
21
18
  if (options.updateBuildableProjectDepsInPackageJson) {
22
- packageJson = (0, internal_2.createPackageJson)(context.projectName, context.projectGraph, {
19
+ packageJson = (0, internal_1.createPackageJson)(context.projectName, context.projectGraph, {
23
20
  target: context.targetName,
24
21
  root: context.root,
25
22
  // By default we remove devDependencies since this is a production build.
@@ -32,7 +29,7 @@ function updatePackageJson(options, context, target, dependencies, fileMap = nul
32
29
  }
33
30
  else {
34
31
  const pathToPackageJson = (0, path_1.join)(context.root, options.projectRoot, 'package.json');
35
- packageJson = (0, internal_3.fileExists)(pathToPackageJson)
32
+ packageJson = (0, internal_1.fileExists)(pathToPackageJson)
36
33
  ? (0, devkit_1.readJsonFile)(pathToPackageJson)
37
34
  : { name: context.projectName, version: '0.0.1' };
38
35
  }
@@ -4,6 +4,8 @@ exports.resolveUserExistingPrettierConfig = resolveUserExistingPrettierConfig;
4
4
  exports.generatePrettierSetup = generatePrettierSetup;
5
5
  exports.resolvePrettierConfigPath = resolvePrettierConfigPath;
6
6
  const devkit_1 = require("@nx/devkit");
7
+ const internal_1 = require("@nx/devkit/internal");
8
+ const nx_formatter_internals_1 = require("./nx-formatter-internals");
7
9
  const versions_1 = require("./versions");
8
10
  // Prettier v3 (ESM) exposes its API as named exports; v2 (CJS) exposes it under
9
11
  // `.default` when loaded via `import()`. Return whichever carries the API, or
@@ -44,22 +46,11 @@ async function resolveUserExistingPrettierConfig() {
44
46
  }
45
47
  }
46
48
  function generatePrettierSetup(tree, options) {
47
- // https://prettier.io/docs/en/configuration.html
48
- const prettierrcNameOptions = [
49
- '.prettierrc',
50
- '.prettierrc.json',
51
- '.prettierrc.yml',
52
- '.prettierrc.yaml',
53
- '.prettierrc.json5',
54
- '.prettierrc.js',
55
- '.prettierrc.cjs',
56
- '.prettierrc.mjs',
57
- '.prettierrc.toml',
58
- 'prettier.config.js',
59
- 'prettier.config.cjs',
60
- 'prettier.config.mjs',
61
- ];
62
- if (prettierrcNameOptions.every((name) => !tree.exists(name))) {
49
+ (0, nx_formatter_internals_1.assertNxSupportsFormatters)();
50
+ // Imported rather than copied: detection and setup have to agree on this
51
+ // list, or a workspace whose config format is missing from one side gets a
52
+ // second, redundant `.prettierrc` written beside the one it already has.
53
+ if (internal_1.prettierConfigFiles.every((name) => !tree.exists(name))) {
63
54
  (0, devkit_1.writeJson)(tree, '.prettierrc', { singleQuote: true });
64
55
  }
65
56
  if (!tree.exists('.prettierignore')) {
@@ -68,6 +59,7 @@ function generatePrettierSetup(tree, options) {
68
59
  /coverage
69
60
  /.nx/cache
70
61
  /.nx/workspace-data
62
+ ${(0, internal_1.getLockFileName)((0, devkit_1.detectPackageManager)(tree.root))}
71
63
  `);
72
64
  }
73
65
  if (tree.exists('.vscode/extensions.json')) {
@@ -85,6 +77,7 @@ function generatePrettierSetup(tree, options) {
85
77
  : (0, devkit_1.addDependenciesToPackageJson)(tree, {}, { prettier: versions_1.prettierVersion });
86
78
  }
87
79
  async function resolvePrettierConfigPath(tree) {
80
+ (0, nx_formatter_internals_1.assertNxSupportsFormatters)();
88
81
  const prettier = await importPrettier();
89
82
  if (!prettier) {
90
83
  return null;
@@ -96,23 +89,11 @@ async function resolvePrettierConfigPath(tree) {
96
89
  if (!tree) {
97
90
  return null;
98
91
  }
99
- // if we haven't find a config file in the file system, we try to find it in the virtual tree
100
- // https://prettier.io/docs/en/configuration.html
101
- const prettierrcNameOptions = [
102
- '.prettierrc',
103
- '.prettierrc.json',
104
- '.prettierrc.yml',
105
- '.prettierrc.yaml',
106
- '.prettierrc.json5',
107
- '.prettierrc.js',
108
- '.prettierrc.cjs',
109
- '.prettierrc.mjs',
110
- '.prettierrc.toml',
111
- 'prettier.config.js',
112
- 'prettier.config.cjs',
113
- 'prettier.config.mjs',
114
- ];
115
- const filePath = prettierrcNameOptions.find((file) => tree.exists(file));
92
+ // Same shared list as the setup above, so a config this can't see is one the
93
+ // setup would overwrite. The copy this replaced was missing the `.ts`,
94
+ // `.mts` and `.cts` forms.
95
+ // https://prettier.io/docs/configuration
96
+ const filePath = internal_1.prettierConfigFiles.find((file) => tree.exists(file));
116
97
  if (filePath) {
117
98
  return filePath;
118
99
  }
@@ -1,5 +1,6 @@
1
1
  export declare const nxVersion: any;
2
2
  export declare const esbuildVersion = "^0.27.0";
3
+ export declare const oxfmtVersion = "^0.60.0";
3
4
  export declare const prettierVersion = "~3.6.2";
4
5
  export declare const swcCliVersion = "~0.8.1";
5
6
  export declare const swcCoreVersion = "~1.15.5";
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.minSupportedTypescriptVersion = exports.typescriptVersion = exports.verdaccioVersion = exports.typesNodeVersion = exports.tsLibVersion = exports.swcNodeVersion = exports.swcHelpersVersion = exports.swcCoreVersion = exports.swcCliVersion = exports.prettierVersion = exports.esbuildVersion = exports.nxVersion = void 0;
3
+ exports.minSupportedTypescriptVersion = exports.typescriptVersion = exports.verdaccioVersion = exports.typesNodeVersion = exports.tsLibVersion = exports.swcNodeVersion = exports.swcHelpersVersion = exports.swcCoreVersion = exports.swcCliVersion = exports.prettierVersion = exports.oxfmtVersion = exports.esbuildVersion = exports.nxVersion = void 0;
4
4
  const path_1 = require("path");
5
5
  exports.nxVersion = require((0, path_1.join)('@nx/js', 'package.json')).version;
6
6
  exports.esbuildVersion = '^0.27.0';
7
+ exports.oxfmtVersion = '^0.60.0';
7
8
  exports.prettierVersion = '~3.6.2';
8
9
  exports.swcCliVersion = '~0.8.1';
9
10
  exports.swcCoreVersion = '~1.15.5';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/js",
3
- "version": "23.2.0-beta.7",
3
+ "version": "23.2.0-beta.9",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "files": [
@@ -147,18 +147,18 @@
147
147
  "source-map-support": "0.5.19",
148
148
  "tinyglobby": "^0.2.12",
149
149
  "tslib": "^2.3.0",
150
- "@nx/devkit": "23.2.0-beta.7",
151
- "@nx/workspace": "23.2.0-beta.7"
150
+ "@nx/devkit": "23.2.0-beta.9",
151
+ "@nx/workspace": "23.2.0-beta.9"
152
152
  },
153
153
  "devDependencies": {
154
- "@nx/esbuild": "23.2.0-beta.7",
155
- "@nx/jest": "23.2.0-beta.7",
156
- "@nx/eslint": "23.2.0-beta.7",
157
- "@nx/oxlint": "23.2.0-beta.7",
158
- "@nx/rollup": "23.2.0-beta.7",
159
- "@nx/vite": "23.2.0-beta.7",
160
- "@nx/vitest": "23.2.0-beta.7",
161
- "nx": "23.2.0-beta.7"
154
+ "@nx/esbuild": "23.2.0-beta.9",
155
+ "@nx/eslint": "23.2.0-beta.9",
156
+ "@nx/jest": "23.2.0-beta.9",
157
+ "@nx/oxlint": "23.2.0-beta.9",
158
+ "@nx/vite": "23.2.0-beta.9",
159
+ "@nx/vitest": "23.2.0-beta.9",
160
+ "@nx/rollup": "23.2.0-beta.9",
161
+ "nx": "23.2.0-beta.9"
162
162
  },
163
163
  "peerDependencies": {
164
164
  "@swc/cli": ">=0.6.0 <0.9.0",