aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bun.js/bindings/CommonJSModuleRecord.cpp379
-rw-r--r--src/bun.js/bindings/CommonJSModuleRecord.h7
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp11
-rw-r--r--src/bun.js/bindings/node_util_types.cpp4
-rw-r--r--src/bun.js/bindings/node_util_types.h2
-rw-r--r--src/bun.js/modules/BufferModule.h10
-rw-r--r--src/bun.js/modules/EventsModule.h11
-rw-r--r--src/bun.js/modules/NodeModuleModule.cpp10
-rw-r--r--src/bun.js/modules/NodeModuleModule.h8
-rw-r--r--src/bun.js/modules/ObjectModule.cpp4
-rw-r--r--src/bun.js/modules/ProcessModule.h11
-rw-r--r--src/bun.js/modules/StringDecoderModule.h3
-rw-r--r--src/bun.js/modules/TTYModule.h10
-rw-r--r--src/js_parser.zig35
14 files changed, 292 insertions, 213 deletions
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);