Skip to content

Commit 9c5c3b3

Browse files
marco-ippolitoaduh95
authored andcommitted
module: add ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX
PR-URL: #56610 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: Geoffrey Booth <[email protected]> Reviewed-By: Ethan Arrowood <[email protected]> Reviewed-By: Chengzhong Wu <[email protected]>
1 parent f97cd5b commit 9c5c3b3

File tree

8 files changed

+93
-38
lines changed

8 files changed

+93
-38
lines changed

‎doc/api/cli.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1403,7 +1403,8 @@ Node.js will try to detect the syntax with the following steps:
14031403
1. Run the input as CommonJS.
14041404
2. If step 1 fails, run the input as an ES module.
14051405
3. If step 2 fails with a SyntaxError, strip the types.
1406-
4. If step 3 fails with an error code [`ERR_INVALID_TYPESCRIPT_SYNTAX`][],
1406+
4. If step 3 fails with an error code [`ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX`][]
1407+
or [`ERR_INVALID_TYPESCRIPT_SYNTAX`][],
14071408
throw the error from step 2, including the TypeScript error in the message,
14081409
else run as CommonJS.
14091410
5. If step 4 fails, run the input as an ES module.
@@ -3691,6 +3692,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12
36913692
[`Buffer`]: buffer.md#class-buffer
36923693
[`CRYPTO_secure_malloc_init`]: https://www.openssl.org/docs/man3.0/man3/CRYPTO_secure_malloc_init.html
36933694
[`ERR_INVALID_TYPESCRIPT_SYNTAX`]: errors.md#err_invalid_typescript_syntax
3695+
[`ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX`]: errors.md#err_unsupported_typescript_syntax
36943696
[`NODE_OPTIONS`]: #node_optionsoptions
36953697
[`NO_COLOR`]: https://no-color.org
36963698
[`SlowBuffer`]: buffer.md#class-slowbuffer

‎doc/api/errors.md‎

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2093,11 +2093,13 @@ does not consist of exactly two elements.
20932093

20942094
<!-- YAML
20952095
added: v23.0.0
2096+
changes:
2097+
- version: REPLACEME
2098+
pr-url: https://github.com/nodejs/node/pull/56610
2099+
description: This error is no longer thrown on valid yet unsupported syntax.
20962100
-->
20972101

2098-
The provided TypeScript syntax is not valid or unsupported.
2099-
This could happen when using TypeScript syntax that requires
2100-
transformation with [type-stripping][].
2102+
The provided TypeScript syntax is not valid.
21012103

21022104
<aid="ERR_INVALID_URI"></a>
21032105

@@ -3096,6 +3098,18 @@ try{
30963098
}
30973099
```
30983100

3101+
<aid="ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX"></a>
3102+
3103+
### `ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX`
3104+
3105+
<!-- YAML
3106+
added: REPLACEME
3107+
-->
3108+
3109+
The provided TypeScript syntax is unsupported.
3110+
This could happen when using TypeScript syntax that requires
3111+
transformation with [type-stripping][].
3112+
30993113
<aid="ERR_USE_AFTER_CLOSE"></a>
31003114

31013115
### `ERR_USE_AFTER_CLOSE`

‎lib/internal/errors.js‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,6 +1838,7 @@ E('ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING',
18381838
E('ERR_UNSUPPORTED_RESOLVE_REQUEST',
18391839
'Failed to resolve module specifier "%s" from "%s": Invalid relative URL or base scheme is not hierarchical.',
18401840
TypeError);
1841+
E('ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX','%s',SyntaxError);
18411842
E('ERR_USE_AFTER_CLOSE','%s was closed',Error);
18421843

18431844
// This should probably be a `TypeError`.

‎lib/internal/modules/typescript.js‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ const{assertTypeScript,
1212
isUnderNodeModules,
1313
kEmptyObject }=require('internal/util');
1414
const{
15+
ERR_INTERNAL_ASSERTION,
1516
ERR_INVALID_TYPESCRIPT_SYNTAX,
1617
ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING,
18+
ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX,
1719
}=require('internal/errors').codes;
1820
const{ getOptionValue }=require('internal/options');
1921
constassert=require('internal/assert');
@@ -49,7 +51,20 @@ function parseTypeScript(source, options){
4951
try{
5052
returnparse(source,options);
5153
}catch(error){
52-
thrownewERR_INVALID_TYPESCRIPT_SYNTAX(error.message);
54+
/**
55+
* Amaro v0.3.0 (from SWC v1.10.7) throws an object with `message` and `code` properties.
56+
* It allows us to distinguish between invalid syntax and unsupported syntax.
57+
*/
58+
switch(error.code){
59+
case'UnsupportedSyntax':
60+
thrownewERR_UNSUPPORTED_TYPESCRIPT_SYNTAX(error.message);
61+
case'InvalidSyntax':
62+
thrownewERR_INVALID_TYPESCRIPT_SYNTAX(error.message);
63+
default:
64+
// SWC will throw strings when something goes wrong.
65+
// Check if has the `message` property or treat it as a string.
66+
thrownewERR_INTERNAL_ASSERTION(error.message??error);
67+
}
5368
}
5469
}
5570

‎lib/internal/process/execution.js‎

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const{getOptionValue } = require('internal/options');
3535
const{
3636
makeContextifyScript, runScriptInThisContext,
3737
}=require('internal/vm');
38-
const{ emitExperimentalWarning, isError}=require('internal/util');
38+
const{ emitExperimentalWarning }=require('internal/util');
3939
// shouldAbortOnUncaughtToggle is a typed array for faster
4040
// communication with JS.
4141
const{ shouldAbortOnUncaughtToggle }=internalBinding('util');
@@ -254,10 +254,6 @@ function evalTypeScript(name, source, breakFirstLine, print, shouldLoadESM = fal
254254
try{
255255
compiledScript=compileScript(name,source,baseUrl);
256256
}catch(originalError){
257-
// If it's not a SyntaxError, rethrow it.
258-
if(!isError(originalError)||originalError.name!=='SyntaxError'){
259-
throworiginalError;
260-
}
261257
try{
262258
sourceToRun=stripTypeScriptModuleTypes(source,name,false);
263259
// Retry the CJS/ESM syntax detection after stripping the types.
@@ -270,15 +266,14 @@ function evalTypeScript(name, source, breakFirstLine, print, shouldLoadESM = fal
270266
// Emit the experimental warning after the code was successfully evaluated.
271267
emitExperimentalWarning('Type Stripping');
272268
}catch(tsError){
273-
// If its not an error, or it's not an invalid typescript syntax error, rethrow it.
274-
if(!isError(tsError)||tsError?.code!=='ERR_INVALID_TYPESCRIPT_SYNTAX'){
275-
throwtsError;
269+
// If it's invalid or unsupported TypeScript syntax, rethrow the original error
270+
// with the TypeScript error message added to the stack.
271+
if(tsError.code==='ERR_INVALID_TYPESCRIPT_SYNTAX'||tsError.code==='ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX'){
272+
originalError.stack=decorateCJSErrorWithTSMessage(originalError.stack,tsError.message);
273+
throworiginalError;
276274
}
277275

278-
try{
279-
originalError.stack=decorateCJSErrorWithTSMessage(originalError.stack,tsError.message);
280-
}catch{/* Ignore potential errors coming from `stack` getter/setter */}
281-
throworiginalError;
276+
throwtsError;
282277
}
283278
}
284279

@@ -322,28 +317,23 @@ function evalTypeScriptModuleEntryPoint(source, print){
322317
// Compile the module to check for syntax errors.
323318
moduleWrap=loader.createModuleWrap(source,url);
324319
}catch(originalError){
325-
// If it's not a SyntaxError, rethrow it.
326-
if(!isError(originalError)||originalError.name!=='SyntaxError'){
327-
throworiginalError;
328-
}
329-
letstrippedSource;
330320
try{
331-
strippedSource=stripTypeScriptModuleTypes(source,url,false);
321+
conststrippedSource=stripTypeScriptModuleTypes(source,url,false);
332322
// If the moduleWrap was successfully created, execute the module job.
333323
// outside the try-catch block to avoid catching runtime errors.
334324
moduleWrap=loader.createModuleWrap(strippedSource,url);
335325
// Emit the experimental warning after the code was successfully compiled.
336326
emitExperimentalWarning('Type Stripping');
337327
}catch(tsError){
338-
// If its not an error, or it's not an invalid typescript syntax error, rethrow it.
339-
if(!isError(tsError)||tsError?.code!=='ERR_INVALID_TYPESCRIPT_SYNTAX'){
340-
throwtsError;
341-
}
342-
try{
328+
// If it's invalid or unsupported TypeScript syntax, rethrow the original error
329+
// with the TypeScript error message added to the stack.
330+
if(tsError.code==='ERR_INVALID_TYPESCRIPT_SYNTAX'||
331+
tsError.code==='ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX'){
343332
originalError.stack=`${tsError.message}\n\n${originalError.stack}`;
344-
}catch{/* Ignore potential errors coming from `stack` getter/setter */}
333+
throworiginalError;
334+
}
345335

346-
throworiginalError;
336+
throwtsError;
347337
}
348338
}
349339
// If the moduleWrap was successfully created either with by just compiling

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

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,33 +102,33 @@ test('expect fail eval TypeScript ESM syntax with input-type commonjs-typescript
102102
strictEqual(result.code,1);
103103
});
104104

105-
test('check syntax error is thrown when passing invalid syntax',async()=>{
105+
test('check syntax error is thrown when passing unsupported syntax',async()=>{
106106
constresult=awaitspawnPromisified(process.execPath,[
107107
'--eval',
108108
'enum Foo{A, B, C }']);
109109
strictEqual(result.stdout,'');
110110
match(result.stderr,/SyntaxError/);
111-
doesNotMatch(result.stderr,/ERR_INVALID_TYPESCRIPT_SYNTAX/);
111+
doesNotMatch(result.stderr,/ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX/);
112112
strictEqual(result.code,1);
113113
});
114114

115-
test('check syntax error is thrown when passing invalid syntax with --input-type=module-typescript',async()=>{
115+
test('check syntax error is thrown when passing unsupported syntax with --input-type=module-typescript',async()=>{
116116
constresult=awaitspawnPromisified(process.execPath,[
117117
'--input-type=module-typescript',
118118
'--eval',
119119
'enum Foo{A, B, C }']);
120120
strictEqual(result.stdout,'');
121-
match(result.stderr,/ERR_INVALID_TYPESCRIPT_SYNTAX/);
121+
match(result.stderr,/ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX/);
122122
strictEqual(result.code,1);
123123
});
124124

125-
test('check syntax error is thrown when passing invalid syntax with --input-type=commonjs-typescript',async()=>{
125+
test('check syntax error is thrown when passing unsupported syntax with --input-type=commonjs-typescript',async()=>{
126126
constresult=awaitspawnPromisified(process.execPath,[
127127
'--input-type=commonjs-typescript',
128128
'--eval',
129129
'enum Foo{A, B, C }']);
130130
strictEqual(result.stdout,'');
131-
match(result.stderr,/ERR_INVALID_TYPESCRIPT_SYNTAX/);
131+
match(result.stderr,/ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX/);
132132
strictEqual(result.code,1);
133133
});
134134

@@ -140,7 +140,7 @@ test('should not parse TypeScript with --type-module=commonjs', async () =>{
140140

141141
strictEqual(result.stdout,'');
142142
match(result.stderr,/SyntaxError/);
143-
doesNotMatch(result.stderr,/ERR_INVALID_TYPESCRIPT_SYNTAX/);
143+
doesNotMatch(result.stderr,/ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX/);
144144
strictEqual(result.code,1);
145145
});
146146

@@ -152,7 +152,7 @@ test('should not parse TypeScript with --type-module=module', async () =>{
152152

153153
strictEqual(result.stdout,'');
154154
match(result.stderr,/SyntaxError/);
155-
doesNotMatch(result.stderr,/ERR_INVALID_TYPESCRIPT_SYNTAX/);
155+
doesNotMatch(result.stderr,/ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX/);
156156
strictEqual(result.code,1);
157157
});
158158

@@ -222,3 +222,23 @@ test('typescript CJS code is throwing a syntax error at runtime', async () =>{
222222
strictEqual(result.stdout,'');
223223
strictEqual(result.code,1);
224224
});
225+
226+
test('check syntax error is thrown when passing invalid syntax with --input-type=commonjs-typescript',async()=>{
227+
constresult=awaitspawnPromisified(process.execPath,[
228+
'--input-type=commonjs-typescript',
229+
'--eval',
230+
'function foo(){await Promise.resolve(1)}']);
231+
strictEqual(result.stdout,'');
232+
match(result.stderr,/ERR_INVALID_TYPESCRIPT_SYNTAX/);
233+
strictEqual(result.code,1);
234+
});
235+
236+
test('check syntax error is thrown when passing invalid syntax with --input-type=module-typescript',async()=>{
237+
constresult=awaitspawnPromisified(process.execPath,[
238+
'--input-type=module-typescript',
239+
'--eval',
240+
'function foo(){await Promise.resolve(1)}']);
241+
strictEqual(result.stdout,'');
242+
match(result.stderr,/ERR_INVALID_TYPESCRIPT_SYNTAX/);
243+
strictEqual(result.code,1);
244+
});

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,3 +321,13 @@ test('execute a TypeScript loader and a .js file', async () =>{
321321
match(result.stdout,/Hello,TypeScript!/);
322322
strictEqual(result.code,0);
323323
});
324+
325+
test('execute invalid TypeScript syntax',async()=>{
326+
constresult=awaitspawnPromisified(process.execPath,[
327+
fixtures.path('typescript/ts/test-invalid-syntax.ts'),
328+
]);
329+
330+
match(result.stderr,/ERR_INVALID_TYPESCRIPT_SYNTAX/);
331+
strictEqual(result.stdout,'');
332+
strictEqual(result.code,1);
333+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
functionfoo(): string{
2+
awaitPromise.resolve(1);
3+
}

0 commit comments

Comments
(0)