@nx/js 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.
@@ -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);
@@ -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;
@@ -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");
@@ -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
+ }
@@ -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
+ }
@@ -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.8",
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.8",
151
- "@nx/workspace": "23.2.0-beta.8"
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.8",
155
- "@nx/eslint": "23.2.0-beta.8",
156
- "@nx/jest": "23.2.0-beta.8",
157
- "@nx/oxlint": "23.2.0-beta.8",
158
- "@nx/vite": "23.2.0-beta.8",
159
- "@nx/rollup": "23.2.0-beta.8",
160
- "@nx/vitest": "23.2.0-beta.8",
161
- "nx": "23.2.0-beta.8"
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",