Skip to content

Commit 54634f5

Browse files
mertcanaltinaduh95
authored andcommitted
module: update tests for combined ambiguous module syntax error
PR-URL: #55874Fixes: #55776 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
1 parent ccca151 commit 54634f5

4 files changed

Lines changed: 60 additions & 4 deletions

File tree

‎lib/internal/modules/esm/module_job.js‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,16 @@ const isCommonJSGlobalLikeNotDefinedError = (errorMessage) =>
7373
* @param {string} url
7474
* @returns {void}
7575
*/
76-
constexplainCommonJSGlobalLikeNotDefinedError=(e,url)=>{
76+
constexplainCommonJSGlobalLikeNotDefinedError=(e,url,hasTopLevelAwait)=>{
7777
if(e?.name==='ReferenceError'&&
7878
isCommonJSGlobalLikeNotDefinedError(e.message)){
79+
80+
if(hasTopLevelAwait){
81+
e.message=`Cannot determine intended module format because both require() and top-level await are present. If the code is intended to be CommonJS, wrap await in an async function. If the code is intended to be an ES module, replace require() with import.`;
82+
e.code='ERR_AMBIGUOUS_MODULE_SYNTAX';
83+
return;
84+
}
85+
7986
e.message+=' in ES module scope';
8087

8188
if(StringPrototypeStartsWith(e.message,'require ')){
@@ -335,7 +342,7 @@ class ModuleJob extends ModuleJobBase {
335342
try{
336343
awaitthis.module.evaluate(timeout,breakOnSigint);
337344
}catch(e){
338-
explainCommonJSGlobalLikeNotDefinedError(e,this.module.url);
345+
explainCommonJSGlobalLikeNotDefinedError(e,this.module.url,this.module.hasTopLevelAwait());
339346
throwe;
340347
}
341348
return{__proto__: null,module: this.module};
@@ -443,7 +450,7 @@ class ModuleJobSync extends ModuleJobBase {
443450
constnamespace=this.module.evaluateSync(filename,parentFilename);
444451
return{__proto__: null,module: this.module, namespace };
445452
}catch(e){
446-
explainCommonJSGlobalLikeNotDefinedError(e,this.module.url);
453+
explainCommonJSGlobalLikeNotDefinedError(e,this.module.url,this.module.hasTopLevelAwait());
447454
throwe;
448455
}
449456
}

‎src/module_wrap.cc‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,27 @@ void ModuleWrap::IsGraphAsync(const FunctionCallbackInfo<Value>& args) {
824824
args.GetReturnValue().Set(module->IsGraphAsync());
825825
}
826826

827+
voidModuleWrap::HasTopLevelAwait(const FunctionCallbackInfo<Value>& args) {
828+
Isolate* isolate = args.GetIsolate();
829+
ModuleWrap* obj;
830+
ASSIGN_OR_RETURN_UNWRAP(&obj, args.This());
831+
832+
Local<Module> module = obj->module_.Get(isolate);
833+
834+
// Check if module is valid
835+
if (module.IsEmpty()) {
836+
args.GetReturnValue().Set(false);
837+
return;
838+
}
839+
840+
// For source text modules, check if the graph is async
841+
// For synthetic modules, it's always false
842+
bool has_top_level_await =
843+
module->IsSourceTextModule() && module->IsGraphAsync();
844+
845+
args.GetReturnValue().Set(has_top_level_await);
846+
}
847+
827848
voidModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) {
828849
Isolate* isolate = args.GetIsolate();
829850
ModuleWrap* obj;
@@ -1181,6 +1202,8 @@ void ModuleWrap::CreatePerIsolateProperties(IsolateData* isolate_data,
11811202
SetProtoMethodNoSideEffect(isolate, tpl, "getNamespace", GetNamespace);
11821203
SetProtoMethodNoSideEffect(isolate, tpl, "getStatus", GetStatus);
11831204
SetProtoMethodNoSideEffect(isolate, tpl, "isGraphAsync", IsGraphAsync);
1205+
SetProtoMethodNoSideEffect(
1206+
isolate, tpl, "hasTopLevelAwait", HasTopLevelAwait);
11841207
SetProtoMethodNoSideEffect(isolate, tpl, "getError", GetError);
11851208
SetConstructorFunction(isolate, target, "ModuleWrap", tpl);
11861209
isolate_data->set_module_wrap_constructor_template(tpl);
@@ -1238,6 +1261,7 @@ void ModuleWrap::RegisterExternalReferences(
12381261
registry->Register(GetStatus);
12391262
registry->Register(GetError);
12401263
registry->Register(IsGraphAsync);
1264+
registry->Register(HasTopLevelAwait);
12411265

12421266
registry->Register(CreateRequiredModuleFacade);
12431267

‎src/module_wrap.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class ModuleWrap : public BaseObject {
5858
voidMemoryInfo(MemoryTracker* tracker) constoverride {
5959
tracker->TrackField("resolve_cache", resolve_cache_);
6060
}
61+
staticvoidHasTopLevelAwait(const v8::FunctionCallbackInfo<v8::Value>& args);
6162

6263
v8::Local<v8::Context> context() const;
6364
v8::Maybe<bool> CheckUnsettledTopLevelAwait();

‎test/es-module/test-esm-detect-ambiguous.mjs‎

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,10 @@ describe('Module syntax detection', { concurrency: !process.env.TEST_PARALLEL },
294294
'const fs = require("node:fs"); await Promise.resolve();',
295295
]);
296296

297-
match(stderr,/ReferenceError:requireisnotdefinedinESmodulescope/);
297+
match(
298+
stderr,
299+
/ReferenceError:Cannotdetermineintendedmoduleformatbecausebothrequire\(\)andtop-levelawaitarepresent\.IfthecodeisintendedtobeCommonJS,wrapawaitinanasyncfunction\.IfthecodeisintendedtobeanESmodule,replacerequire\(\)withimport\./
300+
);
298301
strictEqual(stdout,'');
299302
strictEqual(code,1);
300303
strictEqual(signal,null);
@@ -436,3 +439,24 @@ describe('when working with Worker threads', () => {
436439
strictEqual(signal,null);
437440
});
438441
});
442+
443+
describe('cjs & esm ambiguous syntax case',()=>{
444+
it('should throw an ambiguous syntax error when using top-level await with require',async()=>{
445+
const{ stderr, code, signal }=awaitspawnPromisified(
446+
process.execPath,
447+
[
448+
'--input-type=module',
449+
'--eval',
450+
`await 1;\nconst fs = require('fs');`,
451+
]
452+
);
453+
454+
match(
455+
stderr,
456+
/ReferenceError:Cannotdetermineintendedmoduleformatbecausebothrequire\(\)andtop-levelawaitarepresent\.IfthecodeisintendedtobeCommonJS,wrapawaitinanasyncfunction\.IfthecodeisintendedtobeanESmodule,replacerequire\(\)withimport\./
457+
);
458+
459+
strictEqual(code,1);
460+
strictEqual(signal,null);
461+
});
462+
});

0 commit comments

Comments
 (0)