Skip to content

Commit 5d6c76a

Browse files
module: fix strip-types interaction with detect-module
PR-URL: #54164 Reviewed-By: Paolo Insogna <[email protected]> Reviewed-By: Jake Yuesong Li <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Zeyu "Alex" Yang <[email protected]> Reviewed-By: Yagiz Nizipli <[email protected]>
1 parent acbd0be commit 5d6c76a

9 files changed

+166
-12
lines changed

lib/internal/modules/esm/get_format.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,8 @@ function getFileProtocolModuleFormat(url, context = { __proto__: null }, ignoreE
164164
const { tsParse } = require('internal/modules/helpers');
165165
const parsedSource = tsParse(source);
166166
const detectedFormat = detectModuleFormat(parsedSource, url);
167-
const format = detectedFormat ? `${detectedFormat}-typescript` : 'commonjs-typescript';
167+
// When source is undefined, default to module-typescript.
168+
const format = detectedFormat ? `${detectedFormat}-typescript` : 'module-typescript';
168169
if (format === 'module-typescript' && foundPackageJson) {
169170
// This module has a .js extension, a package.json with no `type` field, and ESM syntax.
170171
// Warn about the missing `type` field so that the user can avoid the performance penalty of detection.

lib/internal/modules/helpers.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -307,10 +307,15 @@ function lazyLoadTSParser() {
307307
return parseTS;
308308
}
309309

310+
/**
311+
* Performs type-stripping to TypeScript source code.
312+
* @param {string} source TypeScript code to parse.
313+
* @returns {string} JavaScript code.
314+
*/
310315
function tsParse(source) {
311-
if (!source || typeof source !== 'string') { return; }
316+
if (!source || typeof source !== 'string') { return ''; }
312317
const transformSync = lazyLoadTSParser();
313-
const { code } = transformSync(source);
318+
const { code } = transformSync(source, { __proto__: null, mode: 'strip-only' });
314319
return code;
315320
}
316321

lib/internal/modules/run_main.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ function shouldUseESMLoader(mainPath) {
8484
if (getOptionValue('--experimental-strip-types')) {
8585
// This ensures that --experimental-default-type=commonjs and .mts files are treated as commonjs
8686
if (getOptionValue('--experimental-default-type') === 'commonjs') { return false; }
87-
if (mainPath && StringPrototypeEndsWith(mainPath, '.cts')) { return false; }
87+
if (!mainPath || StringPrototypeEndsWith(mainPath, '.cts')) { return false; }
8888
// This will likely change in the future to start with commonjs loader by default
8989
if (mainPath && StringPrototypeEndsWith(mainPath, '.mts')) { return true; }
9090
}

test/es-module/test-typescript-commonjs.mjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ test('execute a .cts file importing a .mts file export', async () => {
120120
strictEqual(result.code, 0);
121121
});
122122

123-
test('expect failure of a .cts file with default type module', async () => {
123+
test('execute a .cts file with default type module', async () => {
124124
const result = await spawnPromisified(process.execPath, [
125125
'--experimental-strip-types',
126126
'--experimental-default-type=module', // Keeps working with commonjs

test/es-module/test-typescript-eval.mjs

+28-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ if (!process.config.variables.node_use_amaro) skip('Requires Amaro');
66

77
test('eval TypeScript ESM syntax', async () => {
88
const result = await spawnPromisified(process.execPath, [
9-
'--input-type=module',
109
'--experimental-strip-types',
1110
'--eval',
1211
`import util from 'node:util'
@@ -18,9 +17,22 @@ test('eval TypeScript ESM syntax', async () => {
1817
strictEqual(result.code, 0);
1918
});
2019

20+
test('eval TypeScript ESM syntax with input-type module', async () => {
21+
const result = await spawnPromisified(process.execPath, [
22+
'--experimental-strip-types',
23+
'--input-type=module',
24+
'--eval',
25+
`import util from 'node:util'
26+
const text: string = 'Hello, TypeScript!'
27+
console.log(util.styleText('red', text));`]);
28+
29+
match(result.stderr, /Type Stripping is an experimental feature and might change at any time/);
30+
match(result.stdout, /Hello, TypeScript!/);
31+
strictEqual(result.code, 0);
32+
});
33+
2134
test('eval TypeScript CommonJS syntax', async () => {
2235
const result = await spawnPromisified(process.execPath, [
23-
'--input-type=commonjs',
2436
'--experimental-strip-types',
2537
'--eval',
2638
`const util = require('node:util');
@@ -32,6 +44,20 @@ test('eval TypeScript CommonJS syntax', async () => {
3244
strictEqual(result.code, 0);
3345
});
3446

47+
test('eval TypeScript CommonJS syntax with input-type commonjs', async () => {
48+
const result = await spawnPromisified(process.execPath, [
49+
'--experimental-strip-types',
50+
'--input-type=commonjs',
51+
'--eval',
52+
`const util = require('node:util');
53+
const text: string = 'Hello, TypeScript!'
54+
console.log(util.styleText('red', text));`,
55+
'--no-warnings']);
56+
match(result.stdout, /Hello, TypeScript!/);
57+
strictEqual(result.stderr, '');
58+
strictEqual(result.code, 0);
59+
});
60+
3561
test('eval TypeScript CommonJS syntax by default', async () => {
3662
const result = await spawnPromisified(process.execPath, [
3763
'--experimental-strip-types',

test/es-module/test-typescript-module.mjs

+37-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ test('execute an .mts file importing an .mts file', async () => {
3030
test('execute an .mts file importing a .ts file', async () => {
3131
const result = await spawnPromisified(process.execPath, [
3232
'--experimental-strip-types',
33-
'--experimental-default-type=module', // this should fail
3433
'--no-warnings',
3534
fixtures.path('typescript/mts/test-import-ts-file.mts'),
3635
]);
@@ -40,10 +39,22 @@ test('execute an .mts file importing a .ts file', async () => {
4039
strictEqual(result.code, 0);
4140
});
4241

43-
test('execute an .mts file importing a .cts file', async () => {
42+
test('execute an .mts file importing a .ts file with default-type module', async () => {
4443
const result = await spawnPromisified(process.execPath, [
4544
'--experimental-strip-types',
45+
'--experimental-default-type=module',
4646
'--no-warnings',
47+
fixtures.path('typescript/mts/test-import-ts-file.mts'),
48+
]);
49+
50+
strictEqual(result.stderr, '');
51+
match(result.stdout, /Hello, TypeScript!/);
52+
strictEqual(result.code, 0);
53+
});
54+
55+
test('execute an .mts file importing a .cts file', async () => {
56+
const result = await spawnPromisified(process.execPath, [
57+
'--experimental-strip-types',
4758
'--no-warnings',
4859
fixtures.path('typescript/mts/test-import-commonjs.mts'),
4960
]);
@@ -97,3 +108,27 @@ test('execute a .ts file from node_modules', async () => {
97108
strictEqual(result.stdout, '');
98109
strictEqual(result.code, 1);
99110
});
111+
112+
test('execute an empty .ts file', async () => {
113+
const result = await spawnPromisified(process.execPath, [
114+
'--experimental-strip-types',
115+
'--no-warnings',
116+
fixtures.path('typescript/ts/test-empty-file.ts'),
117+
]);
118+
119+
strictEqual(result.stderr, '');
120+
strictEqual(result.stdout, '');
121+
strictEqual(result.code, 0);
122+
});
123+
124+
test('execute .ts file importing a module', async () => {
125+
const result = await spawnPromisified(process.execPath, [
126+
'--experimental-strip-types',
127+
'--no-warnings',
128+
fixtures.path('typescript/ts/test-import-fs.ts'),
129+
]);
130+
131+
strictEqual(result.stderr, '');
132+
strictEqual(result.stdout, 'Hello, TypeScript!\n');
133+
strictEqual(result.code, 0);
134+
});

test/es-module/test-typescript.mjs

+87-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,18 @@ test('execute a TypeScript file', async () => {
1717
});
1818

1919
test('execute a TypeScript file with imports', async () => {
20+
const result = await spawnPromisified(process.execPath, [
21+
'--experimental-strip-types',
22+
'--no-warnings',
23+
fixtures.path('typescript/ts/test-import-foo.ts'),
24+
]);
25+
26+
strictEqual(result.stderr, '');
27+
match(result.stdout, /Hello, TypeScript!/);
28+
strictEqual(result.code, 0);
29+
});
30+
31+
test('execute a TypeScript file with imports with default-type module', async () => {
2032
const result = await spawnPromisified(process.execPath, [
2133
'--experimental-strip-types',
2234
'--experimental-default-type=module',
@@ -30,6 +42,18 @@ test('execute a TypeScript file with imports', async () => {
3042
});
3143

3244
test('execute a TypeScript file with node_modules', async () => {
45+
const result = await spawnPromisified(process.execPath, [
46+
'--experimental-strip-types',
47+
'--no-warnings',
48+
fixtures.path('typescript/ts/test-typescript-node-modules.ts'),
49+
]);
50+
51+
strictEqual(result.stderr, '');
52+
match(result.stdout, /Hello, TypeScript!/);
53+
strictEqual(result.code, 0);
54+
});
55+
56+
test('execute a TypeScript file with node_modules with default-type module', async () => {
3357
const result = await spawnPromisified(process.execPath, [
3458
'--experimental-strip-types',
3559
'--experimental-default-type=module',
@@ -45,7 +69,6 @@ test('execute a TypeScript file with node_modules', async () => {
4569
test('expect error when executing a TypeScript file with imports with no extensions', async () => {
4670
const result = await spawnPromisified(process.execPath, [
4771
'--experimental-strip-types',
48-
'--experimental-default-type=module',
4972
fixtures.path('typescript/ts/test-import-no-extension.ts'),
5073
]);
5174

@@ -54,6 +77,19 @@ test('expect error when executing a TypeScript file with imports with no extensi
5477
strictEqual(result.code, 1);
5578
});
5679

80+
test('expect error when executing a TypeScript file with imports with no extensions with default-type module',
81+
async () => {
82+
const result = await spawnPromisified(process.execPath, [
83+
'--experimental-strip-types',
84+
'--experimental-default-type=module',
85+
fixtures.path('typescript/ts/test-import-no-extension.ts'),
86+
]);
87+
88+
match(result.stderr, /Error \[ERR_MODULE_NOT_FOUND\]:/);
89+
strictEqual(result.stdout, '');
90+
strictEqual(result.code, 1);
91+
});
92+
5793
test('expect error when executing a TypeScript file with enum', async () => {
5894
const result = await spawnPromisified(process.execPath, [
5995
'--experimental-strip-types',
@@ -101,6 +137,17 @@ test('execute a TypeScript file with type definition', async () => {
101137
});
102138

103139
test('execute a TypeScript file with type definition but no type keyword', async () => {
140+
const result = await spawnPromisified(process.execPath, [
141+
'--experimental-strip-types',
142+
fixtures.path('typescript/ts/test-import-no-type-keyword.ts'),
143+
]);
144+
145+
match(result.stderr, /does not provide an export named 'MyType'/);
146+
strictEqual(result.stdout, '');
147+
strictEqual(result.code, 1);
148+
});
149+
150+
test('execute a TypeScript file with type definition but no type keyword with default-type modue', async () => {
104151
const result = await spawnPromisified(process.execPath, [
105152
'--experimental-strip-types',
106153
'--experimental-default-type=module',
@@ -124,6 +171,18 @@ test('execute a TypeScript file with CommonJS syntax', async () => {
124171
});
125172

126173
test('execute a TypeScript file with ES module syntax', async () => {
174+
const result = await spawnPromisified(process.execPath, [
175+
'--experimental-strip-types',
176+
'--no-warnings',
177+
fixtures.path('typescript/ts/test-module-typescript.ts'),
178+
]);
179+
180+
strictEqual(result.stderr, '');
181+
match(result.stdout, /Hello, TypeScript!/);
182+
strictEqual(result.code, 0);
183+
});
184+
185+
test('execute a TypeScript file with ES module syntax with default-type module', async () => {
127186
const result = await spawnPromisified(process.execPath, [
128187
'--experimental-strip-types',
129188
'--experimental-default-type=module',
@@ -161,7 +220,6 @@ test('expect stack trace of a TypeScript file to be correct', async () => {
161220

162221
test('execute CommonJS TypeScript file from node_modules with require-module', async () => {
163222
const result = await spawnPromisified(process.execPath, [
164-
'--experimental-default-type=module',
165223
'--experimental-strip-types',
166224
fixtures.path('typescript/ts/test-import-ts-node-modules.ts'),
167225
]);
@@ -171,6 +229,19 @@ test('execute CommonJS TypeScript file from node_modules with require-module', a
171229
strictEqual(result.code, 1);
172230
});
173231

232+
test('execute CommonJS TypeScript file from node_modules with require-module and default-type module',
233+
async () => {
234+
const result = await spawnPromisified(process.execPath, [
235+
'--experimental-strip-types',
236+
'--experimental-default-type=module',
237+
fixtures.path('typescript/ts/test-import-ts-node-modules.ts'),
238+
]);
239+
240+
match(result.stderr, /ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING/);
241+
strictEqual(result.stdout, '');
242+
strictEqual(result.code, 1);
243+
});
244+
174245
test('execute a TypeScript file with CommonJS syntax but default type module', async () => {
175246
const result = await spawnPromisified(process.execPath, [
176247
'--experimental-strip-types',
@@ -220,7 +291,6 @@ test('execute a TypeScript file with CommonJS syntax requiring .mts with require
220291
test('execute a TypeScript file with CommonJS syntax requiring .mts with require-module', async () => {
221292
const result = await spawnPromisified(process.execPath, [
222293
'--experimental-strip-types',
223-
'--experimental-default-type=commonjs',
224294
'--no-warnings',
225295
fixtures.path('typescript/ts/test-require-cts.ts'),
226296
]);
@@ -229,3 +299,17 @@ test('execute a TypeScript file with CommonJS syntax requiring .mts with require
229299
match(result.stdout, /Hello, TypeScript!/);
230300
strictEqual(result.code, 0);
231301
});
302+
303+
test('execute a TypeScript file with CommonJS syntax requiring .mts with require-module with default-type commonjs',
304+
async () => {
305+
const result = await spawnPromisified(process.execPath, [
306+
'--experimental-strip-types',
307+
'--experimental-default-type=commonjs',
308+
'--no-warnings',
309+
fixtures.path('typescript/ts/test-require-cts.ts'),
310+
]);
311+
312+
strictEqual(result.stderr, '');
313+
match(result.stdout, /Hello, TypeScript!/);
314+
strictEqual(result.code, 0);
315+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import fs from 'fs';
2+
console.log('Hello, TypeScript!');

0 commit comments

Comments
 (0)