@nx/devkit 23.0.0-beta.15 → 23.0.0-beta.17

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.
@@ -8,21 +8,26 @@ const package_json_1 = require("../utils/package-json");
8
8
  */
9
9
  function toJS(tree, options) {
10
10
  const { JsxEmit, ScriptTarget, transpile, ModuleKind } = (0, package_json_1.ensurePackage)('typescript', versions_1.typescriptVersion);
11
+ // Match `.ts`, `.mts`, `.cts`, `.tsx`. The optional `[cm]` keeps native
12
+ // ESM (`.mts`) and CommonJS (`.cts`) TypeScript extensions in the rename
13
+ // path so `--js` generators that emit `.mts`/`.cts` templates get
14
+ // converted instead of silently left as TypeScript on disk.
15
+ const tsExtRegex = /\.([cm]?ts|tsx)$/;
11
16
  for (const c of tree.listChanges()) {
12
- if ((c.path.endsWith('.ts') || c.path.endsWith('tsx')) &&
13
- c.type === 'CREATE') {
17
+ if (tsExtRegex.test(c.path) && c.type === 'CREATE') {
14
18
  tree.write(c.path, transpile(c.content.toString('utf-8'), {
15
19
  allowJs: true,
16
20
  jsx: JsxEmit.Preserve,
17
21
  target: options?.target ?? ScriptTarget.ESNext,
18
22
  module: options?.module ?? ModuleKind.ESNext,
19
23
  }));
20
- tree.rename(c.path, c.path.replace(/\.ts$/, options?.extension ?? '.js'));
24
+ const targetExt = options?.extension ?? '.js';
25
+ tree.rename(c.path, c.path.replace(/\.([cm]?ts)$/, targetExt));
21
26
  if (options?.useJsx) {
22
27
  tree.rename(c.path, c.path.replace(/\.tsx$/, '.jsx'));
23
28
  }
24
29
  else {
25
- tree.rename(c.path, c.path.replace(/\.tsx$/, options?.extension ?? '.js'));
30
+ tree.rename(c.path, c.path.replace(/\.tsx$/, targetExt));
26
31
  }
27
32
  }
28
33
  }
@@ -27,16 +27,71 @@ function isTypeScriptFile(extension) {
27
27
  }
28
28
  async function loadTypeScriptModule(path, extension, tsconfigFileNames) {
29
29
  const tsConfigPath = getTypeScriptConfigPath(path, tsconfigFileNames);
30
- if (tsConfigPath) {
31
- const unregisterTsProject = (0, devkit_internals_1.registerTsProject)(tsConfigPath);
30
+ if (!tsConfigPath) {
31
+ return await loadModuleByExtension(path, extension);
32
+ }
33
+ // loadTsFile was added in nx@23. @nx/devkit's peer range supports older
34
+ // nx majors, so fall back to the legacy registerTsProject + require path
35
+ // when loadTsFile isn't available on the host nx.
36
+ if (typeof devkit_internals_1.loadTsFile !== 'function') {
37
+ const cleanup = (0, devkit_internals_1.registerTsProject)(tsConfigPath);
32
38
  try {
33
39
  return await loadModuleByExtension(path, extension);
34
40
  }
35
41
  finally {
36
- unregisterTsProject();
42
+ cleanup();
43
+ }
44
+ }
45
+ // Both .ts and .mts go through loadTsFile first. Node 22.12+ supports
46
+ // require() of synchronous ESM by default, and loadTsFile's lazy fallback
47
+ // covers swc/ts-node + tsconfig-paths registration when needed (swc-node
48
+ // hooks .cts/.mts/.ts via Module._extensions). Async-only ESM modules
49
+ // (top-level await) throw ERR_REQUIRE_ASYNC_MODULE and fall through to
50
+ // dynamic import(). ERR_REQUIRE_ESM is the legacy code for the same case
51
+ // - kept for older Node lines.
52
+ try {
53
+ return (0, devkit_internals_1.loadTsFile)(path, tsConfigPath);
54
+ }
55
+ catch (e) {
56
+ if (e?.code !== 'ERR_REQUIRE_ESM' &&
57
+ e?.code !== 'ERR_REQUIRE_ASYNC_MODULE') {
58
+ throw e;
59
+ }
60
+ // The module must be loaded via dynamic import(). Register
61
+ // tsconfig-paths first so workspace alias imports resolve, then try a
62
+ // native dynamic import. Node 22.18+ LTS strips TS types on the ESM
63
+ // path natively, so pure-ESM TLA configs load without any swc/ts-node
64
+ // ESM loader. Only escalate to forceRegisterEsmLoader (which throws
65
+ // when neither @swc-node/register nor ts-node is installed) if the
66
+ // native attempt hits unsupported TS syntax.
67
+ const cleanup = (0, devkit_internals_1.registerTsProject)(tsConfigPath);
68
+ try {
69
+ return await loadESM(path);
70
+ }
71
+ catch (esmErr) {
72
+ if (esmErr?.code !== 'ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX' ||
73
+ typeof devkit_internals_1.forceRegisterEsmLoader !== 'function') {
74
+ throw esmErr;
75
+ }
76
+ // Module.register is global and one-shot per process. After this
77
+ // runs, every subsequent ESM import in the process is routed
78
+ // through the registered loader, forfeiting Node's native TS
79
+ // stripping for the dynamic-import path. If neither swc-node nor
80
+ // ts-node is installed, forceRegisterEsmLoader throws - surface the
81
+ // original ESM error in that case so the user sees the real
82
+ // problem, not a misleading "loader missing" message.
83
+ try {
84
+ (0, devkit_internals_1.forceRegisterEsmLoader)();
85
+ }
86
+ catch {
87
+ throw esmErr;
88
+ }
89
+ return await loadESM(path);
90
+ }
91
+ finally {
92
+ cleanup();
37
93
  }
38
94
  }
39
- return await loadModuleByExtension(path, extension);
40
95
  }
41
96
  function getTypeScriptConfigPath(path, tsconfigFileNames) {
42
97
  const siblingFiles = (0, fs_1.readdirSync)((0, path_1.dirname)(path));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/devkit",
3
- "version": "23.0.0-beta.15",
3
+ "version": "23.0.0-beta.17",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "files": [
@@ -60,7 +60,7 @@
60
60
  },
61
61
  "devDependencies": {
62
62
  "jest": "30.3.0",
63
- "nx": "23.0.0-beta.15"
63
+ "nx": "23.0.0-beta.17"
64
64
  },
65
65
  "peerDependencies": {
66
66
  "nx": ">= 22 <= 24 || ^23.0.0-0"