Compare commits

...

1 Commits

Author SHA1 Message Date
Jarred Sumner
df2738ac82 Align CommonJS evaluation order closer to Node.js 2023-06-02 02:07:17 -07:00
15 changed files with 292 additions and 212 deletions

View File

@@ -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

View File

@@ -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);
exportValues.append(jsUndefined());
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);
}
}
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));

View File

@@ -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

View File

@@ -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);

View File

@@ -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 {};
}
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);