Implement module.parent (#5889)

* Make module.parent work

* yay

* oops

* yay
This commit is contained in:
dave caruso
2023-09-22 01:09:55 -04:00
committed by GitHub
parent 9d5459221f
commit 25e69c71e7
16 changed files with 7487 additions and 7419 deletions

View File

@@ -71,6 +71,8 @@
#include <JavaScriptCore/JSSourceCode.h>
#include <JavaScriptCore/LazyPropertyInlines.h>
extern "C" bool Bun__isBunMain(JSC::JSGlobalObject* global, const char* input_ptr, uint64_t input_len);
namespace Bun {
using namespace JSC;
@@ -267,6 +269,31 @@ JSC_DEFINE_CUSTOM_GETTER(getterPath, (JSC::JSGlobalObject * globalObject, JSC::E
return JSValue::encode(thisObject->m_id.get());
}
JSC_DEFINE_CUSTOM_GETTER(getterParent, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
{
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue));
if (UNLIKELY(!thisObject)) {
return JSValue::encode(jsUndefined());
}
auto v = thisObject->m_parent.get();
if (v)
return JSValue::encode(thisObject->m_parent.get());
// initialize parent by checking if it is the main module. we do this lazily because most people
// dont need `module.parent` and creating commonjs module records is done a ton.
auto idValue = thisObject->m_id.get();
if (idValue) {
auto id = idValue->value(globalObject).utf8();
if (Bun__isBunMain(globalObject, id.data(), id.length())) {
thisObject->m_parent.set(globalObject->vm(), thisObject, jsNull());
return JSValue::encode(jsNull());
}
}
thisObject->m_parent.set(globalObject->vm(), thisObject, jsUndefined());
return JSValue::encode(jsUndefined());
}
JSC_DEFINE_CUSTOM_SETTER(setterPath,
(JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue,
JSC::EncodedJSValue value, JSC::PropertyName propertyName))
@@ -331,16 +358,24 @@ JSC_DEFINE_CUSTOM_SETTER(setterId,
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;
}
static JSValue createLoaded(VM& vm, JSObject* object)
{
JSCommonJSModule* cjs = jsCast<JSCommonJSModule*>(object);
return jsBoolean(cjs->hasEvaluated);
}
static JSValue createParent(VM& vm, JSObject* object)
{
return jsUndefined();
}
static JSValue createChildren(VM& vm, JSObject* object)
{
return constructEmptyArray(object->globalObject(), nullptr, 0);
@@ -404,14 +439,14 @@ JSC_DEFINE_HOST_FUNCTION(functionCommonJSModuleRecord_compile, (JSGlobalObject *
}
static const struct HashTableValue JSCommonJSModulePrototypeTableValues[] = {
{ "children"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback | PropertyAttribute::DontEnum | 0), NoIntrinsic, { HashTableValue::LazyPropertyType, createChildren } },
{ "_compile"_s, static_cast<unsigned>(PropertyAttribute::Function | PropertyAttribute::DontEnum), NoIntrinsic, { HashTableValue::NativeFunctionType, functionCommonJSModuleRecord_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::PropertyCallback | PropertyAttribute::DontEnum | 0), NoIntrinsic, { HashTableValue::LazyPropertyType, createLoaded } },
{ "parent"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback | PropertyAttribute::DontEnum | 0), NoIntrinsic, { HashTableValue::LazyPropertyType, createParent } },
{ "loaded"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, createLoaded } },
{ "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 } },
{ "_compile"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, functionCommonJSModuleRecord_compile, 2 } },
};
class JSCommonJSModulePrototype final : public JSC::JSNonFinalObject {
@@ -499,23 +534,23 @@ JSCommonJSModule* JSCommonJSModule::create(
JSC_DEFINE_HOST_FUNCTION(jsFunctionCreateCommonJSModule, (JSGlobalObject * globalObject, CallFrame* callframe))
{
auto& vm = globalObject->vm();
RELEASE_ASSERT(callframe->argumentCount() == 4);
auto id = callframe->argument(0).toWTFString(globalObject);
auto id = callframe->uncheckedArgument(0).toWTFString(globalObject);
JSValue object = callframe->uncheckedArgument(1);
JSValue hasEvaluated = callframe->uncheckedArgument(2);
ASSERT(hasEvaluated.isBoolean());
JSValue parent = callframe->uncheckedArgument(3);
JSValue object = callframe->argument(1);
return JSValue::encode(
JSCommonJSModule::create(
jsCast<Zig::GlobalObject*>(globalObject),
id,
object, callframe->argument(2).isBoolean() && callframe->argument(2).asBoolean()));
return JSValue::encode(JSCommonJSModule::create(jsCast<Zig::GlobalObject*>(globalObject), id, object, hasEvaluated.isTrue(), parent));
}
JSCommonJSModule* JSCommonJSModule::create(
Zig::GlobalObject* globalObject,
const WTF::String& key,
JSValue exportsObject,
bool hasEvaluated)
bool hasEvaluated,
JSValue parent)
{
auto& vm = globalObject->vm();
JSString* requireMapKey = JSC::jsStringWithCache(vm, key);
@@ -530,8 +565,14 @@ JSCommonJSModule* JSCommonJSModule::create(
globalObject->CommonJSModuleObjectStructure(),
requireMapKey, requireMapKey, dirname, nullptr);
out->putDirect(vm, WebCore::clientData(vm)->builtinNames().exportsPublicName(), exportsObject, exportsObject.isCell() && exportsObject.isCallable() ? JSC::PropertyAttribute::Function | 0 : 0);
out->putDirect(
vm,
WebCore::clientData(vm)->builtinNames().exportsPublicName(),
exportsObject,
exportsObject.isCallable() ? JSC::PropertyAttribute::Function | 0 : 0);
out->hasEvaluated = hasEvaluated;
out->m_parent.set(vm, out, parent);
return out;
}