@nx/jest 23.1.0-beta.2 → 23.1.0-beta.4
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.
- package/dist/src/generators/configuration/files/common/tsconfig.spec.json__tmpl__ +2 -1
- package/dist/src/generators/configuration/lib/create-files.js +13 -6
- package/dist/src/migrations/update-23-1-0/set-ts-jest-isolated-modules.d.ts +8 -0
- package/dist/src/migrations/update-23-1-0/set-ts-jest-isolated-modules.js +86 -0
- package/dist/src/migrations/update-23-1-0/set-ts-jest-isolated-modules.md +51 -0
- package/dist/src/migrations/update-23-1-0/verify-typecheck.md +14 -0
- package/migrations.json +10 -0
- package/package.json +5 -4
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
"compilerOptions": {
|
|
4
4
|
"outDir": "<%= outDir %>",<% if (module) { %>
|
|
5
5
|
"module": "<%= module %>",<% } if (module === 'commonjs') { %>
|
|
6
|
-
"moduleResolution": "<%= moduleResolution %>",<% } if (
|
|
6
|
+
"moduleResolution": "<%= moduleResolution %>",<% } if (isolatedModules) { %>
|
|
7
|
+
"isolatedModules": true,<% } if (supportTsx) { %>
|
|
7
8
|
"jsx": "react-jsx",<% } %>"types": ["jest", "node"]
|
|
8
9
|
},<% if(setupFile !== 'none') { %>
|
|
9
10
|
"files": ["src/test-setup.ts"],<% } %>
|
|
@@ -46,6 +46,16 @@ function createFiles(tree, options, presetExt) {
|
|
|
46
46
|
const coverageDirectory = options.isTsSolutionSetup
|
|
47
47
|
? `test-output/jest/coverage`
|
|
48
48
|
: `${rootOffset}coverage/${projectRoot}`;
|
|
49
|
+
const usesTsJestModuleSettings = !options.isTsSolutionSetup || transformer === 'ts-jest';
|
|
50
|
+
const moduleResolution = usesTsJestModuleSettings
|
|
51
|
+
? (0, internal_1.getTsConfigModuleResolution)(tree)
|
|
52
|
+
: undefined;
|
|
53
|
+
// ts-jest forces `moduleResolution: node10` on the CommonJS path for
|
|
54
|
+
// TypeScript < 6, and node10 ignores package `exports`. Transpiling per file
|
|
55
|
+
// keeps exports-only workspace libraries resolvable. See NXC-4591.
|
|
56
|
+
const isolatedModules = options.isTsSolutionSetup &&
|
|
57
|
+
transformer === 'ts-jest' &&
|
|
58
|
+
moduleResolution === 'node10';
|
|
49
59
|
(0, devkit_1.generateFiles)(tree, (0, path_1.join)(__dirname, commonFilesFolder), projectConfig.root, {
|
|
50
60
|
tmpl: '',
|
|
51
61
|
...options,
|
|
@@ -64,12 +74,9 @@ function createFiles(tree, options, presetExt) {
|
|
|
64
74
|
outDir: options.isTsSolutionSetup
|
|
65
75
|
? `./out-tsc/jest`
|
|
66
76
|
: `${rootOffset}dist/out-tsc`,
|
|
67
|
-
module:
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
moduleResolution: !options.isTsSolutionSetup || transformer === 'ts-jest'
|
|
71
|
-
? (0, internal_1.getTsConfigModuleResolution)(tree)
|
|
72
|
-
: undefined,
|
|
77
|
+
module: usesTsJestModuleSettings ? 'commonjs' : undefined,
|
|
78
|
+
moduleResolution,
|
|
79
|
+
isolatedModules,
|
|
73
80
|
});
|
|
74
81
|
if (options.setupFile !== 'angular') {
|
|
75
82
|
(0, devkit_1.generateFiles)(tree, (0, path_1.join)(__dirname, options.isTsSolutionSetup
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type Tree } from '@nx/devkit';
|
|
2
|
+
/**
|
|
3
|
+
* NXC-4591: ts-jest 29.2+ uses `moduleResolution: node10` on the CommonJS path
|
|
4
|
+
* for TypeScript < 6, which ignores package `exports` and breaks exports-only
|
|
5
|
+
* workspace libs (TS2307). `isolatedModules: true` makes ts-jest transpile per
|
|
6
|
+
* file, skipping that resolution. TS >= 6 is unaffected.
|
|
7
|
+
*/
|
|
8
|
+
export default function (tree: Tree): Promise<void>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = default_1;
|
|
4
|
+
const devkit_1 = require("@nx/devkit");
|
|
5
|
+
const internal_1 = require("@nx/js/internal");
|
|
6
|
+
const jsonc_parser_1 = require("jsonc-parser");
|
|
7
|
+
const config_file_1 = require("../../utils/config/config-file");
|
|
8
|
+
const FORMATTING_OPTIONS = {
|
|
9
|
+
formattingOptions: { keepLines: true, insertSpaces: true, tabSize: 2 },
|
|
10
|
+
};
|
|
11
|
+
// A jest config mentioning any of these uses swc/babel/angular (or is the root
|
|
12
|
+
// aggregator), not ts-jest, so skip it.
|
|
13
|
+
const NON_TS_JEST_MARKERS = [
|
|
14
|
+
'@swc/jest',
|
|
15
|
+
'babel-jest',
|
|
16
|
+
'jest-preset-angular',
|
|
17
|
+
'getJestProjectsAsync',
|
|
18
|
+
];
|
|
19
|
+
/**
|
|
20
|
+
* NXC-4591: ts-jest 29.2+ uses `moduleResolution: node10` on the CommonJS path
|
|
21
|
+
* for TypeScript < 6, which ignores package `exports` and breaks exports-only
|
|
22
|
+
* workspace libs (TS2307). `isolatedModules: true` makes ts-jest transpile per
|
|
23
|
+
* file, skipping that resolution. TS >= 6 is unaffected.
|
|
24
|
+
*/
|
|
25
|
+
async function default_1(tree) {
|
|
26
|
+
// TS >= 6 resolves `exports` under bundler + commonjs; not affected.
|
|
27
|
+
if ((0, internal_1.isTypescriptVersionAtLeast)(tree, '6.0.0')) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
// Path-based workspaces resolve via tsconfig `paths`, not `exports`; skip them.
|
|
31
|
+
if (!(0, internal_1.isUsingTsSolutionSetup)(tree)) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
// Fresh ts-solution workspaces already enable this in the base config.
|
|
35
|
+
if (rootEnablesIsolatedModules(tree)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
let count = 0;
|
|
39
|
+
for (const [, project] of (0, devkit_1.getProjects)(tree)) {
|
|
40
|
+
const specPath = getTsJestSpecTsconfig(tree, project.root);
|
|
41
|
+
if (specPath && setIsolatedModules(tree, specPath)) {
|
|
42
|
+
count++;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (count > 0) {
|
|
46
|
+
devkit_1.logger.info(`NXC-4591: set "isolatedModules": true in ${count} tsconfig.spec.json file(s) so ts-jest resolves exports-only workspace libraries on TypeScript < 6.`);
|
|
47
|
+
}
|
|
48
|
+
await (0, devkit_1.formatFiles)(tree);
|
|
49
|
+
}
|
|
50
|
+
function rootEnablesIsolatedModules(tree) {
|
|
51
|
+
return (readCompilerOption(tree, 'tsconfig.base.json', 'isolatedModules') === true);
|
|
52
|
+
}
|
|
53
|
+
// The project's tsconfig.spec.json if it runs ts-jest, else null.
|
|
54
|
+
function getTsJestSpecTsconfig(tree, root) {
|
|
55
|
+
const jestConfig = (0, config_file_1.findJestConfig)(tree, root);
|
|
56
|
+
if (!jestConfig) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
const source = tree.read(jestConfig, 'utf-8') ?? '';
|
|
60
|
+
if (NON_TS_JEST_MARKERS.some((marker) => source.includes(marker))) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const specPath = (0, devkit_1.joinPathFragments)(root, 'tsconfig.spec.json');
|
|
64
|
+
return tree.exists(specPath) ? specPath : null;
|
|
65
|
+
}
|
|
66
|
+
function setIsolatedModules(tree, tsconfigPath) {
|
|
67
|
+
if (readCompilerOption(tree, tsconfigPath, 'isolatedModules') === true) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
const contents = tree.read(tsconfigPath, 'utf-8');
|
|
71
|
+
if (!contents) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
const edits = (0, jsonc_parser_1.modify)(contents, ['compilerOptions', 'isolatedModules'], true, FORMATTING_OPTIONS);
|
|
75
|
+
tree.write(tsconfigPath, (0, jsonc_parser_1.applyEdits)(contents, edits));
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
function readCompilerOption(tree, tsconfigPath, option) {
|
|
79
|
+
const contents = tree.read(tsconfigPath, 'utf-8');
|
|
80
|
+
if (!contents) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
const root = (0, jsonc_parser_1.parseTree)(contents);
|
|
84
|
+
const node = root && (0, jsonc_parser_1.findNodeAtLocation)(root, ['compilerOptions', option]);
|
|
85
|
+
return node ? (0, jsonc_parser_1.getNodeValue)(node) : undefined;
|
|
86
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#### Set isolatedModules for ts-jest below TypeScript 6
|
|
2
|
+
|
|
3
|
+
The jest 30 path of `@nx/jest` bumps ts-jest to 29.4.x.
|
|
4
|
+
On the CommonJS jest path, ts-jest 29.2+ uses `moduleResolution: node10` when `bundler` is invalid alongside the forced `module: commonjs`, which is the case below TypeScript 6.
|
|
5
|
+
`node10` does not read package `exports` maps, so a workspace library that exposes types only through `exports` fails to resolve during the ts-jest type check:
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
error TS2307: Cannot find module '@my-org/some-lib' or its corresponding type declarations.
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The migration sets `isolatedModules: true` in each affected `tsconfig.spec.json`, so ts-jest transpiles each file independently and skips the cross-file type resolution that was failing.
|
|
12
|
+
This matches the `isolatedModules: true` that fresh ts-solution workspaces already set in `tsconfig.base.json`.
|
|
13
|
+
Type checking stays on each project's dedicated typecheck target.
|
|
14
|
+
|
|
15
|
+
The migration runs only below TypeScript 6, in ts-solution workspaces that do not already enable `isolatedModules`.
|
|
16
|
+
TypeScript 6 and above resolves `exports` under `bundler` with `commonjs`, so those workspaces are left unchanged.
|
|
17
|
+
|
|
18
|
+
#### Sample code changes
|
|
19
|
+
|
|
20
|
+
##### Before
|
|
21
|
+
|
|
22
|
+
```json title="tsconfig.spec.json"
|
|
23
|
+
{
|
|
24
|
+
"extends": "../../tsconfig.base.json",
|
|
25
|
+
"compilerOptions": {
|
|
26
|
+
"types": ["jest", "node"]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
##### After
|
|
32
|
+
|
|
33
|
+
```json title="tsconfig.spec.json" {4}
|
|
34
|
+
{
|
|
35
|
+
"extends": "../../tsconfig.base.json",
|
|
36
|
+
"compilerOptions": {
|
|
37
|
+
"isolatedModules": true,
|
|
38
|
+
"types": ["jest", "node"]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
#### Verifying the workspace
|
|
44
|
+
|
|
45
|
+
After the migration runs, verify the workspace still typechecks and fix anything `isolatedModules` surfaced:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
nx run-many -t typecheck
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`isolatedModules` can fail typecheck (TS1205 - re-exporting a type needs `export type`; TS2748 - const enum access) or break a project's tests at runtime even when typecheck passes. The cause is a package that re-exports a value through both `module.exports` and an ESM `export` (for example napi bindings exposing a `const enum`); per-file transpilation cannot preserve it, and consumers of that const enum break too. To fix a broken project, remove `isolatedModules` from its `tsconfig.spec.json`; if that brings back the `TS2307: Cannot find module` error this migration was added to prevent, that project needs `isolatedModules`, so fix the source instead.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Verify typecheck after the Nx 23.1 migration
|
|
2
|
+
|
|
3
|
+
This migration enables `isolatedModules` on ts-jest spec configs. Run
|
|
4
|
+
`nx run-many -t typecheck` and fix any project it broke.
|
|
5
|
+
|
|
6
|
+
`isolatedModules` can fail typecheck (TS1205 - a re-exported type needs `export type`;
|
|
7
|
+
TS2748 - const enum access) or break a project's tests at runtime. To fix a broken
|
|
8
|
+
project, remove `isolatedModules` from its `tsconfig.spec.json` and re-run. If a
|
|
9
|
+
`TS2307: Cannot find module` error then appears for a workspace library, that project
|
|
10
|
+
needs `isolatedModules` - keep it and fix the source instead (avoid mixing
|
|
11
|
+
`module.exports` with an ESM `export`, and avoid cross-file `const enum`).
|
|
12
|
+
|
|
13
|
+
Re-run until the projects this migration touched typecheck. See the migration
|
|
14
|
+
documentation for details.
|
package/migrations.json
CHANGED
|
@@ -77,6 +77,16 @@
|
|
|
77
77
|
"description": "Rename imports of `createNodesV2` from `@nx/jest/plugin` to the canonical `createNodes` export.",
|
|
78
78
|
"implementation": "./dist/src/migrations/update-23-0-0/migrate-create-nodes-v2-to-create-nodes",
|
|
79
79
|
"documentation": "./dist/src/migrations/update-23-0-0/migrate-create-nodes-v2-to-create-nodes.md"
|
|
80
|
+
},
|
|
81
|
+
"set-ts-jest-isolated-modules": {
|
|
82
|
+
"version": "23.1.0-beta.4",
|
|
83
|
+
"requires": {
|
|
84
|
+
"ts-jest": ">=29.2.0"
|
|
85
|
+
},
|
|
86
|
+
"description": "Set `isolatedModules: true` in `tsconfig.spec.json` for ts-jest projects on TypeScript < 6 (ts-jest 29.2+ forces `moduleResolution: node10` on the CommonJS path, which ignores package `exports` maps and breaks resolution of exports-only workspace libraries), then verify the workspace still typechecks and remedy any failures the change surfaced.",
|
|
87
|
+
"implementation": "./dist/src/migrations/update-23-1-0/set-ts-jest-isolated-modules",
|
|
88
|
+
"prompt": "./dist/src/migrations/update-23-1-0/verify-typecheck.md",
|
|
89
|
+
"documentation": "./dist/src/migrations/update-23-1-0/set-ts-jest-isolated-modules.md"
|
|
80
90
|
}
|
|
81
91
|
},
|
|
82
92
|
"packageJsonUpdates": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nx/jest",
|
|
3
|
-
"version": "23.1.0-beta.
|
|
3
|
+
"version": "23.1.0-beta.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"files": [
|
|
@@ -110,17 +110,18 @@
|
|
|
110
110
|
"jest-config": "^30.0.2",
|
|
111
111
|
"jest-resolve": "^30.0.2",
|
|
112
112
|
"jest-util": "^30.0.2",
|
|
113
|
+
"jsonc-parser": "^3.2.0",
|
|
113
114
|
"minimatch": "10.2.5",
|
|
114
115
|
"picocolors": "^1.1.0",
|
|
115
116
|
"resolve.exports": "2.0.3",
|
|
116
117
|
"semver": "^7.6.3",
|
|
117
118
|
"tslib": "^2.3.0",
|
|
118
119
|
"yargs-parser": "21.1.1",
|
|
119
|
-
"@nx/devkit": "23.1.0-beta.
|
|
120
|
-
"@nx/js": "23.1.0-beta.
|
|
120
|
+
"@nx/devkit": "23.1.0-beta.4",
|
|
121
|
+
"@nx/js": "23.1.0-beta.4"
|
|
121
122
|
},
|
|
122
123
|
"devDependencies": {
|
|
123
|
-
"nx": "23.1.0-beta.
|
|
124
|
+
"nx": "23.1.0-beta.4"
|
|
124
125
|
},
|
|
125
126
|
"publishConfig": {
|
|
126
127
|
"access": "public"
|