Skip to content

Commit 2a11d50

Browse files
islandryumarco-ippolito
authored andcommitted
module: correctly detect top-level await in ambiguous contexts
Fixes: #58331 PR-URL: #58646 Reviewed-By: Ethan Arrowood <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
1 parent 4f004ef commit 2a11d50

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed

‎src/node_contextify.cc‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,6 +1446,12 @@ static std::vector<std::string_view> throws_only_in_cjs_error_messages ={
14461446
"await is only valid in async functions and "
14471447
"the top level bodies of modules"};
14481448

1449+
staticconstauto maybe_top_level_await_errors =
1450+
std::array<std::string_view, 2>{
1451+
"missing ) after argument list", // example: `func(await 1);`
1452+
"SyntaxError: Unexpected"// example: `if(await 1)`
1453+
};
1454+
14491455
// If cached_data is provided, it would be used for the compilation and
14501456
// the on-disk compilation cache from NODE_COMPILE_CACHE (if configured)
14511457
// would be ignored.
@@ -1654,6 +1660,16 @@ bool ShouldRetryAsESM(Realm* realm,
16541660
break;
16551661
}
16561662
}
1663+
1664+
for (constauto& error_message : maybe_top_level_await_errors){
1665+
if (message_view.find(error_message) != std::string_view::npos){
1666+
// If the error message is related to top-level await, we can try to
1667+
// compile it as ESM.
1668+
maybe_valid_in_esm = true;
1669+
break;
1670+
}
1671+
}
1672+
16571673
if (!maybe_valid_in_esm){
16581674
returnfalse;
16591675
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import{spawnPromisified}from'../common/index.mjs';
2+
import{describe,it}from'node:test';
3+
import{strictEqual,match}from'node:assert';
4+
5+
describe('unusual top-level await syntax errors',()=>{
6+
constexpressions=[
7+
// string
8+
{expression: '""'},
9+
// number
10+
{expression: '0'},
11+
// boolean
12+
{expression: 'true'},
13+
// null
14+
{expression: 'null'},
15+
// undefined
16+
{expression: 'undefined'},
17+
// object
18+
{expression: '{}'},
19+
// array
20+
{expression: '[]'},
21+
// new
22+
{expression: 'new Date()'},
23+
// identifier
24+
{initialize: 'const a = 2;',expression: 'a'},
25+
];
26+
it('should not crash the process',async()=>{
27+
for(const{ expression, initialize }ofexpressions){
28+
constwrapperExpressions=[
29+
`function callAwait(){}; callAwait(await ${expression});`,
30+
`if (await ${expression}){}`,
31+
`{key: await ${expression} }`,
32+
`[await ${expression}]`,
33+
`(await ${expression})`,
34+
];
35+
for(constwrapperExpressionofwrapperExpressions){
36+
const{ code, signal, stdout, stderr }=awaitspawnPromisified(process.execPath,[
37+
'--eval',
38+
`
39+
${initialize||''}
40+
${wrapperExpression}
41+
`,
42+
]);
43+
44+
strictEqual(stderr,'');
45+
strictEqual(stdout,'');
46+
strictEqual(code,0);
47+
strictEqual(signal,null);
48+
}
49+
}
50+
});
51+
52+
it('should throw the error for unrelated syntax errors',async()=>{
53+
constexpression='foo bar';
54+
constwrapperExpressions=[
55+
[`function callSyntaxError(){}; callSyntaxError(${expression});`,/missing\)afterargumentlist/],
56+
[`if (${expression}){}`,/Unexpectedidentifier/],
57+
[`{key: ${expression} }`,/Unexpectedidentifier/],
58+
[`[${expression}]`,/Unexpectedidentifier/],
59+
[`(${expression})`,/Unexpectedidentifier/],
60+
[`const ${expression} = 1;`,/Missinginitializerinconstdeclaration/],
61+
['console.log(\'PI: \' Math.PI);',/missing\)afterargumentlist/],
62+
['callAwait(await "" "");',/missing\)afterargumentlist/],
63+
];
64+
65+
for(const[wrapperExpression,error]ofwrapperExpressions){
66+
const{ code, signal, stdout, stderr }=awaitspawnPromisified(process.execPath,[
67+
'--eval',
68+
`
69+
${wrapperExpression}
70+
`,
71+
]);
72+
match(stderr,error);
73+
strictEqual(stdout,'');
74+
strictEqual(code,1);
75+
strictEqual(signal,null);
76+
}
77+
});
78+
});

0 commit comments

Comments
(0)