@@ -1441,35 +1441,18 @@ void ContextifyContext::ContainsModuleSyntax(
14411441 env, " containsModuleSyntax needs at least 1 argument" );
14421442 }
14431443
1444+ // Argument 1: source code
1445+ Local<String> code;
1446+ CHECK (args[0 ]->IsString ());
1447+ code = args[0 ].As <String>();
1448+
14441449 // Argument 2: filename; if undefined, use empty string
14451450 Local<String> filename = String::Empty (isolate);
14461451 if (!args[1 ]->IsUndefined ()) {
14471452 CHECK (args[1 ]->IsString ());
14481453 filename = args[1 ].As <String>();
14491454 }
14501455
1451- // Argument 1: source code; if undefined, read from filename in argument 2
1452- Local<String> code;
1453- if (args[0 ]->IsUndefined ()) {
1454- CHECK (!filename.IsEmpty ());
1455- const char * filename_str = Utf8Value (isolate, filename).out ();
1456- std::string contents;
1457- int result = ReadFileSync (&contents, filename_str);
1458- if (result != 0 ) {
1459- isolate->ThrowException (
1460- ERR_MODULE_NOT_FOUND (isolate, " Cannot read file %s" , filename_str));
1461- return ;
1462- }
1463- code = String::NewFromUtf8 (isolate,
1464- contents.c_str (),
1465- v8::NewStringType::kNormal ,
1466- contents.length ())
1467- .ToLocalChecked ();
1468- } else {
1469- CHECK (args[0 ]->IsString ());
1470- code = args[0 ].As <String>();
1471- }
1472-
14731456 // TODO(geoffreybooth): Centralize this rather than matching the logic in
14741457 // cjs/loader.js and translators.js
14751458 Local<String> script_id = String::Concat (
@@ -1499,91 +1482,34 @@ void ContextifyContext::ContainsModuleSyntax(
14991482
15001483 bool should_retry_as_esm = false ;
15011484 if (try_catch.HasCaught () && !try_catch.HasTerminated ()) {
1502- Utf8Value message_value (env->isolate (), try_catch.Message ()->Get ());
1503- auto message = message_value.ToStringView ();
1504-
1505- for (const auto & error_message : esm_syntax_error_messages) {
1506- if (message.find (error_message) != std::string_view::npos) {
1507- should_retry_as_esm = true ;
1508- break ;
1509- }
1510- }
1511-
1512- if (!should_retry_as_esm) {
1513- for (const auto & error_message : throws_only_in_cjs_error_messages) {
1514- if (message.find (error_message) != std::string_view::npos) {
1515- // Try parsing again where the CommonJS wrapper is replaced by an
1516- // async function wrapper. If the new parse succeeds, then the error
1517- // was caused by either a top-level declaration of one of the CommonJS
1518- // module variables, or a top-level `await`.
1519- TryCatchScope second_parse_try_catch (env);
1520- code =
1521- String::Concat (isolate,
1522- String::NewFromUtf8 (isolate, " (async function() {" )
1523- .ToLocalChecked (),
1524- code);
1525- code = String::Concat (
1526- isolate,
1527- code,
1528- String::NewFromUtf8 (isolate, " })();" ).ToLocalChecked ());
1529- ScriptCompiler::Source wrapped_source = GetCommonJSSourceInstance (
1530- isolate, code, filename, 0 , 0 , host_defined_options, nullptr );
1531- std::ignore = ScriptCompiler::CompileFunction (
1532- context,
1533- &wrapped_source,
1534- params.size (),
1535- params.data (),
1536- 0 ,
1537- nullptr ,
1538- options,
1539- v8::ScriptCompiler::NoCacheReason::kNoCacheNoReason );
1540- if (!second_parse_try_catch.HasTerminated ()) {
1541- if (second_parse_try_catch.HasCaught ()) {
1542- // If on the second parse an error is thrown by ESM syntax, then
1543- // what happened was that the user had top-level `await` or a
1544- // top-level declaration of one of the CommonJS module variables
1545- // above the first `import` or `export`.
1546- Utf8Value second_message_value (
1547- env->isolate (), second_parse_try_catch.Message ()->Get ());
1548- auto second_message = second_message_value.ToStringView ();
1549- for (const auto & error_message : esm_syntax_error_messages) {
1550- if (second_message.find (error_message) !=
1551- std::string_view::npos) {
1552- should_retry_as_esm = true ;
1553- break ;
1554- }
1555- }
1556- } else {
1557- // No errors thrown in the second parse, so most likely the error
1558- // was caused by a top-level `await` or a top-level declaration of
1559- // one of the CommonJS module variables.
1560- should_retry_as_esm = true ;
1561- }
1562- }
1563- break ;
1564- }
1565- }
1566- }
1485+ should_retry_as_esm =
1486+ ContextifyContext::ShouldRetryAsESMInternal (env, code);
15671487 }
15681488 args.GetReturnValue ().Set (should_retry_as_esm);
15691489}
15701490
15711491void ContextifyContext::ShouldRetryAsESM (
15721492 const FunctionCallbackInfo<Value>& args) {
15731493 Environment* env = Environment::GetCurrent (args);
1574- Isolate* isolate = env->isolate ();
1575- Local<Context> context = env->context ();
15761494
1577- if (args.Length () != 1 ) {
1578- return THROW_ERR_MISSING_ARGS (env, " shouldRetryAsESM needs 1 argument" );
1579- }
1495+ CHECK_EQ (args.Length (), 1 );
1496+
15801497 // Argument 1: source code
15811498 Local<String> code;
15821499 CHECK (args[0 ]->IsString ());
15831500 code = args[0 ].As <String>();
15841501
1585- Local<String> script_id =
1586- String::NewFromUtf8 (isolate, " throwaway" ).ToLocalChecked ();
1502+ bool should_retry_as_esm =
1503+ ContextifyContext::ShouldRetryAsESMInternal (env, code);
1504+
1505+ args.GetReturnValue ().Set (should_retry_as_esm);
1506+ }
1507+
1508+ bool ContextifyContext::ShouldRetryAsESMInternal (Environment* env,
1509+ Local<String> code) {
1510+ Isolate* isolate = env->isolate ();
1511+
1512+ Local<String> script_id = FIXED_ONE_BYTE_STRING (isolate, " throwaway" );
15871513 Local<Symbol> id_symbol = Symbol::New (isolate, script_id);
15881514
15891515 Local<PrimitiveArray> host_defined_options =
@@ -1609,6 +1535,7 @@ void ContextifyContext::ShouldRetryAsESM(
16091535 ScriptCompiler::Source wrapped_source = GetCommonJSSourceInstance (
16101536 isolate, code, script_id, 0 , 0 , host_defined_options, nullptr );
16111537
1538+ Local<Context> context = env->context ();
16121539 std::vector<Local<String>> params = GetCJSParameters (env->isolate_data ());
16131540 std::ignore = ScriptCompiler::CompileFunction (
16141541 context,
@@ -1620,7 +1547,6 @@ void ContextifyContext::ShouldRetryAsESM(
16201547 options,
16211548 v8::ScriptCompiler::NoCacheReason::kNoCacheNoReason );
16221549
1623- bool should_retry_as_esm = false ;
16241550 if (!try_catch.HasTerminated ()) {
16251551 if (try_catch.HasCaught ()) {
16261552 // If on the second parse an error is thrown by ESM syntax, then
@@ -1631,18 +1557,17 @@ void ContextifyContext::ShouldRetryAsESM(
16311557 auto message_view = message_value.ToStringView ();
16321558 for (const auto & error_message : esm_syntax_error_messages) {
16331559 if (message_view.find (error_message) != std::string_view::npos) {
1634- should_retry_as_esm = true ;
1635- break ;
1560+ return true ;
16361561 }
16371562 }
16381563 } else {
16391564 // No errors thrown in the second parse, so most likely the error
16401565 // was caused by a top-level `await` or a top-level declaration of
16411566 // one of the CommonJS module variables.
1642- should_retry_as_esm = true ;
1567+ return true ;
16431568 }
16441569 }
1645- args. GetReturnValue (). Set (should_retry_as_esm) ;
1570+ return false ;
16461571}
16471572
16481573static void CompileFunctionForCJSLoader (
0 commit comments