@@ -1648,44 +1648,62 @@ throw NativeScriptException(
16481648 // Create a module object with exports that throws when accessed
16491649 Local<Object> moduleObj = Object::New (isolate);
16501650
1651- // Create a Proxy that throws an error when any property is accessed
1651+ // Create a Proxy that throws an error when any property is accessed.
1652+ //
1653+ // The message is passed to a constant factory script as a real V8 string
1654+ // (never interpolated into the script source). Interpolation is a JS
1655+ // injection hazard: the message itself contains single quotes
1656+ // ("Module 'zip' is not available...") which terminated the string literal
1657+ // early and made the generated script a guaranteed SyntaxError
1658+ // ("missing ) after argument list") that propagated out of require() with
1659+ // no hint of its origin.
16521660 std::string errorMessage =
16531661 " Module '" + moduleName + " ' is not available. This is an optional module." ;
1654- std::string proxyCode = " (function() {"
1655- " const error = new Error('" +
1656- errorMessage +
1657- " ');"
1658- " return new Proxy({}, {"
1659- " get: function(target, prop) {"
1660- " throw error;"
1661- " },"
1662- " set: function(target, prop, value) {"
1663- " throw error;"
1664- " },"
1665- " has: function(target, prop) {"
1666- " return false;"
1667- " },"
1668- " ownKeys: function(target) {"
1669- " return [];"
1670- " },"
1671- " getPrototypeOf: function(target) {"
1672- " return null;"
1673- " }"
1674- " });"
1675- " })()" ;
1662+ static const char * kProxyFactorySource = " (function(msg) {"
1663+ " const error = new Error(msg);"
1664+ " return new Proxy({}, {"
1665+ " get: function(target, prop) {"
1666+ " throw error;"
1667+ " },"
1668+ " set: function(target, prop, value) {"
1669+ " throw error;"
1670+ " },"
1671+ " has: function(target, prop) {"
1672+ " return false;"
1673+ " },"
1674+ " ownKeys: function(target) {"
1675+ " return [];"
1676+ " },"
1677+ " getPrototypeOf: function(target) {"
1678+ " return null;"
1679+ " }"
1680+ " });"
1681+ " })" ;
16761682
1683+ TryCatch tc (isolate);
16771684 Local<Script> proxyScript;
1678- if (Script::Compile (context, tns::ToV8String (isolate, proxyCode.c_str ())).ToLocal (&proxyScript)) {
1679- Local<Value> proxyObject;
1680- if (proxyScript->Run (context).ToLocal (&proxyObject)) {
1681- // Set the exports to the proxy object
1682- bool success = moduleObj->Set (context, tns::ToV8String (isolate, " exports" ), proxyObject)
1683- .FromMaybe (false );
1684- if (!success) {
1685- Log (@" Warning: Failed to set exports property on proxy module object" );
1685+ if (Script::Compile (context, tns::ToV8String (isolate, kProxyFactorySource )).ToLocal (&proxyScript)) {
1686+ Local<Value> factoryValue;
1687+ if (proxyScript->Run (context).ToLocal (&factoryValue) && factoryValue->IsFunction ()) {
1688+ Local<Value> args[]{tns::ToV8String (isolate, errorMessage.c_str ())};
1689+ Local<Value> proxyObject;
1690+ if (factoryValue.As <v8::Function>()
1691+ ->Call (context, v8::Undefined (isolate), 1 , args)
1692+ .ToLocal (&proxyObject)) {
1693+ // Set the exports to the proxy object
1694+ bool success = moduleObj->Set (context, tns::ToV8String (isolate, " exports" ), proxyObject)
1695+ .FromMaybe (false );
1696+ if (!success) {
1697+ Log (@" Warning: Failed to set exports property on proxy module object" );
1698+ }
16861699 }
16871700 }
16881701 }
1702+ if (tc.HasCaught ()) {
1703+ // The placeholder is best-effort. Never let its construction machinery
1704+ // leak an exception that masks the real "module not found" condition.
1705+ Log (@" Warning: placeholder module construction failed for %s " , moduleName.c_str ());
1706+ }
16891707
16901708 // Set up the module object
16911709 bool success = moduleObj
0 commit comments