Compare commits

...

1 Commits

Author SHA1 Message Date
John-David Dalton
c821a4d14a Add support for custom Module._extensions 2024-01-18 13:59:42 -08:00
16 changed files with 607 additions and 530 deletions

View File

@@ -68,11 +68,13 @@
#include <JavaScriptCore/HeapAnalyzer.h>
extern "C" bool Bun__isBunMain(JSC::JSGlobalObject* global, const BunString*);
extern "C" JSC__JSValue Bun__Path__basename(JSC__JSGlobalObject* arg0, bool arg1, JSC__JSValue* arg2, uint16_t arg3);
extern "C" JSC__JSValue Bun__Path__dirname(JSC__JSGlobalObject* arg0, bool arg1, JSC__JSValue* arg2, uint16_t arg3);
namespace Bun {
using namespace JSC;
JSC_DECLARE_HOST_FUNCTION(jsFunctionRequireCommonJS);
JSC_DECLARE_HOST_FUNCTION(jsFunctionRequirePrivate);
static bool canPerformFastEnumeration(Structure* s)
{
@@ -103,19 +105,23 @@ static bool evaluateCommonJSModuleOnce(JSC::VM& vm, Zig::GlobalObject* globalObj
return false;
}
auto clientData = WebCore::clientData(vm);
auto builtinNames = clientData->builtinNames();
auto globalString = globalObject->commonStrings().resolveString(globalObject);
JSFunction* resolveFunction = JSC::JSBoundFunction::create(vm,
globalObject,
globalObject->requireResolveFunctionUnbound(),
moduleObject->id(),
ArgList(), 1, globalObject->commonStrings().resolveString(globalObject));
ArgList(), 1, globalString);
JSFunction* requireFunction = JSC::JSBoundFunction::create(vm,
globalObject,
globalObject->requireFunctionUnbound(),
moduleObject,
ArgList(), 1, globalObject->commonStrings().requireString(globalObject));
ArgList(), 1, globalString);
requireFunction->putDirect(vm, vm.propertyNames->resolve, resolveFunction, 0);
moduleObject->putDirect(vm, WebCore::clientData(vm)->builtinNames().requirePublicName(), requireFunction, 0);
moduleObject->putDirect(vm, builtinNames.requirePublicName(), requireFunction, 0);
moduleObject->hasEvaluated = true;
// This will return 0 if there was a syntax error or an allocation failure
@@ -148,11 +154,11 @@ static bool evaluateCommonJSModuleOnce(JSC::VM& vm, Zig::GlobalObject* globalObj
return exception.get() == nullptr;
}
JSC_DEFINE_HOST_FUNCTION(jsFunctionLoadModule, (JSGlobalObject * lexicalGlobalObject, CallFrame* callframe))
JSC_DEFINE_HOST_FUNCTION(jsFunctionEvaluateCommonJSModule, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
{
auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
auto throwScope = DECLARE_THROW_SCOPE(globalObject->vm());
JSCommonJSModule* moduleObject = jsDynamicCast<JSCommonJSModule*>(callframe->argument(0));
JSCommonJSModule* moduleObject = jsDynamicCast<JSCommonJSModule*>(callFrame->argument(0));
if (!moduleObject) {
RELEASE_AND_RETURN(throwScope, JSValue::encode(jsBoolean(true)));
}
@@ -184,18 +190,18 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionLoadModule, (JSGlobalObject * lexicalGlobalOb
RELEASE_AND_RETURN(throwScope, JSValue::encode(jsBoolean(true)));
}
JSC_DEFINE_HOST_FUNCTION(requireResolvePathsFunction, (JSGlobalObject * globalObject, CallFrame* callframe))
JSC_DEFINE_HOST_FUNCTION(jsFunctionRequireResolvePaths, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
return JSValue::encode(JSC::constructEmptyArray(globalObject, nullptr, 0));
}
JSC_DEFINE_CUSTOM_GETTER(jsRequireCacheGetter, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
JSC_DEFINE_CUSTOM_GETTER(requireCacheGetter, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
{
Zig::GlobalObject* thisObject = jsCast<Zig::GlobalObject*>(globalObject);
return JSValue::encode(thisObject->lazyRequireCacheObject());
}
JSC_DEFINE_CUSTOM_SETTER(jsRequireCacheSetter,
JSC_DEFINE_CUSTOM_SETTER(requireCacheSetter,
(JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue,
JSC::EncodedJSValue value, JSC::PropertyName propertyName))
{
@@ -208,11 +214,11 @@ JSC_DEFINE_CUSTOM_SETTER(jsRequireCacheSetter,
}
static const HashTableValue RequireResolveFunctionPrototypeValues[] = {
{ "paths"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, requireResolvePathsFunction, 1 } },
{ "paths"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsFunctionRequireResolvePaths, 1 } },
};
static const HashTableValue RequireFunctionPrototypeValues[] = {
{ "cache"_s, static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsRequireCacheGetter, jsRequireCacheSetter } },
{ "cache"_s, static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, requireCacheGetter, requireCacheSetter } },
};
Structure* RequireFunctionPrototype::createStructure(
@@ -236,7 +242,6 @@ Structure* RequireResolveFunctionPrototype::createStructure(
RequireResolveFunctionPrototype* RequireResolveFunctionPrototype::create(JSC::JSGlobalObject* globalObject)
{
auto& vm = globalObject->vm();
auto* structure = RequireResolveFunctionPrototype::createStructure(vm, globalObject);
RequireResolveFunctionPrototype* prototype = new (NotNull, JSC::allocateCell<RequireResolveFunctionPrototype>(vm)) RequireResolveFunctionPrototype(vm, structure);
prototype->finishCreation(vm);
@@ -247,13 +252,10 @@ RequireFunctionPrototype* RequireFunctionPrototype::create(
JSC::JSGlobalObject* globalObject)
{
auto& vm = globalObject->vm();
auto* structure = RequireFunctionPrototype::createStructure(vm, globalObject);
RequireFunctionPrototype* prototype = new (NotNull, JSC::allocateCell<RequireFunctionPrototype>(vm)) RequireFunctionPrototype(vm, structure);
prototype->finishCreation(vm);
prototype->putDirect(vm, builtinNames(vm).resolvePublicName(), jsCast<Zig::GlobalObject*>(globalObject)->requireResolveFunctionUnbound(), 0);
return prototype;
}
@@ -263,26 +265,34 @@ void RequireFunctionPrototype::finishCreation(JSC::VM& vm)
ASSERT(inherits(info()));
reifyStaticProperties(vm, info(), RequireFunctionPrototypeValues, *this);
auto clientData = WebCore::clientData(vm);
auto* globalObject = reinterpret_cast<Zig::GlobalObject*>(this->globalObject());
auto builtinNames = clientData->builtinNames();
JSC::JSFunction* requireDotMainFunction = JSFunction::create(
vm,
moduleMainCodeGenerator(vm),
globalObject()->globalScope());
globalObject->globalScope());
this->putDirectAccessor(
globalObject(),
globalObject,
JSC::Identifier::fromString(vm, "main"_s),
JSC::GetterSetter::create(vm, globalObject(), requireDotMainFunction, requireDotMainFunction),
JSC::GetterSetter::create(vm, globalObject, requireDotMainFunction, requireDotMainFunction),
PropertyAttribute::Accessor | PropertyAttribute::ReadOnly | 0);
auto extensions = constructEmptyObject(globalObject());
this->putDirect(vm, builtinNames.resolvePublicName(), globalObject->requireResolveFunctionUnbound(), 0);
auto extensions = constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
extensions->putDirect(vm, JSC::Identifier::fromString(vm, ".js"_s), jsBoolean(true), 0);
extensions->putDirect(vm, JSC::Identifier::fromString(vm, ".json"_s), jsBoolean(true), 0);
extensions->putDirect(vm, JSC::Identifier::fromString(vm, ".node"_s), jsBoolean(true), 0);
extensions->putDirect(vm, builtinNames.originalStructureIDPrivateName(), jsNumber(0), 0);
extensions->putDirect(vm, builtinNames.originalStructureIDPrivateName(), jsNumber(extensions->structureID().bits()), 0);
this->putDirect(vm, JSC::Identifier::fromString(vm, "extensions"_s), extensions, 0);
}
JSC_DEFINE_CUSTOM_GETTER(getterFilename, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
JSC_DEFINE_CUSTOM_GETTER(filenameGetter, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
{
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue));
if (UNLIKELY(!thisObject)) {
@@ -290,7 +300,20 @@ JSC_DEFINE_CUSTOM_GETTER(getterFilename, (JSC::JSGlobalObject * globalObject, JS
}
return JSValue::encode(thisObject->m_filename.get());
}
JSC_DEFINE_CUSTOM_GETTER(getterId, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
JSC_DEFINE_CUSTOM_SETTER(filenameSetter,
(JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue,
JSC::EncodedJSValue value, JSC::PropertyName propertyName))
{
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue));
if (!thisObject)
return false;
thisObject->m_filename.set(globalObject->vm(), thisObject, JSValue::decode(value).toString(globalObject));
return true;
}
JSC_DEFINE_CUSTOM_GETTER(idGetter, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
{
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue));
if (UNLIKELY(!thisObject)) {
@@ -299,16 +322,42 @@ JSC_DEFINE_CUSTOM_GETTER(getterId, (JSC::JSGlobalObject * globalObject, JSC::Enc
return JSValue::encode(thisObject->m_id.get());
}
JSC_DEFINE_CUSTOM_GETTER(getterPath, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
JSC_DEFINE_CUSTOM_SETTER(idSetter,
(JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue,
JSC::EncodedJSValue value, JSC::PropertyName propertyName))
{
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue));
if (!thisObject)
return false;
thisObject->m_id.set(globalObject->vm(), thisObject, JSValue::decode(value).toString(globalObject));
return true;
}
JSC_DEFINE_CUSTOM_GETTER(loadedGetter, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
{
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue));
if (UNLIKELY(!thisObject)) {
return JSValue::encode(jsUndefined());
}
return JSValue::encode(thisObject->m_id.get());
return JSValue::encode(jsBoolean(thisObject->hasEvaluated));
}
JSC_DEFINE_CUSTOM_GETTER(getterParent, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
JSC_DEFINE_CUSTOM_SETTER(loadedSetter,
(JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue,
JSC::EncodedJSValue value, JSC::PropertyName propertyName))
{
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue));
if (!thisObject)
return false;
thisObject->hasEvaluated = JSValue::decode(value).toBoolean(globalObject);
return true;
}
JSC_DEFINE_CUSTOM_GETTER(parentGetter, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
{
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue));
if (UNLIKELY(!thisObject)) {
@@ -334,7 +383,29 @@ JSC_DEFINE_CUSTOM_GETTER(getterParent, (JSC::JSGlobalObject * globalObject, JSC:
return JSValue::encode(jsUndefined());
}
JSC_DEFINE_CUSTOM_SETTER(setterPath,
JSC_DEFINE_CUSTOM_SETTER(parentSetter,
(JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue,
JSC::EncodedJSValue value, JSC::PropertyName propertyName))
{
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue));
if (!thisObject)
return false;
thisObject->m_parent.set(globalObject->vm(), thisObject, JSValue::decode(value));
return true;
}
JSC_DEFINE_CUSTOM_GETTER(pathGetter, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
{
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue));
if (UNLIKELY(!thisObject)) {
return JSValue::encode(jsUndefined());
}
return JSValue::encode(thisObject->m_id.get());
}
JSC_DEFINE_CUSTOM_SETTER(pathSetter,
(JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue,
JSC::EncodedJSValue value, JSC::PropertyName propertyName))
{
@@ -348,7 +419,7 @@ JSC_DEFINE_CUSTOM_SETTER(setterPath,
extern "C" JSC::EncodedJSValue Resolver__propForRequireMainPaths(JSGlobalObject*);
JSC_DEFINE_CUSTOM_GETTER(getterPaths, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
JSC_DEFINE_CUSTOM_GETTER(pathsGetter, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
{
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue));
if (UNLIKELY(!thisObject)) {
@@ -363,17 +434,7 @@ JSC_DEFINE_CUSTOM_GETTER(getterPaths, (JSC::JSGlobalObject * globalObject, JSC::
return JSValue::encode(thisObject->m_paths.get());
}
JSC_DEFINE_CUSTOM_GETTER(getterLoaded, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
{
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue));
if (UNLIKELY(!thisObject)) {
return JSValue::encode(jsUndefined());
}
return JSValue::encode(jsBoolean(thisObject->hasEvaluated));
}
JSC_DEFINE_CUSTOM_SETTER(setterPaths,
JSC_DEFINE_CUSTOM_SETTER(pathsSetter,
(JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue,
JSC::EncodedJSValue value, JSC::PropertyName propertyName))
{
@@ -385,62 +446,14 @@ JSC_DEFINE_CUSTOM_SETTER(setterPaths,
return true;
}
JSC_DEFINE_CUSTOM_SETTER(setterFilename,
(JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue,
JSC::EncodedJSValue value, JSC::PropertyName propertyName))
{
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue));
if (!thisObject)
return false;
thisObject->m_filename.set(globalObject->vm(), thisObject, JSValue::decode(value).toString(globalObject));
return true;
}
JSC_DEFINE_CUSTOM_SETTER(setterId,
(JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue,
JSC::EncodedJSValue value, JSC::PropertyName propertyName))
{
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue));
if (!thisObject)
return false;
thisObject->m_id.set(globalObject->vm(), thisObject, JSValue::decode(value).toString(globalObject));
return true;
}
JSC_DEFINE_CUSTOM_SETTER(setterParent,
(JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue,
JSC::EncodedJSValue value, JSC::PropertyName propertyName))
{
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue));
if (!thisObject)
return false;
thisObject->m_parent.set(globalObject->vm(), thisObject, JSValue::decode(value));
return true;
}
JSC_DEFINE_CUSTOM_SETTER(setterLoaded,
(JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue,
JSC::EncodedJSValue value, JSC::PropertyName propertyName))
{
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue));
if (!thisObject)
return false;
thisObject->hasEvaluated = JSValue::decode(value).toBoolean(globalObject);
return true;
}
static JSValue createChildren(VM& vm, JSObject* object)
{
return constructEmptyArray(object->globalObject(), nullptr, 0);
}
JSC_DEFINE_HOST_FUNCTION(functionCommonJSModuleRecord_compile, (JSGlobalObject * globalObject, CallFrame* callframe))
JSC_DEFINE_HOST_FUNCTION(jsFunctionCommonJSModuleRecord_compile, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
auto* moduleObject = jsDynamicCast<JSCommonJSModule*>(callframe->thisValue());
auto* moduleObject = jsDynamicCast<JSCommonJSModule*>(callFrame->thisValue());
if (!moduleObject) {
return JSValue::encode(jsUndefined());
}
@@ -448,42 +461,46 @@ JSC_DEFINE_HOST_FUNCTION(functionCommonJSModuleRecord_compile, (JSGlobalObject *
auto& vm = globalObject->vm();
auto throwScope = DECLARE_THROW_SCOPE(vm);
String sourceString = callframe->argument(0).toWTFString(globalObject);
JSValue sourceValue = callFrame->argument(0);
auto sourceWTF = sourceValue.toWTFString(globalObject);
RETURN_IF_EXCEPTION(throwScope, JSValue::encode({}));
String filenameString = callframe->argument(1).toWTFString(globalObject);
JSValue filenameValue = callFrame->argument(1);
auto filenameWTF = filenameValue.toWTFString(globalObject);
RETURN_IF_EXCEPTION(throwScope, JSValue::encode({}));
auto filename = JSC::jsStringWithCache(vm, filenameWTF);
WTF::Vector<JSC::EncodedJSValue, 1> dirnameArgs;
dirnameArgs.reserveInitialCapacity(1);
dirnameArgs.unsafeAppendWithoutCapacityCheck(JSValue::encode(filenameValue));
#if OS(WINDOWS)
auto dirname = JSValue::decode(Bun__Path__dirname(globalObject, true, reinterpret_cast<JSC__JSValue*>(dirnameArgs.data()), 1)).toString(globalObject);
#else
auto dirname = JSValue::decode(Bun__Path__dirname(globalObject, false, reinterpret_cast<JSC__JSValue*>(dirnameArgs.data()), 1)).toString(globalObject);
#endif
String wrappedString = makeString(
"(function(exports,require,module,__filename,__dirname){"_s,
sourceString,
sourceWTF,
"\n})"_s);
SourceCode sourceCode = makeSource(
SourceCode sourceCode = JSC::makeSource(
WTFMove(wrappedString),
SourceOrigin(URL::fileURLWithFileSystemPath(filenameString)),
SourceOrigin(URL::fileURLWithFileSystemPath(filenameWTF)),
JSC::SourceTaintedOrigin::Untainted,
filenameString,
filenameWTF,
WTF::TextPosition(),
JSC::SourceProviderSourceType::Program);
JSSourceCode* jsSourceCode = JSSourceCode::create(vm, WTFMove(sourceCode));
moduleObject->sourceCode.set(vm, moduleObject, jsSourceCode);
auto index = filenameString.reverseFind('/', filenameString.length());
String dirnameString;
if (index != WTF::notFound) {
dirnameString = filenameString.substring(0, index);
} else {
dirnameString = "/"_s;
}
WTF::NakedPtr<JSC::Exception> exception;
evaluateCommonJSModuleOnce(
vm,
jsCast<Zig::GlobalObject*>(globalObject),
moduleObject,
jsString(vm, dirnameString),
jsString(vm, filenameString),
dirname,
filename,
exception);
if (exception) {
@@ -495,15 +512,86 @@ JSC_DEFINE_HOST_FUNCTION(functionCommonJSModuleRecord_compile, (JSGlobalObject *
return JSValue::encode(jsUndefined());
}
extern "C" JSC::EncodedJSValue jsFunctionResolveSyncPrivate(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
{
auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
auto& vm = globalObject->vm();
auto throwScope = DECLARE_THROW_SCOPE(vm);
JSValue moduleName = callFrame->argument(0);
JSValue from = callFrame->argument(1);
bool isESM = callFrame->argument(2).asBoolean();
if (moduleName.isUndefinedOrNull()) {
JSC::throwTypeError(globalObject, throwScope, "expected module name as a string"_s);
throwScope.release();
return JSValue::encode(JSValue {});
}
RETURN_IF_EXCEPTION(throwScope, JSValue::encode(JSValue {}));
if (globalObject->onLoadPlugins.hasVirtualModules()) {
if (moduleName.isString()) {
auto moduleStr = moduleName.toWTFString(globalObject);
auto resolvedString = globalObject->onLoadPlugins.resolveVirtualModule(moduleStr, from.toWTFString(globalObject));
if (resolvedString) {
if (moduleStr == resolvedString.value())
return JSValue::encode(moduleName);
return JSValue::encode(jsString(vm, resolvedString.value()));
}
}
}
if (!isESM) {
auto overrideHandler = globalObject->m_nodeModuleOverriddenResolveFilename.get();
if (UNLIKELY(overrideHandler)) {
ASSERT(overrideHandler->isCallable());
auto requireMap = globalObject->requireMap();
auto* parentModuleObject = jsDynamicCast<Bun::JSCommonJSModule*>(requireMap->get(globalObject, from));
JSValue parentID = jsUndefined();
if (parentModuleObject) {
parentID = parentModuleObject->id();
} else {
parentID = from;
}
auto parentIdStr = parentID.toWTFString(globalObject);
auto bunStr = Bun::toString(parentIdStr);
MarkedArgumentBuffer args;
args.append(moduleName);
args.append(parentModuleObject);
args.append(jsBoolean(Bun__isBunMain(globalObject, &bunStr)));
// `Module` will be cached because requesting it is the only way to access `Module._resolveFilename`.
auto* ModuleModuleObject = jsCast<Bun::JSCommonJSModule*>(requireMap->get(globalObject, JSC::jsStringWithCache(vm, "module"_s)));
auto ModuleExportsObject = ModuleModuleObject->exportsObject();
return JSValue::encode(JSC::call(globalObject, overrideHandler, JSC::getCallData(overrideHandler), ModuleExportsObject, args));
}
}
auto result = Bun__resolveSync(globalObject, JSValue::encode(moduleName), JSValue::encode(from), isESM);
if (!JSValue::decode(result).isString()) {
JSC::throwException(globalObject, throwScope, JSValue::decode(result));
return JSValue::encode(JSValue {});
}
throwScope.release();
return result;
}
static const struct HashTableValue JSCommonJSModulePrototypeTableValues[] = {
{ "_compile"_s, static_cast<unsigned>(PropertyAttribute::Function | PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::NativeFunctionType, functionCommonJSModuleRecord_compile, 2 } },
{ "_compile"_s, static_cast<unsigned>(PropertyAttribute::Function | PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::NativeFunctionType, jsFunctionCommonJSModuleRecord_compile, 2 } },
{ "children"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, createChildren } },
{ "filename"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterFilename, setterFilename } },
{ "id"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterId, setterId } },
{ "loaded"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterLoaded, setterLoaded } },
{ "parent"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor | PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, getterParent, setterParent } },
{ "path"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterPath, setterPath } },
{ "paths"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterPaths, setterPaths } },
{ "filename"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, filenameGetter, filenameSetter } },
{ "id"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, idGetter, idSetter } },
{ "loaded"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, loadedGetter, loadedSetter } },
{ "parent"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor | PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::GetterSetterType, parentGetter, parentSetter } },
{ "path"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, pathGetter, pathSetter } },
{ "paths"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, pathsGetter, pathsSetter } },
};
class JSCommonJSModulePrototype final : public JSC::JSNonFinalObject {
@@ -522,7 +610,7 @@ public:
static JSC::Structure* createStructure(
JSC::VM& vm,
JSC::JSGlobalObject* globalObject,
JSC::JSValue prototype)
JSValue prototype)
{
auto* structure = JSC::Structure::create(vm, globalObject, prototype, TypeInfo(JSC::ObjectType, StructureFlags), info());
structure->setMayBePrototype(true);
@@ -556,7 +644,7 @@ public:
globalObject,
clientData(vm)->builtinNames().requirePrivateName(),
2,
jsFunctionRequireCommonJS, ImplementationVisibility::Public, NoIntrinsic, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete);
jsFunctionRequirePrivate, ImplementationVisibility::Public, NoIntrinsic, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete);
}
};
@@ -577,7 +665,6 @@ JSC::Structure* JSCommonJSModule::createStructure(
JSC::JSGlobalObject* globalObject)
{
auto& vm = globalObject->vm();
auto* prototype = JSCommonJSModulePrototype::create(vm, globalObject, JSCommonJSModulePrototype::createStructure(vm, globalObject, globalObject->objectPrototype()));
// Do not set the number of inline properties on this structure
@@ -598,39 +685,41 @@ JSCommonJSModule* JSCommonJSModule::create(
return cell;
}
JSC_DEFINE_HOST_FUNCTION(jsFunctionCreateCommonJSModule, (JSGlobalObject * globalObject, CallFrame* callframe))
JSC_DEFINE_HOST_FUNCTION(jsFunctionCreateCommonJSModule, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
auto& vm = globalObject->vm();
RELEASE_ASSERT(callframe->argumentCount() == 4);
RELEASE_ASSERT(callFrame->argumentCount() == 4);
auto id = callframe->uncheckedArgument(0).toWTFString(globalObject);
JSValue object = callframe->uncheckedArgument(1);
JSValue hasEvaluated = callframe->uncheckedArgument(2);
auto id = callFrame->uncheckedArgument(0).toString(globalObject);
JSValue object = callFrame->uncheckedArgument(1);
JSValue hasEvaluated = callFrame->uncheckedArgument(2);
ASSERT(hasEvaluated.isBoolean());
JSValue parent = callframe->uncheckedArgument(3);
JSValue parent = callFrame->uncheckedArgument(3);
return JSValue::encode(JSCommonJSModule::create(jsCast<Zig::GlobalObject*>(globalObject), id, object, hasEvaluated.isTrue(), parent));
}
JSCommonJSModule* JSCommonJSModule::create(
Zig::GlobalObject* globalObject,
const WTF::String& key,
JSC::JSString* id,
JSValue exportsObject,
bool hasEvaluated,
JSValue parent)
{
auto& vm = globalObject->vm();
JSString* requireMapKey = JSC::jsStringWithCache(vm, key);
auto index = key.reverseFind('/', key.length());
JSString* dirname = jsEmptyString(vm);
if (index != WTF::notFound) {
dirname = JSC::jsSubstring(globalObject, requireMapKey, 0, index);
}
WTF::Vector<JSC::EncodedJSValue, 1> dirnameArgs;
dirnameArgs.reserveInitialCapacity(1);
dirnameArgs.unsafeAppendWithoutCapacityCheck(JSValue::encode(id));
#if OS(WINDOWS)
auto dirname = JSValue::decode(Bun__Path__dirname(globalObject, true, reinterpret_cast<JSC__JSValue*>(dirnameArgs.data()), 1)).toString(globalObject);
#else
auto dirname = JSValue::decode(Bun__Path__dirname(globalObject, false, reinterpret_cast<JSC__JSValue*>(dirnameArgs.data()), 1)).toString(globalObject);
#endif
auto* out = JSCommonJSModule::create(
vm,
globalObject->CommonJSModuleObjectStructure(),
requireMapKey, requireMapKey, dirname, nullptr);
id, id, dirname, nullptr);
out->putDirect(
vm,
@@ -837,8 +926,6 @@ void JSCommonJSModule::toSyntheticSource(JSC::JSGlobalObject* globalObject,
JSC::MarkedArgumentBuffer& exportValues)
{
auto result = this->exportsObject();
auto& vm = globalObject->vm();
populateESMExports(globalObject, result, exportNames, exportValues, this->ignoreESModuleAnnotation);
}
@@ -890,23 +977,82 @@ const JSC::ClassInfo JSCommonJSModule::s_info = { "Module"_s, &Base::s_info, nul
const JSC::ClassInfo RequireResolveFunctionPrototype::s_info = { "resolve"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(RequireResolveFunctionPrototype) };
const JSC::ClassInfo RequireFunctionPrototype::s_info = { "require"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(RequireFunctionPrototype) };
JSC_DEFINE_HOST_FUNCTION(jsFunctionRequireCommonJS, (JSGlobalObject * lexicalGlobalObject, CallFrame* callframe))
JSC_DEFINE_HOST_FUNCTION(jsFunctionRequirePrivate, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
{
auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
auto& vm = globalObject->vm();
auto throwScope = DECLARE_THROW_SCOPE(vm);
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(callframe->thisValue());
if (!thisObject)
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(callFrame->thisValue());
if (!thisObject) {
return throwVMTypeError(globalObject, throwScope);
}
JSValue specifierValue = callframe->argument(0);
WTF::String specifier = specifierValue.toWTFString(globalObject);
RETURN_IF_EXCEPTION(throwScope, {});
JSValue specifierValue = callFrame->argument(0);
auto specifier = specifierValue.toWTFString(globalObject);
auto* moduleObject = jsCast<JSCommonJSModule*>(callFrame->argument(1));
auto requireUnbound = globalObject->requireFunctionUnbound();
auto requireUnboundPrototype = requireUnbound->getPrototype(vm, globalObject);
if (requireUnboundPrototype.isObject()) {
JSObject* prototype = requireUnboundPrototype.getObject();
auto extensionsValue = prototype->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "extensions"_s));
if (extensionsValue.isObject()) {
auto clientData = WebCore::clientData(vm);
auto builtinNames = clientData->builtinNames();
JSObject* extensionsObject = extensionsValue.getObject();
bool structureChanged = extensionsObject->getDirect(vm, builtinNames.originalStructureIDPrivateName()) != jsNumber(extensionsObject->structureID().bits());
if (UNLIKELY(structureChanged)) {
WTF::Vector<JSC::EncodedJSValue, 1> basenameArgs;
basenameArgs.reserveInitialCapacity(1);
basenameArgs.unsafeAppendWithoutCapacityCheck(JSC::JSValue::encode(specifierValue));
#if OS(WINDOWS)
auto basename = JSValue::decode(Bun__Path__basename(globalObject, true, reinterpret_cast<JSC__JSValue*>(basenameArgs.data()), 1)).toWTFString(globalObject);
#else
auto basename = JSValue::decode(Bun__Path__basename(globalObject, false, reinterpret_cast<JSC__JSValue*>(basenameArgs.data()), 1)).toWTFString(globalObject);
#endif
size_t index = 0;
uint16_t startIndex = 0;
JSFunction* extHandler = nullptr;
// Find longest registered extension.
while ((index = basename.find("."_s, startIndex)) != WTF::notFound) {
if (index == 0) {
// Skip dotfiles like .gitignore
continue;
}
auto extStr = basename.substring(index);
auto extValue = extensionsObject->get(globalObject, JSC::Identifier::fromString(vm, extStr));
if (UNLIKELY(extValue.isCallable())) {
extHandler = jsCast<JSFunction*>(extValue);
break;
}
startIndex = index + 1;
}
// Fallback to ".js".
if (LIKELY(!extHandler)) {
auto extValue = extensionsObject->get(globalObject, JSC::Identifier::fromString(vm, ".js"_s));
if (UNLIKELY(extValue.isCallable())) {
extHandler = jsCast<JSFunction*>(extValue);
}
}
if (UNLIKELY(extHandler)) {
JSC::CallData callData = JSC::getCallData(extHandler);
MarkedArgumentBuffer args;
args.append(moduleObject); // module
args.append(specifierValue); // id
// Call Module._extensions[ext](module, id)
JSC::call(globalObject, extHandler, callData, extensionsObject, args);
return JSValue::encode(moduleObject->exportsObject());
}
}
}
}
// Special-case for "process" to just return the process object directly.
if (UNLIKELY(specifier == "process"_s || specifier == "node:process"_s)) {
jsCast<JSCommonJSModule*>(callframe->argument(1))->putDirect(vm, builtinNames(vm).exportsPublicName(), globalObject->processObject(), 0);
moduleObject->putDirect(vm, Bun::builtinNames(vm).exportsPublicName(), globalObject->processObject(), 0);
return JSValue::encode(globalObject->processObject());
}
@@ -918,17 +1064,16 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionRequireCommonJS, (JSGlobalObject * lexicalGlo
BunString typeAttributeStr = { BunStringTag::Dead };
String typeAttribute = String();
// We need to be able to wire in the "type" import attribute from bundled code..
// so we do it via CommonJS require().
int32_t previousArgumentCount = callframe->argument(2).asInt32();
int32_t previousArgumentCount = callFrame->argument(2).asInt32();
// If they called require(id), skip the check for the type attribute
if (UNLIKELY(previousArgumentCount == 2)) {
JSValue val = callframe->argument(3);
if (val.isObject()) {
JSObject* obj = val.getObject();
JSValue attrValue = callFrame->argument(3);
if (attrValue.isObject()) {
JSObject* attrObject = attrValue.getObject();
// This getter is expensive and rare.
if (auto typeValue = obj->getIfPropertyExists(globalObject, vm.propertyNames->type)) {
if (auto typeValue = attrObject->getIfPropertyExists(globalObject, vm.propertyNames->type)) {
if (typeValue.isString()) {
typeAttribute = typeValue.toWTFString(globalObject);
RETURN_IF_EXCEPTION(throwScope, {});
@@ -941,7 +1086,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionRequireCommonJS, (JSGlobalObject * lexicalGlo
JSValue fetchResult = Bun::fetchCommonJSModule(
globalObject,
jsCast<JSCommonJSModule*>(callframe->argument(1)),
moduleObject,
specifierValue,
&specifierStr,
&referrerStr,
@@ -967,15 +1112,16 @@ bool JSCommonJSModule::evaluate(
ResolvedSource source,
bool isBuiltIn)
{
auto& vm = globalObject->vm();
auto sourceProvider = Zig::SourceProvider::create(jsCast<Zig::GlobalObject*>(globalObject), source, JSC::SourceProviderSourceType::Program, isBuiltIn);
this->ignoreESModuleAnnotation = source.tag == ResolvedSourceTagPackageJSONTypeModule;
JSC::SourceCode rawInputSource(
WTFMove(sourceProvider));
if (this->hasEvaluated)
if (this->hasEvaluated) {
return true;
}
auto& vm = globalObject->vm();
this->sourceCode.set(vm, this, JSC::JSSourceCode::create(vm, WTFMove(rawInputSource)));
WTF::NakedPtr<JSC::Exception> exception;
@@ -1003,10 +1149,10 @@ std::optional<JSC::SourceCode> createCommonJSModule(
bool isBuiltIn)
{
JSCommonJSModule* moduleObject = nullptr;
WTF::String sourceURL = source.source_url.toWTFString();
JSValue specifierValue = Bun::toJS(globalObject, source.specifier);
JSValue entry = globalObject->requireMap()->get(globalObject, specifierValue);
auto sourceURL = source.source_url.toWTFString();
auto sourceURLValue = Bun::toJS(globalObject, source.source_url);
auto specifierValue = Bun::toJS(globalObject, source.specifier);
auto entry = globalObject->requireMap()->get(globalObject, specifierValue);
auto sourceProvider = Zig::SourceProvider::create(jsCast<Zig::GlobalObject*>(globalObject), source, JSC::SourceProviderSourceType::Program, isBuiltIn);
bool ignoreESModuleAnnotation = source.tag == ResolvedSourceTagPackageJSONTypeModule;
@@ -1018,24 +1164,25 @@ std::optional<JSC::SourceCode> createCommonJSModule(
if (!moduleObject) {
auto& vm = globalObject->vm();
auto* requireMapKey = jsStringWithCache(vm, sourceURL);
auto index = sourceURL.reverseFind('/', sourceURL.length());
JSString* dirname = jsEmptyString(vm);
JSString* filename = requireMapKey;
if (index != WTF::notFound) {
dirname = JSC::jsSubstring(globalObject, requireMapKey, 0, index);
}
auto* id = JSC::jsStringWithCache(vm, sourceURL);
WTF::Vector<JSC::EncodedJSValue, 1> dirnameArgs;
dirnameArgs.reserveInitialCapacity(1);
dirnameArgs.unsafeAppendWithoutCapacityCheck(JSValue::encode(specifierValue));
#if OS(WINDOWS)
auto dirname = JSValue::decode(Bun__Path__dirname(globalObject, true, reinterpret_cast<JSC__JSValue*>(dirnameArgs.data()), 1)).toString(globalObject);
#else
auto dirname = JSValue::decode(Bun__Path__dirname(globalObject, false, reinterpret_cast<JSC__JSValue*>(dirnameArgs.data()), 1)).toString(globalObject);
#endif
moduleObject = JSCommonJSModule::create(
vm,
globalObject->CommonJSModuleObjectStructure(),
requireMapKey, filename, dirname, JSC::JSSourceCode::create(vm, SourceCode(WTFMove(sourceProvider))));
id, id, dirname, JSC::JSSourceCode::create(vm, SourceCode(WTFMove(sourceProvider))));
moduleObject->putDirect(vm,
WebCore::clientData(vm)->builtinNames().exportsPublicName(),
JSC::constructEmptyObject(globalObject, globalObject->objectPrototype()), 0);
globalObject->requireMap()->set(globalObject, requireMapKey, moduleObject);
globalObject->requireMap()->set(globalObject, id, moduleObject);
}
moduleObject->ignoreESModuleAnnotation = ignoreESModuleAnnotation;
@@ -1067,8 +1214,8 @@ std::optional<JSC::SourceCode> createCommonJSModule(
// so that it can be re-evaluated on the next require.
globalObject->requireMap()->remove(globalObject, moduleObject->id());
auto scope = DECLARE_THROW_SCOPE(vm);
throwException(globalObject, scope, exception.get());
auto throwScope = DECLARE_THROW_SCOPE(vm);
throwException(globalObject, throwScope, exception.get());
exception.clear();
return;
}
@@ -1082,19 +1229,19 @@ std::optional<JSC::SourceCode> createCommonJSModule(
sourceURL));
}
JSObject* JSCommonJSModule::createBoundRequireFunction(VM& vm, JSGlobalObject* lexicalGlobalObject, const WTF::String& pathString)
JSObject* JSCommonJSModule::createBoundRequireFunction(VM& vm, JSGlobalObject* lexicalGlobalObject, JSC::JSString* filename)
{
ASSERT(!pathString.startsWith("file://"_s));
ASSERT(!filename->tryGetValue().startsWith("file://"_s));
auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
JSString* filename = JSC::jsStringWithCache(vm, pathString);
auto index = pathString.reverseFind('/', pathString.length());
JSString* dirname = jsEmptyString(vm);
if (index != WTF::notFound) {
dirname = JSC::jsSubstring(globalObject, filename, 0, index);
}
WTF::Vector<JSC::EncodedJSValue, 1> dirnameArgs;
dirnameArgs.reserveInitialCapacity(1);
dirnameArgs.unsafeAppendWithoutCapacityCheck(JSValue::encode(filename));
#if OS(WINDOWS)
auto dirname = JSValue::decode(Bun__Path__dirname(globalObject, true, reinterpret_cast<JSC__JSValue*>(dirnameArgs.data()), 1)).toString(globalObject);
#else
auto dirname = JSValue::decode(Bun__Path__dirname(globalObject, false, reinterpret_cast<JSC__JSValue*>(dirnameArgs.data()), 1)).toString(globalObject);
#endif
auto moduleObject = Bun::JSCommonJSModule::create(
vm,
globalObject->CommonJSModuleObjectStructure(),

View File

@@ -2,6 +2,8 @@
#include "root.h"
#include "headers-handwritten.h"
extern "C" JSC_DECLARE_HOST_FUNCTION(jsFunctionResolveSyncPrivate);
namespace Zig {
class GlobalObject;
}
@@ -15,7 +17,7 @@ class AbstractModuleRecord;
namespace Bun {
JSC_DECLARE_HOST_FUNCTION(jsFunctionCreateCommonJSModule);
JSC_DECLARE_HOST_FUNCTION(jsFunctionLoadModule);
JSC_DECLARE_HOST_FUNCTION(jsFunctionEvaluateCommonJSModule);
void populateESMExports(
JSC::JSGlobalObject* globalObject,
@@ -61,15 +63,15 @@ public:
static JSCommonJSModule* create(
Zig::GlobalObject* globalObject,
const WTF::String& key,
JSC::JSString* id,
JSValue exportsObject, bool hasEvaluated, JSValue parent);
static JSCommonJSModule* create(
Zig::GlobalObject* globalObject,
const WTF::String& key,
JSC::JSString* id,
ResolvedSource resolvedSource);
static JSObject* createBoundRequireFunction(VM& vm, JSGlobalObject* lexicalGlobalObject, const WTF::String& pathString);
static JSObject* createBoundRequireFunction(VM& vm, JSGlobalObject* lexicalGlobalObject, JSC::JSString* filename);
void toSyntheticSource(JSC::JSGlobalObject* globalObject,
JSC::Identifier moduleKey,
@@ -82,7 +84,6 @@ public:
DECLARE_INFO;
DECLARE_VISIT_CHILDREN;
static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
template<typename, SubspaceAccess mode>
@@ -106,12 +107,6 @@ public:
}
};
JSCommonJSModule* createCommonJSModuleWithoutRunning(
Zig::GlobalObject* globalObject,
Ref<Zig::SourceProvider> sourceProvider,
const WTF::String& sourceURL,
ResolvedSource source);
JSC::Structure* createCommonJSModuleStructure(
Zig::GlobalObject* globalObject);

View File

@@ -87,84 +87,12 @@ ALWAYS_INLINE bool isAbsolutePath(WTF::String input)
#endif
}
extern "C" JSC__JSValue Bun__Path__dirname(JSC__JSGlobalObject* arg0, bool arg1, JSC__JSValue* arg2, uint16_t arg3);
namespace Zig {
using namespace JSC;
using namespace WebCore;
static JSC::EncodedJSValue functionRequireResolve(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame, const WTF::String& fromStr)
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
switch (callFrame->argumentCount()) {
case 0: {
// not "requires" because "require" could be confusing
JSC::throwTypeError(globalObject, scope, "require.resolve needs 1 argument (a string)"_s);
scope.release();
return JSC::JSValue::encode(JSC::JSValue {});
}
default: {
JSValue thisValue = callFrame->thisValue();
JSC::JSValue moduleName = callFrame->argument(0);
auto doIt = [&](const WTF::String& fromStr) -> JSC::EncodedJSValue {
Zig::GlobalObject* zigGlobalObject = jsCast<Zig::GlobalObject*>(globalObject);
if (zigGlobalObject->onLoadPlugins.hasVirtualModules()) {
if (auto result = zigGlobalObject->onLoadPlugins.resolveVirtualModule(fromStr, String())) {
if (fromStr == result.value())
return JSC::JSValue::encode(moduleName);
return JSC::JSValue::encode(jsString(vm, result.value()));
}
}
BunString from = Bun::toString(fromStr);
auto result = Bun__resolveSyncWithSource(globalObject, JSC::JSValue::encode(moduleName), &from, false);
if (!JSC::JSValue::decode(result).isString()) {
JSC::throwException(globalObject, scope, JSC::JSValue::decode(result));
return JSC::JSValue::encode(JSValue {});
}
scope.release();
return result;
};
if (moduleName.isUndefinedOrNull()) {
JSC::throwTypeError(globalObject, scope, "require.resolve expects a string"_s);
scope.release();
return JSC::JSValue::encode(JSC::JSValue {});
}
if (callFrame->argumentCount() > 1) {
JSC::JSValue fromValue = callFrame->argument(1);
// require.resolve also supports a paths array
// we only support a single path
if (!fromValue.isUndefinedOrNull() && fromValue.isObject()) {
if (auto pathsObject = fromValue.getObject()->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "paths"_s))) {
if (pathsObject.isCell() && pathsObject.asCell()->type() == JSC::JSType::ArrayType) {
auto pathsArray = JSC::jsCast<JSC::JSArray*>(pathsObject);
if (pathsArray->length() > 0) {
fromValue = pathsArray->getIndex(globalObject, 0);
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {}));
}
}
}
}
if (fromValue.isString()) {
WTF::String str = fromValue.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {}));
return doIt(str);
}
}
return doIt(fromStr);
}
}
}
Zig::ImportMetaObject* Zig::ImportMetaObject::create(JSC::JSGlobalObject* globalObject, JSValue key)
{
if (WebCore::DOMURL* domURL = WebCoreCast<WebCore::JSDOMURL, WebCore__DOMURL>(JSValue::encode(key))) {
@@ -183,33 +111,20 @@ Zig::ImportMetaObject* Zig::ImportMetaObject::create(JSC::JSGlobalObject* global
return create(globalObject, keyString);
}
JSC_DECLARE_HOST_FUNCTION(jsFunctionRequireResolve);
JSC_DEFINE_HOST_FUNCTION(jsFunctionRequireResolve, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
JSValue thisValue = callFrame->thisValue();
WTF::String fromStr;
if (thisValue.isString()) {
fromStr = thisValue.toWTFString(globalObject);
}
return functionRequireResolve(globalObject, callFrame, fromStr);
}
extern "C" JSC::EncodedJSValue functionImportMeta__resolveSync(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
JSC_DEFINE_HOST_FUNCTION(jsFunctionImportMeta_resolveSync, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
{
auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
auto throwScope = DECLARE_THROW_SCOPE(globalObject->vm());
JSValue thisValue = callFrame->thisValue();
JSC::JSValue moduleName = callFrame->argument(0);
JSC::JSValue fromValue = callFrame->argument(1);
JSValue moduleName = callFrame->argument(0);
JSValue fromValue = callFrame->argument(1);
if (moduleName.isUndefinedOrNull()) {
JSC::throwTypeError(globalObject, scope, "expects a string"_s);
scope.release();
return JSC::JSValue::encode(JSC::JSValue {});
JSC::throwTypeError(globalObject, throwScope, "expects a string"_s);
throwScope.release();
return JSValue::encode(JSValue {});
}
JSC__JSValue from;
@@ -218,52 +133,53 @@ extern "C" JSC::EncodedJSValue functionImportMeta__resolveSync(JSC::JSGlobalObje
if (callFrame->argumentCount() > 1) {
if (callFrame->argumentCount() > 2) {
JSC::JSValue isESMValue = callFrame->argument(2);
JSValue isESMValue = callFrame->argument(2);
if (isESMValue.isBoolean()) {
isESM = isESMValue.toBoolean(globalObject);
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {}));
RETURN_IF_EXCEPTION(throwScope, JSValue::encode(JSValue {}));
}
}
if (!fromValue.isUndefinedOrNull() && fromValue.isObject()) {
if (auto pathsObject = fromValue.getObject()->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "paths"_s))) {
if (pathsObject.isCell() && pathsObject.asCell()->type() == JSC::JSType::ArrayType) {
auto pathsArray = JSC::jsCast<JSC::JSArray*>(pathsObject);
if (pathsArray->length() > 0) {
fromValue = pathsArray->getIndex(globalObject, 0);
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {}));
RETURN_IF_EXCEPTION(throwScope, JSValue::encode(JSValue {}));
}
}
}
} else if (fromValue.isBoolean()) {
isESM = fromValue.toBoolean(globalObject);
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {}));
RETURN_IF_EXCEPTION(throwScope, JSValue::encode(JSValue {}));
fromValue = JSC::jsUndefined();
}
if (fromValue.isString()) {
from = JSC::JSValue::encode(fromValue);
from = JSValue::encode(fromValue);
} else if (thisValue.isString()) {
from = JSC::JSValue::encode(thisValue);
from = JSValue::encode(thisValue);
}
} else if (thisValue.isString()) {
from = JSC::JSValue::encode(thisValue);
from = JSValue::encode(thisValue);
} else {
JSC::JSObject* thisObject = JSC::jsDynamicCast<JSC::JSObject*>(thisValue);
if (UNLIKELY(!thisObject)) {
auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
JSC::throwTypeError(globalObject, scope, "import.meta.resolveSync must be bound to an import.meta object"_s);
return JSC::JSValue::encode(JSC::JSValue {});
auto throwScope = DECLARE_THROW_SCOPE(globalObject->vm());
JSC::throwTypeError(globalObject, throwScope, "import.meta.resolveSync must be bound to an import.meta object"_s);
return JSValue::encode(JSValue {});
}
auto clientData = WebCore::clientData(vm);
JSValue pathProperty = thisObject->getIfPropertyExists(globalObject, clientData->builtinNames().pathPublicName());
auto builtinNames = clientData->builtinNames();
JSValue pathProperty = thisObject->getIfPropertyExists(globalObject, builtinNames.pathPublicName());
if (pathProperty && pathProperty.isString())
from = JSC::JSValue::encode(pathProperty);
from = JSValue::encode(pathProperty);
}
if (globalObject->onLoadPlugins.hasVirtualModules()) {
@@ -271,131 +187,64 @@ extern "C" JSC::EncodedJSValue functionImportMeta__resolveSync(JSC::JSGlobalObje
auto moduleString = moduleName.toWTFString(globalObject);
if (auto resolvedString = globalObject->onLoadPlugins.resolveVirtualModule(moduleString, JSValue::decode(from).toWTFString(globalObject))) {
if (moduleString == resolvedString.value())
return JSC::JSValue::encode(moduleName);
return JSC::JSValue::encode(jsString(vm, resolvedString.value()));
return JSValue::encode(moduleName);
return JSValue::encode(jsString(vm, resolvedString.value()));
}
}
}
auto result = Bun__resolveSync(globalObject, JSC::JSValue::encode(moduleName), from, isESM);
auto result = Bun__resolveSync(globalObject, JSValue::encode(moduleName), from, isESM);
if (!JSC::JSValue::decode(result).isString()) {
JSC::throwException(globalObject, scope, JSC::JSValue::decode(result));
return JSC::JSValue::encode(JSC::JSValue {});
if (!JSValue::decode(result).isString()) {
JSC::throwException(globalObject, throwScope, JSValue::decode(result));
return JSValue::encode(JSValue {});
}
scope.release();
throwScope.release();
return result;
}
extern "C" bool Bun__isBunMain(JSC::JSGlobalObject* global, const BunString*);
extern "C" JSC::EncodedJSValue functionImportMeta__resolveSyncPrivate(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
{
JSC::VM& vm = lexicalGlobalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* globalObject = jsDynamicCast<Zig::GlobalObject*>(lexicalGlobalObject);
JSC::JSValue moduleName = callFrame->argument(0);
JSValue from = callFrame->argument(1);
bool isESM = callFrame->argument(2).asBoolean();
if (moduleName.isUndefinedOrNull()) {
JSC::throwTypeError(lexicalGlobalObject, scope, "expected module name as a string"_s);
scope.release();
return JSC::JSValue::encode(JSC::JSValue {});
}
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {}));
if (globalObject->onLoadPlugins.hasVirtualModules()) {
if (moduleName.isString()) {
auto moduleString = moduleName.toWTFString(globalObject);
if (auto resolvedString = globalObject->onLoadPlugins.resolveVirtualModule(moduleString, from.toWTFString(globalObject))) {
if (moduleString == resolvedString.value())
return JSC::JSValue::encode(moduleName);
return JSC::JSValue::encode(jsString(vm, resolvedString.value()));
}
}
}
if (!isESM) {
if (LIKELY(globalObject)) {
auto overrideHandler = globalObject->m_nodeModuleOverriddenResolveFilename.get();
if (UNLIKELY(overrideHandler)) {
ASSERT(overrideHandler->isCallable());
JSValue parentModuleObject = globalObject->requireMap()->get(globalObject, from);
JSValue parentID = jsUndefined();
if (auto* parent = jsDynamicCast<Bun::JSCommonJSModule*>(parentModuleObject)) {
parentID = parent->id();
} else {
parentID = from;
}
MarkedArgumentBuffer args;
args.append(moduleName);
args.append(parentModuleObject);
auto parentIdStr = parentID.toWTFString(globalObject);
auto bunStr = Bun::toString(parentIdStr);
args.append(jsBoolean(Bun__isBunMain(lexicalGlobalObject, &bunStr)));
return JSValue::encode(JSC::call(lexicalGlobalObject, overrideHandler, JSC::getCallData(overrideHandler), parentModuleObject, args));
}
}
}
auto result = Bun__resolveSync(lexicalGlobalObject, JSC::JSValue::encode(moduleName), JSValue::encode(from), isESM);
if (!JSC::JSValue::decode(result).isString()) {
JSC::throwException(lexicalGlobalObject, scope, JSC::JSValue::decode(result));
return JSC::JSValue::encode(JSC::JSValue {});
}
scope.release();
return result;
}
JSC_DEFINE_HOST_FUNCTION(functionImportMeta__resolve,
JSC_DEFINE_HOST_FUNCTION(jsFunctionImportMeta_resolve,
(JSC::JSGlobalObject * lexicalGlobalObject, JSC::CallFrame* callFrame))
{
auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
auto throwScope = DECLARE_THROW_SCOPE(globalObject->vm());
switch (callFrame->argumentCount()) {
case 0: {
// not "requires" because "require" could be confusing
JSC::throwTypeError(globalObject, scope, "import.meta.resolve needs 1 argument (a string)"_s);
scope.release();
return JSC::JSValue::encode(JSC::JSValue {});
JSC::throwTypeError(globalObject, throwScope, "import.meta.resolve needs 1 argument (a string)"_s);
throwScope.release();
return JSValue::encode(JSValue {});
}
default: {
JSC::JSValue moduleName = callFrame->argument(0);
JSValue moduleName = callFrame->argument(0);
if (moduleName.isUndefinedOrNull()) {
auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
JSC::throwTypeError(globalObject, scope, "import.meta.resolve expects a string"_s);
scope.release();
return JSC::JSValue::encode(JSC::JSValue {});
auto throwScope = DECLARE_THROW_SCOPE(globalObject->vm());
JSC::throwTypeError(globalObject, throwScope, "import.meta.resolve expects a string"_s);
throwScope.release();
return JSValue::encode(JSValue {});
}
JSC__JSValue from;
if (callFrame->argumentCount() > 1 && callFrame->argument(1).isString()) {
from = JSC::JSValue::encode(callFrame->argument(1));
from = JSValue::encode(callFrame->argument(1));
} else {
JSC::JSObject* thisObject = JSC::jsDynamicCast<JSC::JSObject*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
JSC::throwTypeError(globalObject, scope, "import.meta.resolve must be bound to an import.meta object"_s);
return JSC::JSValue::encode(JSC::JSValue {});
auto throwScope = DECLARE_THROW_SCOPE(globalObject->vm());
JSC::throwTypeError(globalObject, throwScope, "import.meta.resolve must be bound to an import.meta object"_s);
return JSValue::encode(JSValue {});
}
auto clientData = WebCore::clientData(vm);
auto builtinNames = clientData->builtinNames();
from = JSC::JSValue::encode(thisObject->getIfPropertyExists(globalObject, clientData->builtinNames().pathPublicName()));
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {}));
from = JSValue::encode(thisObject->getIfPropertyExists(globalObject, builtinNames.pathPublicName()));
RETURN_IF_EXCEPTION(throwScope, JSValue::encode(JSValue {}));
}
if (globalObject->onLoadPlugins.hasVirtualModules()) {
@@ -403,13 +252,13 @@ JSC_DEFINE_HOST_FUNCTION(functionImportMeta__resolve,
auto moduleString = moduleName.toWTFString(globalObject);
if (auto resolvedString = globalObject->onLoadPlugins.resolveVirtualModule(moduleString, JSValue::decode(from).toWTFString(globalObject))) {
if (moduleString == resolvedString.value())
return JSC::JSValue::encode(JSPromise::resolvedPromise(globalObject, moduleName));
return JSC::JSValue::encode(JSPromise::resolvedPromise(globalObject, jsString(vm, resolvedString.value())));
return JSValue::encode(JSPromise::resolvedPromise(globalObject, moduleName));
return JSValue::encode(JSPromise::resolvedPromise(globalObject, jsString(vm, resolvedString.value())));
}
}
}
return Bun__resolve(globalObject, JSC::JSValue::encode(moduleName), from, true);
return Bun__resolve(globalObject, JSValue::encode(moduleName), from, true);
}
}
}
@@ -429,6 +278,7 @@ Zig::ImportMetaObject* ImportMetaObject::create(JSC::VM& vm, JSC::JSGlobalObject
ptr->finishCreation(vm);
return ptr;
}
Zig::ImportMetaObject* ImportMetaObject::create(JSC::JSGlobalObject* jslobalObject, JSC::JSString* keyString)
{
auto* globalObject = jsCast<Zig::GlobalObject*>(jslobalObject);
@@ -446,6 +296,7 @@ JSC_DEFINE_CUSTOM_GETTER(jsImportMetaObjectGetter_url, (JSGlobalObject * globalO
return JSValue::encode(thisObject->urlProperty.getInitializedOnMainThread(thisObject));
}
JSC_DEFINE_CUSTOM_GETTER(jsImportMetaObjectGetter_dir, (JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, PropertyName propertyName))
{
ImportMetaObject* thisObject = jsDynamicCast<ImportMetaObject*>(JSValue::decode(thisValue));
@@ -454,6 +305,7 @@ JSC_DEFINE_CUSTOM_GETTER(jsImportMetaObjectGetter_dir, (JSGlobalObject * globalO
return JSValue::encode(thisObject->dirProperty.getInitializedOnMainThread(thisObject));
}
JSC_DEFINE_CUSTOM_GETTER(jsImportMetaObjectGetter_file, (JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, PropertyName propertyName))
{
ImportMetaObject* thisObject = jsDynamicCast<ImportMetaObject*>(JSValue::decode(thisValue));
@@ -462,6 +314,7 @@ JSC_DEFINE_CUSTOM_GETTER(jsImportMetaObjectGetter_file, (JSGlobalObject * global
return JSValue::encode(thisObject->fileProperty.getInitializedOnMainThread(thisObject));
}
JSC_DEFINE_CUSTOM_GETTER(jsImportMetaObjectGetter_path, (JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, PropertyName propertyName))
{
ImportMetaObject* thisObject = jsDynamicCast<ImportMetaObject*>(JSValue::decode(thisValue));
@@ -470,6 +323,7 @@ JSC_DEFINE_CUSTOM_GETTER(jsImportMetaObjectGetter_path, (JSGlobalObject * global
return JSValue::encode(thisObject->pathProperty.getInitializedOnMainThread(thisObject));
}
JSC_DEFINE_CUSTOM_GETTER(jsImportMetaObjectGetter_require, (JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, PropertyName propertyName))
{
ImportMetaObject* thisObject = jsDynamicCast<ImportMetaObject*>(JSValue::decode(thisValue));
@@ -478,6 +332,7 @@ JSC_DEFINE_CUSTOM_GETTER(jsImportMetaObjectGetter_require, (JSGlobalObject * glo
return JSValue::encode(thisObject->requireProperty.getInitializedOnMainThread(thisObject));
}
JSC_DEFINE_CUSTOM_GETTER(jsImportMetaObjectGetter_env, (JSGlobalObject * jsGlobalObject, JSC::EncodedJSValue thisValue, PropertyName propertyName))
{
auto* globalObject = jsCast<Zig::GlobalObject*>(jsGlobalObject);
@@ -485,15 +340,15 @@ JSC_DEFINE_CUSTOM_GETTER(jsImportMetaObjectGetter_env, (JSGlobalObject * jsGloba
}
static const HashTableValue ImportMetaObjectPrototypeValues[] = {
{ "env"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsImportMetaObjectGetter_env, 0 } },
{ "dir"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsImportMetaObjectGetter_dir, 0 } },
{ "dirname"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsImportMetaObjectGetter_dir, 0 } },
{ "env"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsImportMetaObjectGetter_env, 0 } },
{ "file"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsImportMetaObjectGetter_file, 0 } },
{ "filename"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsImportMetaObjectGetter_path, 0 } },
{ "path"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsImportMetaObjectGetter_path, 0 } },
{ "require"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsImportMetaObjectGetter_require, 0 } },
{ "resolve"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, functionImportMeta__resolve, 0 } },
{ "resolveSync"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, functionImportMeta__resolveSync, 0 } },
{ "resolve"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, jsFunctionImportMeta_resolve, 0 } },
{ "resolveSync"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, jsFunctionImportMeta_resolveSync, 0 } },
{ "url"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, jsImportMetaObjectGetter_url, 0 } },
};
@@ -525,8 +380,8 @@ public:
{
Base::finishCreation(vm);
auto* clientData = WebCore::clientData(vm);
auto& builtinNames = clientData->builtinNames();
auto clientData = WebCore::clientData(vm);
auto builtinNames = clientData->builtinNames();
reifyStaticProperties(vm, ImportMetaObject::info(), ImportMetaObjectPrototypeValues, *this);
JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
@@ -558,9 +413,6 @@ JSC::Structure* ImportMetaObject::createStructure(JSC::VM& vm, JSC::JSGlobalObje
globalObject,
ImportMetaObjectPrototype::createStructure(vm, globalObject));
auto clientData = WebCore::clientData(vm);
auto& builtinNames = clientData->builtinNames();
return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), ImportMetaObject::info());
}
@@ -570,52 +422,57 @@ void ImportMetaObject::finishCreation(VM& vm)
ASSERT(inherits(info()));
this->requireProperty.initLater([](const JSC::LazyProperty<JSC::JSObject, JSC::JSFunction>::Initializer& init) {
ImportMetaObject* meta = jsCast<ImportMetaObject*>(init.owner);
WTF::URL url = isAbsolutePath(meta->url) ? WTF::URL::fileURLWithFileSystemPath(meta->url) : WTF::URL(meta->url);
WTF::String path;
auto* meta = jsCast<ImportMetaObject*>(init.owner);
auto globalObject = meta->globalObject();
auto& vm = init.vm;
auto url = isAbsolutePath(meta->url) ? WTF::URL::fileURLWithFileSystemPath(meta->url) : WTF::URL(meta->url);
WTF::String filenameWTF;
if (url.isValid()) {
if (url.protocolIsFile()) {
path = url.fileSystemPath();
filenameWTF = url.fileSystemPath();
} else {
path = url.path().toString();
filenameWTF = url.path().toString();
}
} else {
path = meta->url;
filenameWTF = meta->url;
}
JSFunction* value = jsCast<JSFunction*>(Bun::JSCommonJSModule::createBoundRequireFunction(init.vm, meta->globalObject(), path));
auto* filename = JSC::jsStringWithCache(vm, filenameWTF);
JSFunction* value = jsCast<JSFunction*>(Bun::JSCommonJSModule::createBoundRequireFunction(vm, globalObject, filename));
init.set(value);
});
this->urlProperty.initLater([](const JSC::LazyProperty<JSC::JSObject, JSC::JSString>::Initializer& init) {
ImportMetaObject* meta = jsCast<ImportMetaObject*>(init.owner);
WTF::URL url = isAbsolutePath(meta->url) ? WTF::URL::fileURLWithFileSystemPath(meta->url) : WTF::URL(meta->url);
auto* meta = jsCast<ImportMetaObject*>(init.owner);
auto url = isAbsolutePath(meta->url) ? WTF::URL::fileURLWithFileSystemPath(meta->url) : WTF::URL(meta->url);
init.set(jsString(init.vm, url.string()));
});
this->dirProperty.initLater([](const JSC::LazyProperty<JSC::JSObject, JSC::JSString>::Initializer& init) {
ImportMetaObject* meta = jsCast<ImportMetaObject*>(init.owner);
WTF::URL url = isAbsolutePath(meta->url) ? WTF::URL::fileURLWithFileSystemPath(meta->url) : WTF::URL(meta->url);
WTF::String dirname;
auto* meta = jsCast<ImportMetaObject*>(init.owner);
auto globalObject = meta->globalObject();
auto& vm = init.vm;
auto url = isAbsolutePath(meta->url) ? WTF::URL::fileURLWithFileSystemPath(meta->url) : WTF::URL(meta->url);
WTF::String filenameWTF;
if (url.isValid()) {
if (url.protocolIsFile()) {
dirname = url.fileSystemPath();
filenameWTF = url.fileSystemPath();
} else {
dirname = url.path().toString();
filenameWTF = url.path().toString();
}
} else {
filenameWTF = meta->url;
}
if (dirname.endsWith(PLATFORM_SEP_s)) {
dirname = dirname.substring(0, dirname.length() - 1);
} else if (dirname.contains(PLATFORM_SEP)) {
dirname = dirname.substring(0, dirname.reverseFind(PLATFORM_SEP));
}
init.set(jsString(init.vm, dirname));
auto filename = JSC::jsStringWithCache(vm, filenameWTF);
WTF::Vector<JSC::EncodedJSValue, 1> dirnameArgs;
dirnameArgs.reserveInitialCapacity(1);
dirnameArgs.unsafeAppendWithoutCapacityCheck(JSValue::encode(filename));
#if OS(WINDOWS)
auto dirname = JSValue::decode(Bun__Path__dirname(globalObject, true, reinterpret_cast<JSC__JSValue*>(dirnameArgs.data()), 1)).toString(globalObject);
#else
auto dirname = JSValue::decode(Bun__Path__dirname(globalObject, false, reinterpret_cast<JSC__JSValue*>(dirnameArgs.data()), 1)).toString(globalObject);
#endif
init.set(dirname);
});
this->fileProperty.initLater([](const JSC::LazyProperty<JSC::JSObject, JSC::JSString>::Initializer& init) {
ImportMetaObject* meta = jsCast<ImportMetaObject*>(init.owner);

View File

@@ -8,11 +8,8 @@
#include "JSDOMWrapperCache.h"
extern "C" JSC_DECLARE_HOST_FUNCTION(functionImportMeta__resolveSync);
extern "C" JSC_DECLARE_HOST_FUNCTION(functionImportMeta__resolveSyncPrivate);
extern "C" JSC::EncodedJSValue Bun__resolve(JSC::JSGlobalObject* global, JSC::EncodedJSValue specifier, JSC::EncodedJSValue from, bool is_esm);
extern "C" JSC::EncodedJSValue Bun__resolveSync(JSC::JSGlobalObject* global, JSC::EncodedJSValue specifier, JSC::EncodedJSValue from, bool is_esm);
extern "C" JSC::EncodedJSValue Bun__resolveSyncWithSource(JSC::JSGlobalObject* global, JSC::EncodedJSValue specifier, BunString* from, bool is_esm);
namespace Zig {
@@ -24,9 +21,6 @@ public:
using Base = JSC::JSNonFinalObject;
static ImportMetaObject* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, const WTF::String& url);
static JSObject* createRequireFunction(VM& vm, JSGlobalObject* lexicalGlobalObject, const WTF::String& pathString);
static ImportMetaObject* create(JSC::JSGlobalObject* globalObject, JSC::JSString* keyString);
static ImportMetaObject* create(JSC::JSGlobalObject* globalObject, JSValue keyString);

View File

@@ -3663,21 +3663,19 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm)
// TODO: most/all of these private properties can be made as static globals.
// i've noticed doing it as is will work somewhat but getDirect() wont be able to find them
putDirectBuiltinFunction(vm, this, builtinNames.createFIFOPrivateName(), streamInternalsCreateFIFOCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectBuiltinFunction(vm, this, builtinNames.createEmptyReadableStreamPrivateName(), readableStreamCreateEmptyReadableStreamCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectBuiltinFunction(vm, this, builtinNames.createUsedReadableStreamPrivateName(), readableStreamCreateUsedReadableStreamCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectBuiltinFunction(vm, this, builtinNames.consumeReadableStreamPrivateName(), readableStreamConsumeReadableStreamCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectBuiltinFunction(vm, this, builtinNames.createNativeReadableStreamPrivateName(), readableStreamCreateNativeReadableStreamCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectBuiltinFunction(vm, this, builtinNames.requireESMPrivateName(), importMetaObjectRequireESMCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectBuiltinFunction(vm, this, builtinNames.loadCJS2ESMPrivateName(), importMetaObjectLoadCJS2ESMCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectBuiltinFunction(vm, this, builtinNames.internalRequirePrivateName(), importMetaObjectInternalRequireCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectBuiltinFunction(vm, this, builtinNames.requireNativeModulePrivateName(), moduleRequireNativeModuleCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectBuiltinFunction(vm, this, builtinNames.overridableRequirePrivateName(), moduleOverridableRequireCodeGenerator(vm), 0);
putDirectNativeFunction(vm, this, builtinNames.createUninitializedArrayBufferPrivateName(), 1, functionCreateUninitializedArrayBuffer, ImplementationVisibility::Public, NoIntrinsic, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectNativeFunction(vm, this, builtinNames.resolveSyncPrivateName(), 1, functionImportMeta__resolveSyncPrivate, ImplementationVisibility::Public, NoIntrinsic, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectBuiltinFunction(vm, this, builtinNames.createEmptyReadableStreamPrivateName(), readableStreamCreateEmptyReadableStreamCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectBuiltinFunction(vm, this, builtinNames.createFIFOPrivateName(), streamInternalsCreateFIFOCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectNativeFunction(vm, this, builtinNames.createInternalModuleByIdPrivateName(), 1, InternalModuleRegistry::jsCreateInternalModuleById, ImplementationVisibility::Public, NoIntrinsic, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectBuiltinFunction(vm, this, builtinNames.createNativeReadableStreamPrivateName(), readableStreamCreateNativeReadableStreamCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectNativeFunction(vm, this, builtinNames.createUninitializedArrayBufferPrivateName(), 1, functionCreateUninitializedArrayBuffer, ImplementationVisibility::Public, NoIntrinsic, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectBuiltinFunction(vm, this, builtinNames.createUsedReadableStreamPrivateName(), readableStreamCreateUsedReadableStreamCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectBuiltinFunction(vm, this, builtinNames.internalRequirePrivateName(), importMetaObjectInternalRequireCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectBuiltinFunction(vm, this, builtinNames.loadCJS2ESMPrivateName(), importMetaObjectLoadCJS2ESMCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectBuiltinFunction(vm, this, builtinNames.overridableRequirePrivateName(), moduleOverridableRequireCodeGenerator(vm), 0);
putDirectBuiltinFunction(vm, this, builtinNames.requireESMPrivateName(), importMetaObjectRequireESMCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectBuiltinFunction(vm, this, builtinNames.requireNativeModulePrivateName(), moduleRequireNativeModuleCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectNativeFunction(vm, this, builtinNames.resolveSyncPrivateName(), 1, jsFunctionResolveSyncPrivate, ImplementationVisibility::Public, NoIntrinsic, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
putDirectNativeFunction(vm, this,
builtinNames.createCommonJSModulePrivateName(),
@@ -3689,7 +3687,7 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm)
putDirectNativeFunction(vm, this,
builtinNames.evaluateCommonJSModulePrivateName(),
2,
Bun::jsFunctionLoadModule,
Bun::jsFunctionEvaluateCommonJSModule,
ImplementationVisibility::Public,
NoIntrinsic,
PropertyAttribute::ReadOnly | PropertyAttribute::DontDelete | 0);
@@ -3793,13 +3791,13 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
thisObject->m_builtinInternalFunctions.visit(visitor);
thisObject->m_commonStrings.visit<Visitor>(visitor);
visitor.append(thisObject->m_assignToStream);
visitor.append(thisObject->m_nodeModuleOverriddenResolveFilename);
visitor.append(thisObject->m_readableStreamToArrayBuffer);
visitor.append(thisObject->m_readableStreamToArrayBufferResolve);
visitor.append(thisObject->m_readableStreamToBlob);
visitor.append(thisObject->m_readableStreamToJSON);
visitor.append(thisObject->m_readableStreamToText);
visitor.append(thisObject->m_readableStreamToFormData);
visitor.append(thisObject->m_nodeModuleOverriddenResolveFilename);
visitor.append(thisObject->m_nextTickQueue);
visitor.append(thisObject->m_errorConstructorPrepareStackTraceValue);
@@ -3841,7 +3839,6 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
thisObject->m_emitReadableNextTickFunction.visit(visitor);
thisObject->m_JSBufferSubclassStructure.visit(visitor);
thisObject->m_JSCryptoKey.visit(visitor);
thisObject->m_cryptoObject.visit(visitor);
thisObject->m_JSDOMFileConstructor.visit(visitor);
@@ -3857,6 +3854,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
thisObject->m_lazyTestModuleObject.visit(visitor);
thisObject->m_lazyPreloadTestModuleObject.visit(visitor);
thisObject->m_testMatcherUtilsObject.visit(visitor);
thisObject->m_commonJSModuleObjectStructure.visit(visitor);
thisObject->m_JSSQLStatementStructure.visit(visitor);
thisObject->m_memoryFootprintStructure.visit(visitor);

View File

@@ -268,7 +268,7 @@ public:
bool hasProcessObject() const { return m_processObject.isInitialized(); }
RefPtr<WebCore::Performance> performance();
JSC::JSObject* processObject() { return m_processObject.getInitializedOnMainThread(this); }
JSC::JSObject* processEnvObject() { return m_processEnvObject.getInitializedOnMainThread(this); }
JSC::JSObject* bunObject() { return m_bunObject.getInitializedOnMainThread(this); }
@@ -362,8 +362,8 @@ public:
mutable WriteBarrier<JSFunction> m_readableStreamToText;
mutable WriteBarrier<JSFunction> m_readableStreamToFormData;
// This is set when doing `require('module')._resolveFilename = ...`
// a hack used by Next.js to inject their versions of webpack and react
// This is set when overriding `require('module')._resolveFilename = ...`
// used by projects like Next.js to inject their versions of webpack and react.
mutable WriteBarrier<JSFunction> m_nodeModuleOverriddenResolveFilename;
mutable WriteBarrier<Unknown> m_nextTickQueue;

View File

@@ -10,6 +10,9 @@
using namespace Zig;
using namespace JSC;
extern "C" JSC__JSValue Bun__Path__dirname(JSC__JSGlobalObject *arg0, bool arg1,
JSC__JSValue *arg2, uint16_t arg3);
// This is a mix of bun's builtin module names and also the ones reported by
// node v20.4.0
static constexpr ASCIILiteral builtinModuleNames[] = {
@@ -98,10 +101,9 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionNodeModuleModuleConstructor,
// In node, this is supposed to be the actual CommonJSModule constructor.
// We are cutting a huge corner by not doing all that work.
// This code is only to support babel.
JSC::VM &vm = globalObject->vm();
JSString *idString = JSC::jsString(vm, WTF::String("."_s));
JSString *dirname = jsEmptyString(vm);
auto &vm = globalObject->vm();
auto *id = JSC::jsEmptyString(vm);
auto *dirname = JSC::jsStringWithCache(vm, "."_s);
// TODO: handle when JSGlobalObject !== Zig::GlobalObject, such as in node:vm
Structure *structure = static_cast<Zig::GlobalObject *>(globalObject)
@@ -112,18 +114,29 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionNodeModuleModuleConstructor,
JSValue parentValue = callFrame->argument(1);
auto scope = DECLARE_THROW_SCOPE(vm);
if (idValue.isString()) {
idString = idValue.toString(globalObject);
id = idValue.toString(globalObject);
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::jsUndefined()));
auto index = idString->tryGetValue().reverseFind('/', idString->length());
if (index != WTF::notFound) {
dirname = JSC::jsSubstring(globalObject, idString, 0, index);
}
WTF::Vector<JSC::EncodedJSValue, 1> dirnameArgs;
dirnameArgs.reserveInitialCapacity(1);
dirnameArgs.unsafeAppendWithoutCapacityCheck(JSValue::encode(idValue));
#if OS(WINDOWS)
dirname = JSValue::decode(
Bun__Path__dirname(
globalObject, true,
reinterpret_cast<JSC__JSValue *>(dirnameArgs.data()), 1))
.toString(globalObject);
#else
dirname = JSValue::decode(
Bun__Path__dirname(
globalObject, false,
reinterpret_cast<JSC__JSValue *>(dirnameArgs.data()), 1))
.toString(globalObject);
#endif
}
auto *out = Bun::JSCommonJSModule::create(vm, structure, idString, jsNull(),
auto *out = Bun::JSCommonJSModule::create(vm, structure, id, jsNull(),
dirname, nullptr);
if (!parentValue.isUndefined())
@@ -175,7 +188,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionWrap, (JSC::JSGlobalObject * globalObject,
JSC_DEFINE_HOST_FUNCTION(jsFunctionNodeModuleCreateRequire,
(JSC::JSGlobalObject * globalObject,
JSC::CallFrame *callFrame)) {
JSC::VM &vm = globalObject->vm();
auto &vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (callFrame->argumentCount() < 1) {
throwTypeError(globalObject, scope,
@@ -183,10 +196,9 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionNodeModuleCreateRequire,
RELEASE_AND_RETURN(scope, JSC::JSValue::encode({}));
}
auto val = callFrame->uncheckedArgument(0).toWTFString(globalObject);
if (val.startsWith("file://"_s)) {
WTF::URL url(val);
auto filenameWTF = callFrame->uncheckedArgument(0).toWTFString(globalObject);
if (filenameWTF.startsWith("file://"_s)) {
WTF::URL url(filenameWTF);
if (!url.isValid()) {
throwTypeError(globalObject, scope,
makeString("createRequire() was given an invalid URL '"_s,
@@ -199,14 +211,16 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionNodeModuleCreateRequire,
"createRequire() does not support non-file URLs"_s);
RELEASE_AND_RETURN(scope, JSValue::encode({}));
}
val = url.fileSystemPath();
filenameWTF = url.fileSystemPath();
}
auto *filename = JSC::jsStringWithCache(vm, filenameWTF);
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::jsUndefined()));
RELEASE_AND_RETURN(
scope, JSValue::encode(Bun::JSCommonJSModule::createBoundRequireFunction(
vm, globalObject, val)));
vm, globalObject, filename)));
}
extern "C" JSC::EncodedJSValue Resolver__nodeModulePathsForJS(JSGlobalObject *,
CallFrame *);
@@ -332,16 +346,14 @@ JSC_DEFINE_CUSTOM_SETTER(set_resolveFilename,
return false;
}
// These two setters are only used if you directly hit
// `Module.prototype.require` or `module.require`. When accessing the cjs
// require argument, this is a bound version of `require`, which calls into the
// overridden one.
// These accessors are defined for `Module.prototype.require`.
// The cjs `require` argument will also call into the overridden one.
//
// This require function also intentionally does not have .resolve on it, nor
// does it have any of the other properties.
//
// Note: allowing require to be overridable at all is only needed for Next.js to
// work (they do Module.prototype.require = ...)
// Note: allowing require to be overridable is needed for projects like Next.js
// to work (they do Module.prototype.require = ...)
JSC_DEFINE_CUSTOM_GETTER(getterRequireFunction,
(JSC::JSGlobalObject * globalObject,

View File

@@ -33,6 +33,7 @@ export const globalsToPrefix = [
"ArrayBuffer",
"Buffer",
"Infinity",
"isFinite",
"Loader",
"Promise",
"ReadableByteStreamController",
@@ -41,17 +42,15 @@ export const globalsToPrefix = [
"ReadableStreamBYOBRequest",
"ReadableStreamDefaultController",
"ReadableStreamDefaultReader",
"RegExp",
"String",
"TransformStream",
"TransformStreamDefaultController",
"Uint8Array",
"String",
"Buffer",
"RegExp",
"undefined",
"WritableStream",
"WritableStreamDefaultController",
"WritableStreamDefaultWriter",
"isFinite",
"undefined",
];
// These enums map to $<enum>IdToLabel and $<enum>LabelToId

View File

@@ -407,6 +407,8 @@ declare function $streamErrored(): TODO;
declare function $streamReadable(): TODO;
declare function $streamWaiting(): TODO;
declare function $streamWritable(): TODO;
declare function $stringIndexOfInternal(searchString: string, position?: number): number;
declare function $stringSubstring(indexStart: number, indexEnd?: number): string;
declare function $structuredCloneForStream(): TODO;
declare function $syscall(): TODO;
declare function $textDecoderStreamDecoder(): TODO;
@@ -538,3 +540,8 @@ declare var $Buffer: {
declare interface Error {
code?: string;
}
declare var $Object: {
$create(o: object | null): any;
$create(o: object | null, properties: PropertyDescriptorMap & ThisType<any>): any;
};

View File

@@ -150,6 +150,7 @@ using namespace JSC;
macro(once) \
macro(options) \
macro(origin) \
macro(originalStructureID) \
macro(overridableRequire) \
macro(ownerReadableStream) \
macro(parse) \
@@ -217,6 +218,7 @@ using namespace JSC;
macro(strategySizeAlgorithm) \
macro(stream) \
macro(structuredCloneForStream) \
macro(structureChanged) \
macro(syscall) \
macro(textDecoderStreamDecoder) \
macro(textDecoderStreamTransform) \

View File

@@ -11,8 +11,12 @@ export function require(this: CommonJSModuleRecord, id: string) {
// overridableRequire can be overridden by setting `Module.prototype.require`
$overriddenName = "require";
$visibility = "Private";
export function overridableRequire(this: CommonJSModuleRecord, id: string) {
const existing = $requireMap.$get(id) || $requireMap.$get((id = $resolveSync(id, this.path, false)));
export function overridableRequire(this: CommonJSModuleRecord, id: string, type?: { type: string }) {
let existing = $requireMap.$get(id);
if (existing === undefined) {
id = $resolveSync(id, this.path, false);
existing = $requireMap.$get(id);
}
if (existing) {
// Scenario where this is necessary:
//
@@ -34,11 +38,9 @@ export function overridableRequire(this: CommonJSModuleRecord, id: string) {
$evaluateCommonJSModule(existing);
return existing.exports;
}
if (id.endsWith(".node")) {
return $internalRequire(id);
}
// To handle import/export cycles, we need to create a module object and put
// it into the map before we import it.
const mod = $createCommonJSModule(id, {}, false, this);
@@ -49,38 +51,38 @@ export function overridableRequire(this: CommonJSModuleRecord, id: string) {
//
// Note: we do not need to wrap this in a try/catch, if it throws the C++ code will
// clear the module from the map.
//
var out = this.$require(
id,
mod,
// did they pass a { type } object?
$argumentCount(),
// the object containing a "type" attribute, if they passed one
// maybe this will be "paths" in the future too.
arguments[1],
);
// -1 means we need to lookup the module from the ESM registry.
if (out === -1) {
if (
this.$require(
id,
mod,
// Did they pass a { type } object?
// Use `@argumentCount()` to avoid cloned arguments allocation.
$argumentCount(),
// The object containing a "type" attribute, if they passed one
// maybe this will be "paths" in the future too.
type,
) === -1
) {
// -1 means we need to lookup the module from the ESM registry.
try {
out = $requireESM(id);
$requireESM(id);
} catch (exception) {
// Since the ESM code is mostly JS, we need to handle exceptions here.
$requireMap.$delete(id);
throw exception;
}
const esm = Loader.registry.$get(id);
// If we can pull out a ModuleNamespaceObject, let's do it.
if (esm?.evaluated && (esm.state ?? 0) >= $ModuleReady) {
if (esm && esm.evaluated && (esm.state ?? 0) >= $ModuleReady) {
const namespace = Loader.getModuleNamespaceObject(esm!.module);
return (mod.exports =
// if they choose a module
namespace.__esModule ? namespace : Object.create(namespace, { __esModule: { value: true } }));
const exports = namespace.__esModule
? // If they choose a module.
namespace
: $Object.$create(namespace, { __esModule: { value: true } });
mod.exports = exports;
return exports;
}
}
$evaluateCommonJSModule(mod);
return mod.exports;
}
@@ -93,7 +95,7 @@ export function requireResolve(this: string | { path: string }, id: string) {
$visibility = "Private";
export function requireNativeModule(id: string) {
let esm = Loader.registry.$get(id);
if (esm?.evaluated && (esm.state ?? 0) >= $ModuleReady) {
if (esm && esm.evaluated && (esm.state ?? 0) >= $ModuleReady) {
const exports = Loader.getModuleNamespaceObject(esm.module);
return exports.default;
}

View File

@@ -0,0 +1 @@
module.exports = "original";

View File

@@ -0,0 +1,51 @@
const { expect, test } = require("bun:test");
const Module = require("node:module");
test("Module._extensions change", () => {
const oldCjs = Module._extensions[".cjs"];
const oldJs = Module._extensions[".js"];
debugger;
// Test default behavior.
const defaultResult = require("./moduleExtensionsChange-fixture.cjs");
expect(defaultResult).toBe("original");
// Reset.
delete Module._cache[require.resolve("./moduleExtensionsChange-fixture.cjs")];
// Test .cjs extension override.
Module._extensions[".cjs"] = function (mod, filename) {
mod._compile(`module.exports = "winner";`, filename);
};
const changedCjsResult = require("./moduleExtensionsChange-fixture.cjs");
expect(changedCjsResult).toBe("winner");
// Reset.
delete Module._cache[require.resolve("./moduleExtensionsChange-fixture.cjs")];
if (oldCjs) {
Module._extensions['.cjs'] = oldCjs;
} else {
delete Module._extensions['.cjs'];
}
// Test reverted behavior.
const revertedResult = require("./moduleExtensionsChange-fixture.cjs");
expect(revertedResult).toBe("original");
// Reset.
delete Module._cache[require.resolve("./moduleExtensionsChange-fixture.cjs")];
// Test fallback to .js.
Module._extensions[".cjs"] = function (mod, filename) {
mod._compile(`module.exports = "winner";`, filename);
};
const changedJsResult = require("./moduleExtensionsChange-fixture.cjs");
expect(changedJsResult).toBe("winner");
// Reset.
delete Module._cache[require.resolve("./moduleExtensionsChange-fixture.cjs")];
if (oldJs) {
Module._extensions['.js'] = oldJs;
} else {
delete Module._extensions['.js'];
}
});

View File

@@ -1,17 +1,19 @@
const { expect, test } = require("bun:test");
const Module = require("node:module");
// This behavior is required for Next.js to work
const eql = require("assert").deepStrictEqual;
const Module = require("module");
const old = Module.prototype.require;
Module.prototype.require = function (str) {
if (str === "hook") return "winner";
return {
wrap: old.call(this, str),
test("Module.prototype.require overwrite", () => {
const old = Module.prototype.require;
Module.prototype.require = function (id) {
if (id === "hook") {
return "winner";
}
return {
wrap: old.call(this, id),
};
};
};
// this context has the new require
const result = require("./modulePrototypeOverwrite-fixture.cjs");
eql(result, { wrap: "winner" });
console.log("--pass--");
// This context has the new require
const result = require("./modulePrototypeOverwrite-fixture.cjs");
Module.prototype.require = old;
expect(result).toEqual({ wrap: "winner" });
});

View File

@@ -1,9 +1,8 @@
// @known-failing-on-windows: 1 failing
import { expect, test } from "bun:test";
import { bunEnv, bunExe } from "harness";
import { _nodeModulePaths, builtinModules, isBuiltin, wrap } from "module";
import Module from "module";
import path from "path";
import Module, { _nodeModulePaths, builtinModules, isBuiltin, wrap } from "node:module";
import path from "node:path";
test("builtinModules exists", () => {
expect(Array.isArray(builtinModules)).toBe(true);

View File

@@ -1,15 +1,26 @@
const { expect, test } = require("bun:test");
const Module = require("node:module");
const path = require("node:path");
// This behavior is required for Next.js to work
const eql = require("assert").strictEqual;
const path = require("path");
const Module = require("module");
const original = Module._resolveFilename;
Module._resolveFilename = (specifier, parent, isMain) => {
eql(specifier.endsWith("💔"), true);
eql(parent.filename, path.join(__dirname, "./resolveFilenameOverwrite.cjs"));
return path.join(__dirname, "./resolveFilenameOverwrite-fixture.cjs");
};
eql(require("overwriting _resolveFilename broke 💔"), "winner");
Module._resolveFilename = original;
console.log("--pass--");
test("Module._resolveFilename overwrite", () => {
let assertions = 0;
const old = Module._resolveFilename;
Module._resolveFilename = function (request, parent, isMain) {
expect(request.endsWith("💔")).toBe(true);
assertions++;
expect(parent.filename).toBe(path.join(__dirname, "./resolveFilenameOverwrite.cjs"));
assertions++;
expect(isMain).toBe(true);
assertions++;
expect(this).toBe(Module);
assertions++;
return path.join(__dirname, "./resolveFilenameOverwrite-fixture.cjs");
};
const result = require("overwriting _resolveFilename broke 💔");
Module._resolveFilename = old;
expect(result).toBe("winner");
assertions++;
// TODO: Replace with `expect.assertions(3)` once implemented.
expect(assertions).toBe(5);
});