diff options
author | 2023-06-02 02:07:17 -0700 | |
---|---|---|
committer | 2023-06-02 02:07:17 -0700 | |
commit | df2738ac824e46499b2f046a4eba165c19466e0e (patch) | |
tree | 94fc225123b83d2b82f9a7a7084131c07691b182 | |
parent | 4c6245b2e5788ac46e31bf67beefab8cdadebedb (diff) | |
download | bun-jarred/redo-evaluation-order.tar.gz bun-jarred/redo-evaluation-order.tar.zst bun-jarred/redo-evaluation-order.zip |
Align CommonJS evaluation order closer to Node.jsjarred/redo-evaluation-order
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | src/bun.js/bindings/CommonJSModuleRecord.cpp | 379 | ||||
-rw-r--r-- | src/bun.js/bindings/CommonJSModuleRecord.h | 7 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGlobalObject.cpp | 11 | ||||
-rw-r--r-- | src/bun.js/bindings/node_util_types.cpp | 4 | ||||
-rw-r--r-- | src/bun.js/bindings/node_util_types.h | 2 | ||||
-rw-r--r-- | src/bun.js/modules/BufferModule.h | 10 | ||||
-rw-r--r-- | src/bun.js/modules/EventsModule.h | 11 | ||||
-rw-r--r-- | src/bun.js/modules/NodeModuleModule.cpp | 10 | ||||
-rw-r--r-- | src/bun.js/modules/NodeModuleModule.h | 8 | ||||
-rw-r--r-- | src/bun.js/modules/ObjectModule.cpp | 4 | ||||
-rw-r--r-- | src/bun.js/modules/ProcessModule.h | 11 | ||||
-rw-r--r-- | src/bun.js/modules/StringDecoderModule.h | 3 | ||||
-rw-r--r-- | src/bun.js/modules/TTYModule.h | 10 | ||||
-rw-r--r-- | src/js_parser.zig | 35 |
15 files changed, 293 insertions, 213 deletions
@@ -1109,6 +1109,7 @@ jsc-copy-headers: cp $(WEBKIT_DIR)/Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.h $(WEBKIT_RELEASE_DIR)/JavaScriptCore/PrivateHeaders/JavaScriptCore/JSTypedArrayViewPrototype.h cp $(WEBKIT_DIR)/Source/JavaScriptCore/runtime/JSTypedArrayPrototypes.h $(WEBKIT_RELEASE_DIR)/JavaScriptCore/PrivateHeaders/JavaScriptCore/JSTypedArrayPrototypes.h cp $(WEBKIT_DIR)/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.h $(WEBKIT_RELEASE_DIR)/JavaScriptCore/PrivateHeaders/JavaScriptCore/JSModuleNamespaceObject.h + cp $(WEBKIT_DIR)/Source/JavaScriptCore/runtime/JSModuleEnvironment.h $(WEBKIT_RELEASE_DIR)/JavaScriptCore/PrivateHeaders/JavaScriptCore/JSModuleEnvironment.h cp $(WEBKIT_DIR)/Source/JavaScriptCore/jit/JIT.h $(WEBKIT_RELEASE_DIR)/JavaScriptCore/PrivateHeaders/JavaScriptCore/JIT.h cp $(WEBKIT_DIR)/Source/JavaScriptCore/bytecode/StructureStubInfo.h $(WEBKIT_RELEASE_DIR)/JavaScriptCore/PrivateHeaders/JavaScriptCore/StructureStubInfo.h cp $(WEBKIT_DIR)/Source/JavaScriptCore/bytecode/AccessCase.h $(WEBKIT_RELEASE_DIR)/JavaScriptCore/PrivateHeaders/JavaScriptCore/AccessCase.h diff --git a/src/bun.js/bindings/CommonJSModuleRecord.cpp b/src/bun.js/bindings/CommonJSModuleRecord.cpp index a32d722d9..1df7e0edf 100644 --- a/src/bun.js/bindings/CommonJSModuleRecord.cpp +++ b/src/bun.js/bindings/CommonJSModuleRecord.cpp @@ -62,6 +62,8 @@ #include <JavaScriptCore/JSMap.h> #include <JavaScriptCore/JSMapInlines.h> +#include <JavaScriptCore/JSModuleEnvironment.h> +#include <JavaScriptCore/SyntheticModuleRecord.h> namespace Bun { using namespace JSC; @@ -247,7 +249,6 @@ const JSC::ClassInfo JSCommonJSModule::s_info = { "Module"_s, &Base::s_info, nul JSCommonJSModule* createCommonJSModuleObject( Zig::GlobalObject* globalObject, - const ResolvedSource& source, const WTF::String& sourceURL, JSC::JSValue exportsObjectValue, JSC::JSValue requireFunctionValue) @@ -287,6 +288,180 @@ static bool canPerformFastEnumeration(Structure* s) return true; } +JSC::JSValue evaluateCommonJSModule( + Zig::GlobalObject* globalObject, + JSC::SyntheticModuleRecord* syntheticModuleRecord, + EvalExecutable* executable) +{ + auto sourceURL = syntheticModuleRecord->moduleKey().string().string(); + auto& vm = globalObject->vm(); + auto throwScope = DECLARE_THROW_SCOPE(vm); + auto* requireMapKey = jsString(vm, sourceURL); + + unsigned int exportCount = syntheticModuleRecord->exportEntries().size(); + JSC::JSObject* exportsObject = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype()); + + auto index = sourceURL.reverseFind('/', sourceURL.length()); + JSString* dirname = jsEmptyString(vm); + JSString* filename = requireMapKey; + if (index != WTF::notFound) { + dirname = JSC::jsSubstring(globalObject, requireMapKey, 0, index); + } + + globalObject->requireMap()->set(globalObject, requireMapKey, exportsObject); + + JSC::Structure* scopeExtensionObjectStructure = globalObject->commonJSFunctionArgumentsStructure(); + JSC::JSObject* scopeExtensionObject = JSC::constructEmptyObject( + vm, + scopeExtensionObjectStructure); + + auto* requireFunction = Zig::ImportMetaObject::createRequireFunction(vm, globalObject, sourceURL); + + auto* moduleObject = createCommonJSModuleObject(globalObject, + sourceURL, + exportsObject, + requireFunction); + + scopeExtensionObject->putDirectOffset( + vm, + 0, + moduleObject); + + scopeExtensionObject->putDirectOffset( + vm, + 1, + exportsObject); + + scopeExtensionObject->putDirectOffset( + vm, + 2, + dirname); + + scopeExtensionObject->putDirectOffset( + vm, + 3, + filename); + + scopeExtensionObject->putDirectOffset( + vm, + 4, + requireFunction); + + if (UNLIKELY(throwScope.exception())) { + globalObject->requireMap()->remove(globalObject, requireMapKey); + throwScope.release(); + return {}; + } + + auto catchScope = DECLARE_CATCH_SCOPE(vm); + + // Where the magic happens. + // + // A `with` scope is created containing { module, exports, require }. + // We eval() the CommonJS module code + // with that scope. + // + // Doing it that way saves us a roundtrip through C++ <> JS. + // + // Sidenote: another implementation could use + // FunctionExecutable. It looks like there are lots of arguments + // to pass to that and it isn't used directly much, so that + // seems harder to do correctly. + { + JSWithScope* withScope = JSWithScope::create(vm, globalObject, globalObject->globalScope(), scopeExtensionObject); + auto* globalExtension = globalObject->globalScopeExtension(); + globalObject->setGlobalScopeExtension(withScope); + vm.interpreter.executeEval(executable, globalObject, globalObject->globalScope()); + globalObject->setGlobalScopeExtension(globalExtension); + syntheticModuleRecord->setUserValue(vm, jsUndefined()); + } + + if (throwScope.exception()) { + globalObject->requireMap()->remove(globalObject, requireMapKey); + throwScope.release(); + return {}; + } + + JSValue result = moduleObject->exportsObject(); + + globalObject->requireMap()->set(globalObject, requireMapKey, result); + + // The developer can do something like: + // + // Object.defineProperty(module, 'exports', {get: getter}) + // + // In which case, the exports object is now a GetterSetter object. + // + // We can't return a GetterSetter object to ESM code, so we need to call it. + if (!result.isEmpty() && (result.isGetterSetter() || result.isCustomGetterSetter())) { + auto* clientData = WebCore::clientData(vm); + + // TODO: is there a faster way to call these getters? We shouldn't need to do a full property lookup. + // + // we use getIfPropertyExists just incase a pathological devleoper did: + // + // - Object.defineProperty(module, 'exports', {get: getter}) + // - delete module.exports + // + result = moduleObject->getIfPropertyExists(globalObject, clientData->builtinNames().exportsPublicName()); + + if (UNLIKELY(throwScope.exception())) { + // Unlike getters on properties of the exports object + // When the exports object itself is a getter and it throws + // There's not a lot we can do + // so we surface that error + globalObject->requireMap()->remove(globalObject, requireMapKey); + throwScope.release(); + } + } + + auto* moduleEnvironment = syntheticModuleRecord->moduleEnvironment(); + + if (result && result.isObject()) { + auto* jsExportsObject = jsCast<JSC::JSObject*>(result); + auto defaultKeyword = vm.propertyNames->defaultKeyword; + for (auto& exportEntry : syntheticModuleRecord->exportEntries()) { + PropertyName exportName = exportEntry.value.localName; + + if (exportName == defaultKeyword) { + continue; + } else if (exportName.isSymbol()) + continue; + + JSValue exportValue = jsExportsObject->getIfPropertyExists(globalObject, exportName); + if (UNLIKELY(catchScope.exception())) { + catchScope.clearException(); + continue; + } + + constexpr bool shouldThrowReadOnlyError = false; + constexpr bool ignoreReadOnlyErrors = true; + bool putResult = false; + symbolTablePutTouchWatchpointSet(moduleEnvironment, globalObject, exportName, exportValue, shouldThrowReadOnlyError, ignoreReadOnlyErrors, putResult); + } + } + + if (result) { + constexpr bool shouldThrowReadOnlyError = false; + constexpr bool ignoreReadOnlyErrors = true; + bool putResult = false; + PropertyName exportName = vm.propertyNames->defaultKeyword; + JSValue exportValue = result; + symbolTablePutTouchWatchpointSet(moduleEnvironment, globalObject, exportName, exportValue, shouldThrowReadOnlyError, ignoreReadOnlyErrors, putResult); + } + + { + constexpr bool shouldThrowReadOnlyError = false; + constexpr bool ignoreReadOnlyErrors = true; + bool putResult = false; + PropertyName exportName = Identifier::fromUid(vm.symbolRegistry().symbolForKey("module"_s)); + JSValue exportValue = moduleObject; + symbolTablePutTouchWatchpointSet(moduleEnvironment, globalObject, exportName, exportValue, shouldThrowReadOnlyError, ignoreReadOnlyErrors, putResult); + } + + return {}; +} + JSC::SourceCode createCommonJSModule( Zig::GlobalObject* globalObject, ResolvedSource source) @@ -299,218 +474,52 @@ JSC::SourceCode createCommonJSModule( [source, sourceURL](JSC::JSGlobalObject* lexicalGlobalObject, JSC::Identifier moduleKey, Vector<JSC::Identifier, 4>& exportNames, - JSC::MarkedArgumentBuffer& exportValues) -> void { + JSC::MarkedArgumentBuffer& exportValues) -> JSValue { Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); - auto& vm = globalObject->vm(); - auto throwScope = DECLARE_THROW_SCOPE(vm); auto sourceCodeString = Zig::toString(source.source_code); - auto* requireMapKey = jsString(vm, sourceURL); - - JSC::JSObject* exportsObject = source.commonJSExportsLen < 64 - ? JSC::constructEmptyObject(globalObject, globalObject->objectPrototype(), source.commonJSExportsLen) - : JSC::constructEmptyObject(globalObject, globalObject->objectPrototype()); - - auto index = sourceURL.reverseFind('/', sourceURL.length()); - JSString* dirname = jsEmptyString(vm); - JSString* filename = requireMapKey; - if (index != WTF::notFound) { - dirname = JSC::jsSubstring(globalObject, requireMapKey, 0, index); - } - - globalObject->requireMap()->set(globalObject, requireMapKey, exportsObject); + auto& vm = globalObject->vm(); JSC::SourceCode inputSource( JSC::StringSourceProvider::create(sourceCodeString, JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(sourceURL)), sourceURL, TextPosition())); - JSC::Structure* scopeExtensionObjectStructure = globalObject->commonJSFunctionArgumentsStructure(); - JSC::JSObject* scopeExtensionObject = JSC::constructEmptyObject( - vm, - scopeExtensionObjectStructure); - - auto* requireFunction = Zig::ImportMetaObject::createRequireFunction(vm, globalObject, sourceURL); - - auto* moduleObject = createCommonJSModuleObject(globalObject, - source, - sourceURL, - exportsObject, - requireFunction); - scopeExtensionObject->putDirectOffset( - vm, - 0, - moduleObject); - - scopeExtensionObject->putDirectOffset( - vm, - 1, - exportsObject); - - scopeExtensionObject->putDirectOffset( - vm, - 2, - dirname); - - scopeExtensionObject->putDirectOffset( - vm, - 3, - filename); - - scopeExtensionObject->putDirectOffset( - vm, - 4, - requireFunction); - + auto throwScope = DECLARE_THROW_SCOPE(vm); auto* executable = JSC::DirectEvalExecutable::create( globalObject, inputSource, DerivedContextType::None, NeedsClassFieldInitializer::No, PrivateBrandRequirement::None, false, false, EvalContextType::None, nullptr, nullptr, ECMAMode::sloppy()); if (UNLIKELY(!executable && !throwScope.exception())) { - // I'm not sure if this case happens, but it's better to be safe than sorry. - throwSyntaxError(globalObject, throwScope, "Failed to compile CommonJS module."_s); + throwSyntaxError(globalObject, throwScope, "Failed to create CommonJS module"_s); } if (UNLIKELY(throwScope.exception())) { - globalObject->requireMap()->remove(globalObject, requireMapKey); throwScope.release(); - return; + return jsUndefined(); } - auto catchScope = DECLARE_CATCH_SCOPE(vm); - - // Where the magic happens. - // - // A `with` scope is created containing { module, exports, require }. - // We eval() the CommonJS module code - // with that scope. - // - // Doing it that way saves us a roundtrip through C++ <> JS. - // - // Sidenote: another implementation could use - // FunctionExecutable. It looks like there are lots of arguments - // to pass to that and it isn't used directly much, so that - // seems harder to do correctly. - { - JSWithScope* withScope = JSWithScope::create(vm, globalObject, globalObject->globalScope(), scopeExtensionObject); - vm.interpreter.executeEval(executable, globalObject, withScope); - - if (UNLIKELY(catchScope.exception())) { - auto returnedException = catchScope.exception(); - catchScope.clearException(); - JSC::throwException(globalObject, throwScope, returnedException); - } - } - - if (throwScope.exception()) { - globalObject->requireMap()->remove(globalObject, requireMapKey); - throwScope.release(); - return; - } - - JSValue result = moduleObject->exportsObject(); - - // The developer can do something like: - // - // Object.defineProperty(module, 'exports', {get: getter}) - // - // In which case, the exports object is now a GetterSetter object. - // - // We can't return a GetterSetter object to ESM code, so we need to call it. - if (!result.isEmpty() && (result.isGetterSetter() || result.isCustomGetterSetter())) { - auto* clientData = WebCore::clientData(vm); - - // TODO: is there a faster way to call these getters? We shouldn't need to do a full property lookup. - // - // we use getIfPropertyExists just incase a pathological devleoper did: - // - // - Object.defineProperty(module, 'exports', {get: getter}) - // - delete module.exports - // - result = moduleObject->getIfPropertyExists(globalObject, clientData->builtinNames().exportsPublicName()); - - if (UNLIKELY(throwScope.exception())) { - // Unlike getters on properties of the exports object - // When the exports object itself is a getter and it throws - // There's not a lot we can do - // so we surface that error - globalObject->requireMap()->remove(globalObject, requireMapKey); - throwScope.release(); - return; - } - } - - globalObject->requireMap()->set(globalObject, requireMapKey, result); + size_t exportNamesLen = source.commonJSExportsLen > 0 && source.commonJSExportsLen < std::numeric_limits<uint32_t>::max() ? source.commonJSExportsLen : 0; + exportNames.reserveCapacity(exportNamesLen + 3); + exportValues.ensureCapacity(exportNamesLen + 3); exportNames.append(vm.propertyNames->defaultKeyword); - exportValues.append(result); + exportValues.append(jsUndefined()); // This exists to tell ImportMetaObject.ts that this is a CommonJS module. exportNames.append(Identifier::fromUid(vm.symbolRegistry().symbolForKey("CommonJS"_s))); exportValues.append(jsNumber(0)); - // This strong reference exists because otherwise it will crash when the finalizer runs. + // This exists to tell ImportMetaObject.ts that this is a CommonJS module. exportNames.append(Identifier::fromUid(vm.symbolRegistry().symbolForKey("module"_s))); - exportValues.append(moduleObject); - - if (result.isObject()) { - auto* exports = asObject(result); - - auto* structure = exports->structure(); - uint32_t size = structure->inlineSize() + structure->outOfLineSize(); - exportNames.reserveCapacity(size + 3); - exportValues.ensureCapacity(size + 3); - - if (canPerformFastEnumeration(structure)) { - exports->structure()->forEachProperty(vm, [&](const PropertyTableEntry& entry) -> bool { - auto key = entry.key(); - if (key->isSymbol() || key == vm.propertyNames->defaultKeyword || entry.attributes() & PropertyAttribute::DontEnum) - return true; - - exportNames.append(Identifier::fromUid(vm, key)); - - JSValue value = exports->getDirect(entry.offset()); - - exportValues.append(value); - return true; - }); - } else { - JSC::PropertyNameArray properties(vm, JSC::PropertyNameMode::Strings, JSC::PrivateSymbolMode::Exclude); - exports->methodTable()->getOwnPropertyNames(exports, globalObject, properties, DontEnumPropertiesMode::Exclude); - if (throwScope.exception()) { - throwScope.release(); - return; - } - - for (auto property : properties) { - if (UNLIKELY(property.isEmpty() || property.isNull())) - continue; - - // ignore constructor - if (property == vm.propertyNames->constructor) - continue; - - if (property.isSymbol() || property.isPrivateName() || property == vm.propertyNames->defaultKeyword) - continue; - - JSC::PropertySlot slot(exports, PropertySlot::InternalMethodType::Get); - if (!exports->getPropertySlot(globalObject, property, slot)) - continue; - - exportNames.append(property); - - JSValue getterResult = slot.getValue(globalObject, property); - - // If it throws, we keep them in the exports list, but mark it as undefined - // This is consistent with what Node.js does. - if (catchScope.exception()) { - catchScope.clearException(); - getterResult = jsUndefined(); - } - - exportValues.append(getterResult); - } - } + exportValues.append(jsUndefined()); + + for (size_t i = 0; i < exportNamesLen; i++) { + auto str = Zig::toStringCopy(source.commonJSExports[i]); + exportNames.append(Identifier::fromString(vm, str)); + exportValues.append(jsUndefined()); } + vm.heap.collectAsync(); + return executable; }, SourceOrigin(WTF::URL::fileURLWithFileSystemPath(sourceURL)), sourceURL)); diff --git a/src/bun.js/bindings/CommonJSModuleRecord.h b/src/bun.js/bindings/CommonJSModuleRecord.h index 86daf875d..ba03d8a71 100644 --- a/src/bun.js/bindings/CommonJSModuleRecord.h +++ b/src/bun.js/bindings/CommonJSModuleRecord.h @@ -6,6 +6,8 @@ class GlobalObject; } namespace JSC { class SourceCode; +class EvalExecutable; +class SyntheticModuleRecord; } namespace Bun { @@ -17,4 +19,9 @@ JSC::SourceCode createCommonJSModule( Zig::GlobalObject* globalObject, ResolvedSource source); +JSC::JSValue evaluateCommonJSModule( + Zig::GlobalObject* globalObject, + JSC::SyntheticModuleRecord* syntheticModuleRecord, + EvalExecutable* executable); + } // namespace Bun diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index 0a453a9c8..5810b25fb 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -178,6 +178,7 @@ namespace JSCastingHelpers = JSC::JSCastingHelpers; #include "CallSitePrototype.h" #include "DOMWrapperWorld-class.h" #include "CommonJSModuleRecord.h" +#include "JavaScriptCore/SyntheticModuleRecord.h" constexpr size_t DEFAULT_ERROR_STACK_TRACE_LIMIT = 10; @@ -4113,6 +4114,16 @@ JSC::JSValue GlobalObject::moduleLoaderEvaluate(JSGlobalObject* globalObject, return scriptFetcher; } + if (JSC::SyntheticModuleRecord* record = jsDynamicCast<JSC::SyntheticModuleRecord*>(moduleRecordValue)) { + if (JSValue userValue = record->userValue()) { + auto* evalExecutable = jsDynamicCast<JSC::EvalExecutable*>(userValue); + return Bun::evaluateCommonJSModule( + reinterpret_cast<Zig::GlobalObject*>(globalObject), + record, + evalExecutable); + } + } + JSC::JSValue result = moduleLoader->evaluateNonVirtual(globalObject, key, moduleRecordValue, scriptFetcher, sentValue, resumeMode); diff --git a/src/bun.js/bindings/node_util_types.cpp b/src/bun.js/bindings/node_util_types.cpp index 0c75662cf..bfe46e712 100644 --- a/src/bun.js/bindings/node_util_types.cpp +++ b/src/bun.js/bindings/node_util_types.cpp @@ -313,7 +313,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionIsCryptoKey, (JSC::JSGlobalObject * globalObj } namespace Bun { -void generateNodeUtilTypesSourceCode(JSC::JSGlobalObject* lexicalGlobalObject, +JSC::JSValue generateNodeUtilTypesSourceCode(JSC::JSGlobalObject* lexicalGlobalObject, JSC::Identifier moduleKey, Vector<JSC::Identifier, 4>& exportNames, JSC::MarkedArgumentBuffer& exportValues) @@ -379,5 +379,7 @@ void generateNodeUtilTypesSourceCode(JSC::JSGlobalObject* lexicalGlobalObject, exportNames.append(JSC::Identifier::fromString(vm, "default"_s)); exportValues.append(defaultObject); + return {}; } + } diff --git a/src/bun.js/bindings/node_util_types.h b/src/bun.js/bindings/node_util_types.h index adf0cd0ea..9cacb4050 100644 --- a/src/bun.js/bindings/node_util_types.h +++ b/src/bun.js/bindings/node_util_types.h @@ -4,7 +4,7 @@ namespace Bun { using namespace WebCore; -void generateNodeUtilTypesSourceCode(JSC::JSGlobalObject* lexicalGlobalObject, +JSC::JSValue generateNodeUtilTypesSourceCode(JSC::JSGlobalObject* lexicalGlobalObject, JSC::Identifier moduleKey, Vector<JSC::Identifier, 4>& exportNames, JSC::MarkedArgumentBuffer& exportValues); diff --git a/src/bun.js/modules/BufferModule.h b/src/bun.js/modules/BufferModule.h index 42eab5173..8c456f72d 100644 --- a/src/bun.js/modules/BufferModule.h +++ b/src/bun.js/modules/BufferModule.h @@ -18,10 +18,11 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionNotImplemented, return JSValue::encode(jsUndefined()); } -inline void generateBufferSourceCode(JSC::JSGlobalObject *lexicalGlobalObject, - JSC::Identifier moduleKey, - Vector<JSC::Identifier, 4> &exportNames, - JSC::MarkedArgumentBuffer &exportValues) { +inline JSValue +generateBufferSourceCode(JSC::JSGlobalObject *lexicalGlobalObject, + JSC::Identifier moduleKey, + Vector<JSC::Identifier, 4> &exportNames, + JSC::MarkedArgumentBuffer &exportValues) { JSC::VM &vm = lexicalGlobalObject->vm(); GlobalObject *globalObject = reinterpret_cast<GlobalObject *>(lexicalGlobalObject); @@ -105,6 +106,7 @@ inline void generateBufferSourceCode(JSC::JSGlobalObject *lexicalGlobalObject, exportNames.append(vm.propertyNames->defaultKeyword); exportValues.append(defaultObject); + return {}; } } // namespace Zig diff --git a/src/bun.js/modules/EventsModule.h b/src/bun.js/modules/EventsModule.h index 7d53ff838..49685b8db 100644 --- a/src/bun.js/modules/EventsModule.h +++ b/src/bun.js/modules/EventsModule.h @@ -4,10 +4,11 @@ namespace Zig { using namespace WebCore; -inline void generateEventsSourceCode(JSC::JSGlobalObject *lexicalGlobalObject, - JSC::Identifier moduleKey, - Vector<JSC::Identifier, 4> &exportNames, - JSC::MarkedArgumentBuffer &exportValues) { +inline JSValue +generateEventsSourceCode(JSC::JSGlobalObject *lexicalGlobalObject, + JSC::Identifier moduleKey, + Vector<JSC::Identifier, 4> &exportNames, + JSC::MarkedArgumentBuffer &exportValues) { JSC::VM &vm = lexicalGlobalObject->vm(); GlobalObject *globalObject = reinterpret_cast<GlobalObject *>(lexicalGlobalObject); @@ -53,6 +54,8 @@ inline void generateEventsSourceCode(JSC::JSGlobalObject *lexicalGlobalObject, exportNames.append(JSC::Identifier::fromString(vm, "default"_s)); exportValues.append(eventEmitterModuleCJS); + + return {}; } } // namespace Zig diff --git a/src/bun.js/modules/NodeModuleModule.cpp b/src/bun.js/modules/NodeModuleModule.cpp index f11277709..849d3eafd 100644 --- a/src/bun.js/modules/NodeModuleModule.cpp +++ b/src/bun.js/modules/NodeModuleModule.cpp @@ -116,10 +116,10 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionResolveFileName, } namespace Zig { -void generateNodeModuleModule(JSC::JSGlobalObject *globalObject, - JSC::Identifier moduleKey, - Vector<JSC::Identifier, 4> &exportNames, - JSC::MarkedArgumentBuffer &exportValues) { +JSValue generateNodeModuleModule(JSC::JSGlobalObject *globalObject, + JSC::Identifier moduleKey, + Vector<JSC::Identifier, 4> &exportNames, + JSC::MarkedArgumentBuffer &exportValues) { JSC::VM &vm = globalObject->vm(); exportValues.append(JSFunction::create( @@ -185,5 +185,7 @@ void generateNodeModuleModule(JSC::JSGlobalObject *globalObject, builtinModules->putDirectIndex(globalObject, 6, JSC::jsString(vm, String("bun:sqlite"_s))); exportValues.append(builtinModules); + + return {}; } } // namespace Zig diff --git a/src/bun.js/modules/NodeModuleModule.h b/src/bun.js/modules/NodeModuleModule.h index 0aefdef12..1722e779f 100644 --- a/src/bun.js/modules/NodeModuleModule.h +++ b/src/bun.js/modules/NodeModuleModule.h @@ -4,9 +4,9 @@ namespace Zig { // node:module -void generateNodeModuleModule(JSC::JSGlobalObject *globalObject, - JSC::Identifier moduleKey, - Vector<JSC::Identifier, 4> &exportNames, - JSC::MarkedArgumentBuffer &exportValues); +JSValue generateNodeModuleModule(JSC::JSGlobalObject *globalObject, + JSC::Identifier moduleKey, + Vector<JSC::Identifier, 4> &exportNames, + JSC::MarkedArgumentBuffer &exportValues); } // namespace Zig
\ No newline at end of file diff --git a/src/bun.js/modules/ObjectModule.cpp b/src/bun.js/modules/ObjectModule.cpp index 4272bec4e..2b528d7c6 100644 --- a/src/bun.js/modules/ObjectModule.cpp +++ b/src/bun.js/modules/ObjectModule.cpp @@ -9,7 +9,7 @@ generateObjectModuleSourceCode(JSC::JSGlobalObject *globalObject, return [object](JSC::JSGlobalObject *lexicalGlobalObject, JSC::Identifier moduleKey, Vector<JSC::Identifier, 4> &exportNames, - JSC::MarkedArgumentBuffer &exportValues) -> void { + JSC::MarkedArgumentBuffer &exportValues) -> JSValue { JSC::VM &vm = lexicalGlobalObject->vm(); GlobalObject *globalObject = reinterpret_cast<GlobalObject *>(lexicalGlobalObject); @@ -24,6 +24,8 @@ generateObjectModuleSourceCode(JSC::JSGlobalObject *globalObject, exportNames.append(entry); exportValues.append(object->get(globalObject, entry)); } + + return {}; }; } } // namespace Zig
\ No newline at end of file diff --git a/src/bun.js/modules/ProcessModule.h b/src/bun.js/modules/ProcessModule.h index 3c9c3261f..c84080cdf 100644 --- a/src/bun.js/modules/ProcessModule.h +++ b/src/bun.js/modules/ProcessModule.h @@ -35,10 +35,11 @@ JSC_DEFINE_CUSTOM_SETTER(jsFunctionProcessModuleCommonJSSetter, ->putDirect(vm, propertyName, JSValue::decode(encodedValue), 0); } -inline void generateProcessSourceCode(JSC::JSGlobalObject *lexicalGlobalObject, - JSC::Identifier moduleKey, - Vector<JSC::Identifier, 4> &exportNames, - JSC::MarkedArgumentBuffer &exportValues) { +inline JSValue +generateProcessSourceCode(JSC::JSGlobalObject *lexicalGlobalObject, + JSC::Identifier moduleKey, + Vector<JSC::Identifier, 4> &exportNames, + JSC::MarkedArgumentBuffer &exportValues) { JSC::VM &vm = lexicalGlobalObject->vm(); GlobalObject *globalObject = reinterpret_cast<GlobalObject *>(lexicalGlobalObject); @@ -71,6 +72,8 @@ inline void generateProcessSourceCode(JSC::JSGlobalObject *lexicalGlobalObject, jsFunctionProcessModuleCommonJSSetter), 0); } + + return {}; } } // namespace Zig diff --git a/src/bun.js/modules/StringDecoderModule.h b/src/bun.js/modules/StringDecoderModule.h index c3b5f57bb..afcb5c0ee 100644 --- a/src/bun.js/modules/StringDecoderModule.h +++ b/src/bun.js/modules/StringDecoderModule.h @@ -4,7 +4,7 @@ namespace Zig { -inline void +inline JSValue generateStringDecoderSourceCode(JSC::JSGlobalObject *lexicalGlobalObject, JSC::Identifier moduleKey, Vector<JSC::Identifier, 4> &exportNames, @@ -28,6 +28,7 @@ generateStringDecoderSourceCode(JSC::JSGlobalObject *lexicalGlobalObject, exportNames.append(vm.propertyNames->defaultKeyword); exportValues.append(defaultObject); + return {}; } } // namespace Zig diff --git a/src/bun.js/modules/TTYModule.h b/src/bun.js/modules/TTYModule.h index 423268b32..c5f2afd7b 100644 --- a/src/bun.js/modules/TTYModule.h +++ b/src/bun.js/modules/TTYModule.h @@ -31,10 +31,10 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionNotImplementedYet, return JSValue::encode(jsUndefined()); } -inline void generateTTYSourceCode(JSC::JSGlobalObject *lexicalGlobalObject, - JSC::Identifier moduleKey, - Vector<JSC::Identifier, 4> &exportNames, - JSC::MarkedArgumentBuffer &exportValues) { +inline JSValue generateTTYSourceCode(JSC::JSGlobalObject *lexicalGlobalObject, + JSC::Identifier moduleKey, + Vector<JSC::Identifier, 4> &exportNames, + JSC::MarkedArgumentBuffer &exportValues) { JSC::VM &vm = lexicalGlobalObject->vm(); GlobalObject *globalObject = reinterpret_cast<GlobalObject *>(lexicalGlobalObject); @@ -73,6 +73,8 @@ inline void generateTTYSourceCode(JSC::JSGlobalObject *lexicalGlobalObject, exportNames.append(vm.propertyNames->defaultKeyword); exportValues.append(tty); + + return {}; } } // namespace Zig diff --git a/src/js_parser.zig b/src/js_parser.zig index 5f46507d7..ac8d9fea2 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -17603,6 +17603,41 @@ fn NewParser_( // rewrite `module.exports` to `exports` return p.newExpr(E.Identifier{ .ref = p.exports_ref }, name_loc); + } else if (p.options.features.commonjs_at_runtime and strings.eqlComptime(name, "exports")) { + + // Detect if we are doing + // + // module.exports = { + // foo: "bar" + // } + // + // Note that it cannot be any of these: + // + // module.exports += { }; + // delete module.exports = {}; + // module.exports() + if (!(identifier_opts.is_call_target or identifier_opts.is_delete_target) and + identifier_opts.assign_target == .replace and + p.stmt_expr_value == .e_binary and + p.stmt_expr_value.e_binary.op == .bin_assign and + !(p.stmt_expr_value.e_binary.right.data != .e_object or + p.stmt_expr_value.e_binary.left.data != .e_dot or + !strings.eqlComptime(p.stmt_expr_value.e_binary.left.data.e_dot.name, "exports") or + p.stmt_expr_value.e_binary.left.data.e_dot.target.data != .e_identifier or + !p.stmt_expr_value.e_binary.left.data.e_dot.target.data.e_identifier.ref.eql(p.module_ref))) + { + const props: []const G.Property = p.stmt_expr_value.e_binary.right.data.e_object.properties.slice(); + for (props) |prop| { + // only worry about string literals + if (prop.key == null or + prop.key.?.data != .e_string or prop.key.?.data.e_string.len() == 0) + { + continue; + } + + _ = p.commonjs_export_names.getOrPut(p.allocator, prop.key.?.data.e_string.slice(p.allocator)) catch unreachable; + } + } } else if (p.options.bundle and strings.eqlComptime(name, "id") and identifier_opts.assign_target == .none) { // inline module.id p.ignoreUsage(p.module_ref); |