Compare commits

...

1 Commits

Author SHA1 Message Date
Cursor Agent
ddb5866a94 Add Yoga layout library bindings to Bun runtime 2025-06-21 03:07:04 +00:00
14 changed files with 1187 additions and 0 deletions

View File

@@ -92,6 +92,10 @@ src/bun.js/bindings/JSWrappingFunction.cpp
src/bun.js/bindings/JSX509Certificate.cpp
src/bun.js/bindings/JSX509CertificateConstructor.cpp
src/bun.js/bindings/JSX509CertificatePrototype.cpp
src/bun.js/bindings/JSYogaConfig.cpp
src/bun.js/bindings/JSYogaConstructor.cpp
src/bun.js/bindings/JSYogaNode.cpp
src/bun.js/bindings/JSYogaPrototype.cpp
src/bun.js/bindings/linux_perf_tracing.cpp
src/bun.js/bindings/MarkingConstraint.cpp
src/bun.js/bindings/ModuleLoader.cpp

View File

@@ -0,0 +1,58 @@
#include "root.h"
#include "JSYogaConfig.h"
#include <JavaScriptCore/ObjectConstructor.h>
namespace Bun {
const JSC::ClassInfo JSYogaConfig::s_info = { "Yoga.Config"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSYogaConfig) };
JSYogaConfig::JSYogaConfig(JSC::VM& vm, JSC::Structure* structure)
: Base(vm, structure)
, m_config(nullptr)
{
}
JSYogaConfig::~JSYogaConfig()
{
if (m_config) {
YGConfigFree(m_config);
}
}
JSYogaConfig* JSYogaConfig::create(JSC::VM& vm, JSC::Structure* structure)
{
JSYogaConfig* config = new (NotNull, JSC::allocateCell<JSYogaConfig>(vm)) JSYogaConfig(vm, structure);
config->finishCreation(vm);
return config;
}
void JSYogaConfig::finishCreation(JSC::VM& vm)
{
Base::finishCreation(vm);
m_config = YGConfigNew();
}
void JSYogaConfig::destroy(JSC::JSCell* cell)
{
static_cast<JSYogaConfig*>(cell)->~JSYogaConfig();
}
JSC::Structure* JSYogaConfig::createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
{
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
}
template<typename, JSC::SubspaceAccess mode>
JSC::GCClient::IsoSubspace* JSYogaConfig::subspaceFor(JSC::VM& vm)
{
if constexpr (mode == JSC::SubspaceAccess::Concurrently)
return nullptr;
return WebCore::subspaceForImpl<JSYogaConfig, WebCore::UseCustomHeapCellType::No>(
vm,
[](auto& spaces) { return spaces.m_clientSubspaceForJSYogaConfig.get(); },
[](auto& spaces, auto&& space) { spaces.m_clientSubspaceForJSYogaConfig = std::forward<decltype(space)>(space); },
[](auto& spaces) { return spaces.m_subspaceForJSYogaConfig.get(); },
[](auto& spaces, auto&& space) { spaces.m_subspaceForJSYogaConfig = std::forward<decltype(space)>(space); });
}
} // namespace Bun

View File

@@ -0,0 +1,31 @@
#pragma once
#include "root.h"
#include "vendor/yoga/yoga/Yoga.h"
#include <JavaScriptCore/JSDestructibleObject.h>
#include <memory>
namespace Bun {
class JSYogaConfig final : public JSC::JSDestructibleObject {
public:
using Base = JSC::JSDestructibleObject;
static constexpr unsigned StructureFlags = Base::StructureFlags;
static constexpr JSC::DestructionMode needsDestruction = JSC::NeedsDestruction;
static JSYogaConfig* create(JSC::VM&, JSC::Structure*);
static void destroy(JSC::JSCell*);
static JSC::Structure* createStructure(JSC::VM&, JSC::JSGlobalObject*, JSC::JSValue);
~JSYogaConfig();
template<typename, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM&);
DECLARE_INFO;
YGConfigRef internal() { return m_config; }
private:
JSYogaConfig(JSC::VM&, JSC::Structure*);
void finishCreation(JSC::VM&);
YGConfigRef m_config;
};
} // namespace Bun

View File

@@ -0,0 +1,102 @@
#include "root.h"
#include "JSYogaConfig.h"
#include "JSYogaNode.h"
#include "JSYogaPrototype.h"
#include "JSYogaConstructor.h"
#include <JavaScriptCore/JSCInlines.h>
#include <JavaScriptCore/ObjectConstructor.h>
#include "ZigGlobalObject.h"
namespace Bun {
// ================ JSYogaConfig Constructor ================
const JSC::ClassInfo JSYogaConfigConstructor::s_info = { "ConfigConstructor"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSYogaConfigConstructor) };
void JSYogaConfigConstructor::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSObject* prototype)
{
Base::finishCreation(vm, 0, "Config"_s);
putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly);
}
JSC_DEFINE_HOST_FUNCTION(constructJSYogaConfig, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto* zigGlobal = Bun::defaultGlobalObject(globalObject);
// Get the pre-initialized structure from the global object
JSC::Structure* structure = zigGlobal->m_JSYogaConfigClassStructure.get(zigGlobal);
// Create new Config instance
return JSC::JSValue::encode(JSYogaConfig::create(vm, structure));
}
// ================ JSYogaNode Constructor ================
const JSC::ClassInfo JSYogaNodeConstructor::s_info = { "NodeConstructor"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSYogaNodeConstructor) };
void JSYogaNodeConstructor::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSObject* prototype)
{
Base::finishCreation(vm, 1, "Node"_s);
putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly);
}
JSC_DEFINE_HOST_FUNCTION(constructJSYogaNode, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* zigGlobal = Bun::defaultGlobalObject(globalObject);
// Get the pre-initialized structure from the global object
JSC::Structure* structure = zigGlobal->m_JSYogaNodeClassStructure.get(zigGlobal);
// Check if a config was provided as the first argument
YGConfigRef config = nullptr;
if (callFrame->argumentCount() > 0) {
JSC::JSValue configValue = callFrame->argument(0);
if (!configValue.isUndefinedOrNull()) {
auto* configObject = jsDynamicCast<JSYogaConfig*>(configValue);
if (UNLIKELY(!configObject)) {
return JSC::JSValue::encode(throwTypeError(globalObject, scope, "First argument must be a Yoga.Config instance"_s));
}
config = configObject->internal();
}
}
// Create new Node instance
return JSC::JSValue::encode(JSYogaNode::create(vm, structure, config));
}
// ================ Setup Functions ================
void setupJSYogaConfigClassStructure(JSC::LazyClassStructure::Initializer& init)
{
auto* prototypeStructure = JSYogaConfigPrototype::createStructure(init.vm, init.global, init.global->objectPrototype());
auto* prototype = JSYogaConfigPrototype::create(init.vm, init.global, prototypeStructure);
auto* constructorStructure = JSYogaConfigConstructor::createStructure(init.vm, init.global, init.global->functionPrototype());
auto* constructor = JSYogaConfigConstructor::create(init.vm, init.global, constructorStructure, prototype);
auto* structure = JSYogaConfig::createStructure(init.vm, init.global, prototype);
init.setPrototype(prototype);
init.setStructure(structure);
init.setConstructor(constructor);
}
void setupJSYogaNodeClassStructure(JSC::LazyClassStructure::Initializer& init)
{
auto* prototypeStructure = JSYogaNodePrototype::createStructure(init.vm, init.global, init.global->objectPrototype());
auto* prototype = JSYogaNodePrototype::create(init.vm, init.global, prototypeStructure);
auto* constructorStructure = JSYogaNodeConstructor::createStructure(init.vm, init.global, init.global->functionPrototype());
auto* constructor = JSYogaNodeConstructor::create(init.vm, init.global, constructorStructure, prototype);
auto* structure = JSYogaNode::createStructure(init.vm, init.global, prototype);
init.setPrototype(prototype);
init.setStructure(structure);
init.setConstructor(constructor);
}
} // namespace Bun

View File

@@ -0,0 +1,73 @@
#pragma once
#include "root.h"
#include <JavaScriptCore/InternalFunction.h>
namespace Bun {
// JSYogaConfig Constructor
class JSYogaConfigConstructor final : public JSC::InternalFunction {
public:
using Base = JSC::InternalFunction;
static constexpr unsigned StructureFlags = Base::StructureFlags;
static JSYogaConfigConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSC::JSObject* prototype)
{
JSYogaConfigConstructor* constructor = new (NotNull, JSC::allocateCell<JSYogaConfigConstructor>(vm)) JSYogaConfigConstructor(vm, structure);
constructor->finishCreation(vm, globalObject, prototype);
return constructor;
}
DECLARE_INFO;
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
{
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info());
}
private:
JSYogaConfigConstructor(JSC::VM& vm, JSC::Structure* structure)
: Base(vm, structure, constructJSYogaConfig, constructJSYogaConfig)
{
}
void finishCreation(JSC::VM&, JSC::JSGlobalObject*, JSC::JSObject*);
};
// JSYogaNode Constructor
class JSYogaNodeConstructor final : public JSC::InternalFunction {
public:
using Base = JSC::InternalFunction;
static constexpr unsigned StructureFlags = Base::StructureFlags;
static JSYogaNodeConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSC::JSObject* prototype)
{
JSYogaNodeConstructor* constructor = new (NotNull, JSC::allocateCell<JSYogaNodeConstructor>(vm)) JSYogaNodeConstructor(vm, structure);
constructor->finishCreation(vm, globalObject, prototype);
return constructor;
}
DECLARE_INFO;
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
{
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info());
}
private:
JSYogaNodeConstructor(JSC::VM& vm, JSC::Structure* structure)
: Base(vm, structure, constructJSYogaNode, constructJSYogaNode)
{
}
void finishCreation(JSC::VM&, JSC::JSGlobalObject*, JSC::JSObject*);
};
// Forward declarations for construct functions
JSC_DECLARE_HOST_FUNCTION(constructJSYogaConfig);
JSC_DECLARE_HOST_FUNCTION(constructJSYogaNode);
// Setup functions for lazy class structure initialization
void setupJSYogaConfigClassStructure(JSC::LazyClassStructure::Initializer&);
void setupJSYogaNodeClassStructure(JSC::LazyClassStructure::Initializer&);
} // namespace Bun

View File

@@ -0,0 +1,79 @@
#include "root.h"
#include "JSYogaNode.h"
#include <JavaScriptCore/ObjectConstructor.h>
namespace Bun {
const JSC::ClassInfo JSYogaNode::s_info = { "Yoga.Node"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSYogaNode) };
JSYogaNode::JSYogaNode(JSC::VM& vm, JSC::Structure* structure)
: Base(vm, structure)
, m_node(nullptr)
{
}
JSYogaNode::~JSYogaNode()
{
if (m_node) {
YGNodeFreeRecursive(m_node);
}
}
JSYogaNode* JSYogaNode::create(JSC::VM& vm, JSC::Structure* structure, YGConfigRef config)
{
JSYogaNode* node = new (NotNull, JSC::allocateCell<JSYogaNode>(vm)) JSYogaNode(vm, structure);
node->finishCreation(vm, config);
return node;
}
void JSYogaNode::finishCreation(JSC::VM& vm, YGConfigRef config)
{
Base::finishCreation(vm);
if (config) {
m_node = YGNodeNewWithConfig(config);
} else {
m_node = YGNodeNew();
}
// This is the essential link that enables callbacks and hierarchy traversal
YGNodeSetContext(m_node, this);
}
void JSYogaNode::destroy(JSC::JSCell* cell)
{
static_cast<JSYogaNode*>(cell)->~JSYogaNode();
}
JSC::Structure* JSYogaNode::createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
{
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
}
JSYogaNode* JSYogaNode::fromYGNode(YGNodeRef nodeRef)
{
if (!nodeRef) return nullptr;
return static_cast<JSYogaNode*>(YGNodeGetContext(nodeRef));
}
DEFINE_VISIT_CHILDREN(JSYogaNode);
void JSYogaNode::visitChildrenImpl(JSC::JSCell* cell, JSC::Visitor& visitor)
{
JSYogaNode* thisObject = jsCast<JSYogaNode*>(cell);
Base::visitChildren(thisObject, visitor);
visitor.append(thisObject->m_measureFunc);
visitor.append(thisObject->m_dirtiedFunc);
}
template<typename, JSC::SubspaceAccess mode>
JSC::GCClient::IsoSubspace* JSYogaNode::subspaceFor(JSC::VM& vm)
{
if constexpr (mode == JSC::SubspaceAccess::Concurrently)
return nullptr;
return WebCore::subspaceForImpl<JSYogaNode, WebCore::UseCustomHeapCellType::No>(
vm,
[](auto& spaces) { return spaces.m_clientSubspaceForJSYogaNode.get(); },
[](auto& spaces, auto&& space) { spaces.m_clientSubspaceForJSYogaNode = std::forward<decltype(space)>(space); },
[](auto& spaces) { return spaces.m_subspaceForJSYogaNode.get(); },
[](auto& spaces, auto&& space) { spaces.m_subspaceForJSYogaNode = std::forward<decltype(space)>(space); });
}
} // namespace Bun

View File

@@ -0,0 +1,37 @@
#pragma once
#include "root.h"
#include "vendor/yoga/yoga/Yoga.h"
#include <JavaScriptCore/JSDestructibleObject.h>
#include <JavaScriptCore/Strong.h>
#include <memory>
namespace Bun {
class JSYogaNode final : public JSC::JSDestructibleObject {
public:
using Base = JSC::JSDestructibleObject;
static constexpr unsigned StructureFlags = Base::StructureFlags;
static constexpr JSC::DestructionMode needsDestruction = JSC::NeedsDestruction;
static JSYogaNode* create(JSC::VM&, JSC::Structure*, YGConfigRef config = nullptr);
static void destroy(JSC::JSCell*);
static JSC::Structure* createStructure(JSC::VM&, JSC::JSGlobalObject*, JSC::JSValue);
static JSYogaNode* fromYGNode(YGNodeRef);
~JSYogaNode();
template<typename, JSC::SubspaceAccess> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM&);
DECLARE_INFO;
DECLARE_VISIT_CHILDREN;
YGNodeRef internal() { return m_node; }
JSC::Strong<JSC::JSObject> m_measureFunc;
JSC::Strong<JSC::JSObject> m_dirtiedFunc;
private:
JSYogaNode(JSC::VM&, JSC::Structure*);
void finishCreation(JSC::VM&, YGConfigRef config);
YGNodeRef m_node;
};
} // namespace Bun

View File

@@ -0,0 +1,535 @@
#include "root.h"
#include "JSYogaConfig.h"
#include "JSYogaNode.h"
#include "JSYogaPrototype.h"
#include <JavaScriptCore/JSCInlines.h>
#include <JavaScriptCore/PropertyTable.h>
namespace Bun {
// ================ JSYogaConfigPrototype Implementation ================
// Declare all host functions for the Config prototype
static JSC_DECLARE_HOST_FUNCTION(jsYogaConfigProtoFuncSetUseWebDefaults);
static JSC_DECLARE_HOST_FUNCTION(jsYogaConfigProtoFuncUseWebDefaults);
static JSC_DECLARE_HOST_FUNCTION(jsYogaConfigProtoFuncSetPointScaleFactor);
static JSC_DECLARE_HOST_FUNCTION(jsYogaConfigProtoFuncIsExperimentalFeatureEnabled);
static JSC_DECLARE_HOST_FUNCTION(jsYogaConfigProtoFuncSetExperimentalFeatureEnabled);
// Define the static hash table for Config properties
static const JSC::HashTableValue JSYogaConfigPrototypeTableValues[] = {
{ "setUseWebDefaults"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaConfigProtoFuncSetUseWebDefaults, 1 } },
{ "useWebDefaults"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaConfigProtoFuncUseWebDefaults, 0 } },
{ "setPointScaleFactor"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaConfigProtoFuncSetPointScaleFactor, 1 } },
{ "isExperimentalFeatureEnabled"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaConfigProtoFuncIsExperimentalFeatureEnabled, 1 } },
{ "setExperimentalFeatureEnabled"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaConfigProtoFuncSetExperimentalFeatureEnabled, 2 } },
};
const JSC::ClassInfo JSYogaConfigPrototype::s_info = { "Yoga.Config"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSYogaConfigPrototype) };
void JSYogaConfigPrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
{
Base::finishCreation(vm);
reifyStaticProperties(vm, JSYogaConfig::info(), JSYogaConfigPrototypeTableValues, *this);
JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
}
// Config method implementations
JSC_DEFINE_HOST_FUNCTION(jsYogaConfigProtoFuncSetUseWebDefaults, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsDynamicCast<JSYogaConfig*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
return JSC::JSValue::encode(throwThisTypeError(globalObject, scope, "Yoga.Config", "setUseWebDefaults"));
}
bool enabled = callFrame->argument(0).toBoolean(globalObject);
YGConfigSetUseWebDefaults(thisObject->internal(), enabled);
return JSC::JSValue::encode(JSC::jsUndefined());
}
JSC_DEFINE_HOST_FUNCTION(jsYogaConfigProtoFuncUseWebDefaults, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsDynamicCast<JSYogaConfig*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
return JSC::JSValue::encode(throwThisTypeError(globalObject, scope, "Yoga.Config", "useWebDefaults"));
}
bool result = YGConfigGetUseWebDefaults(thisObject->internal());
return JSC::JSValue::encode(JSC::jsBoolean(result));
}
JSC_DEFINE_HOST_FUNCTION(jsYogaConfigProtoFuncSetPointScaleFactor, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsDynamicCast<JSYogaConfig*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
return JSC::JSValue::encode(throwThisTypeError(globalObject, scope, "Yoga.Config", "setPointScaleFactor"));
}
float factor = callFrame->argument(0).toFloat(globalObject);
RETURN_IF_EXCEPTION(scope, {});
YGConfigSetPointScaleFactor(thisObject->internal(), factor);
return JSC::JSValue::encode(JSC::jsUndefined());
}
JSC_DEFINE_HOST_FUNCTION(jsYogaConfigProtoFuncIsExperimentalFeatureEnabled, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsDynamicCast<JSYogaConfig*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
return JSC::JSValue::encode(throwThisTypeError(globalObject, scope, "Yoga.Config", "isExperimentalFeatureEnabled"));
}
int featureInt = callFrame->argument(0).toInt32(globalObject);
RETURN_IF_EXCEPTION(scope, {});
bool result = YGConfigIsExperimentalFeatureEnabled(thisObject->internal(), static_cast<YGExperimentalFeature>(featureInt));
return JSC::JSValue::encode(JSC::jsBoolean(result));
}
JSC_DEFINE_HOST_FUNCTION(jsYogaConfigProtoFuncSetExperimentalFeatureEnabled, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsDynamicCast<JSYogaConfig*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
return JSC::JSValue::encode(throwThisTypeError(globalObject, scope, "Yoga.Config", "setExperimentalFeatureEnabled"));
}
int featureInt = callFrame->argument(0).toInt32(globalObject);
RETURN_IF_EXCEPTION(scope, {});
bool enabled = callFrame->argument(1).toBoolean(globalObject);
YGConfigSetExperimentalFeatureEnabled(thisObject->internal(), static_cast<YGExperimentalFeature>(featureInt), enabled);
return JSC::JSValue::encode(JSC::jsUndefined());
}
// ================ JSYogaNodePrototype Implementation ================
// Declare all host functions for the Node prototype
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncCalculateLayout);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncCopyStyle);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncFree);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncFreeRecursive);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncGetChild);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncGetChildCount);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedBorder);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedBottom);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedHeight);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedLayout);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedLeft);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedMargin);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedPadding);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedRight);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedTop);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedWidth);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncGetParent);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncInsertChild);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncIsDirty);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncMarkDirty);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncRemoveChild);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncReset);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetAlignContent);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetAlignItems);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetAlignSelf);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetAspectRatio);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetBorder);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetDisplay);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetFlex);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetFlexBasis);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetFlexBasisPercent);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetFlexDirection);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetFlexGrow);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetFlexShrink);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetFlexWrap);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetGap);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetHeight);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetHeightAuto);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetHeightPercent);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetJustifyContent);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMargin);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMarginAuto);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMarginPercent);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMaxHeight);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMaxHeightPercent);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMaxWidth);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMaxWidthPercent);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMeasureFunc);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMinHeight);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMinHeightPercent);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMinWidth);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMinWidthPercent);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetOverflow);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetPadding);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetPaddingPercent);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetPosition);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetPositionPercent);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetPositionType);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetWidth);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetWidthAuto);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetWidthPercent);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncUnsetMeasureFunc);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncSetDirtiedFunc);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncUnsetDirtiedFunc);
static JSC_DECLARE_HOST_FUNCTION(jsYogaNodeProtoFuncGetDirtiedFunc);
// Define the static hash table for Node properties (partial implementation)
static const JSC::HashTableValue JSYogaNodePrototypeTableValues[] = {
{ "calculateLayout"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaNodeProtoFuncCalculateLayout, 3 } },
{ "copyStyle"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaNodeProtoFuncCopyStyle, 1 } },
{ "free"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaNodeProtoFuncFree, 0 } },
{ "freeRecursive"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaNodeProtoFuncFreeRecursive, 0 } },
{ "getChild"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaNodeProtoFuncGetChild, 1 } },
{ "getChildCount"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaNodeProtoFuncGetChildCount, 0 } },
{ "getComputedLayout"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaNodeProtoFuncGetComputedLayout, 0 } },
{ "getParent"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaNodeProtoFuncGetParent, 0 } },
{ "insertChild"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaNodeProtoFuncInsertChild, 2 } },
{ "isDirty"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaNodeProtoFuncIsDirty, 0 } },
{ "markDirty"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaNodeProtoFuncMarkDirty, 0 } },
{ "removeChild"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaNodeProtoFuncRemoveChild, 1 } },
{ "reset"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaNodeProtoFuncReset, 0 } },
{ "setWidth"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaNodeProtoFuncSetWidth, 1 } },
{ "setHeight"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaNodeProtoFuncSetHeight, 1 } },
{ "setMeasureFunc"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaNodeProtoFuncSetMeasureFunc, 1 } },
{ "unsetMeasureFunc"_s, JSC::PropertyAttribute::Function, JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsYogaNodeProtoFuncUnsetMeasureFunc, 0 } },
};
const JSC::ClassInfo JSYogaNodePrototype::s_info = { "Yoga.Node"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSYogaNodePrototype) };
void JSYogaNodePrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
{
Base::finishCreation(vm);
reifyStaticProperties(vm, JSYogaNode::info(), JSYogaNodePrototypeTableValues, *this);
JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
}
// Node method implementations (partial - just a few key ones)
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncCalculateLayout, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsDynamicCast<JSYogaNode*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
return JSC::JSValue::encode(throwThisTypeError(globalObject, scope, "Yoga.Node", "calculateLayout"));
}
float width = YGUndefined;
float height = YGUndefined;
YGDirection direction = YGDirectionLTR;
if (callFrame->argumentCount() > 0) {
width = callFrame->argument(0).toFloat(globalObject);
RETURN_IF_EXCEPTION(scope, {});
}
if (callFrame->argumentCount() > 1) {
height = callFrame->argument(1).toFloat(globalObject);
RETURN_IF_EXCEPTION(scope, {});
}
if (callFrame->argumentCount() > 2) {
direction = static_cast<YGDirection>(callFrame->argument(2).toInt32(globalObject));
RETURN_IF_EXCEPTION(scope, {});
}
YGNodeCalculateLayout(thisObject->internal(), width, height, direction);
return JSC::JSValue::encode(JSC::jsUndefined());
}
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedLayout, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsDynamicCast<JSYogaNode*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
return JSC::JSValue::encode(throwThisTypeError(globalObject, scope, "Yoga.Node", "getComputedLayout"));
}
auto* node = thisObject->internal();
JSC::JSObject* result = JSC::constructEmptyObject(globalObject);
result->putDirect(vm, vm.propertyNames->left, JSC::jsNumber(YGNodeLayoutGetLeft(node)));
result->putDirect(vm, vm.propertyNames->top, JSC::jsNumber(YGNodeLayoutGetTop(node)));
result->putDirect(vm, vm.propertyNames->width, JSC::jsNumber(YGNodeLayoutGetWidth(node)));
result->putDirect(vm, vm.propertyNames->height, JSC::jsNumber(YGNodeLayoutGetHeight(node)));
return JSC::JSValue::encode(result);
}
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncGetChild, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsDynamicCast<JSYogaNode*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
return JSC::JSValue::encode(throwThisTypeError(globalObject, scope, "Yoga.Node", "getChild"));
}
int index = callFrame->argument(0).toInt32(globalObject);
RETURN_IF_EXCEPTION(scope, {});
YGNodeRef childRef = YGNodeGetChild(thisObject->internal(), index);
if (!childRef) {
return JSC::JSValue::encode(JSC::jsNull());
}
return JSC::JSValue::encode(JSYogaNode::fromYGNode(childRef));
}
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncGetParent, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsDynamicCast<JSYogaNode*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
return JSC::JSValue::encode(throwThisTypeError(globalObject, scope, "Yoga.Node", "getParent"));
}
YGNodeRef parentRef = YGNodeGetParent(thisObject->internal());
if (!parentRef) {
return JSC::JSValue::encode(JSC::jsNull());
}
return JSC::JSValue::encode(JSYogaNode::fromYGNode(parentRef));
}
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncInsertChild, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsDynamicCast<JSYogaNode*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
return JSC::JSValue::encode(throwThisTypeError(globalObject, scope, "Yoga.Node", "insertChild"));
}
auto* child = jsDynamicCast<JSYogaNode*>(callFrame->argument(0));
if (UNLIKELY(!child)) {
return JSC::JSValue::encode(throwTypeError(globalObject, scope, "First argument must be a Yoga.Node instance"_s));
}
int index = callFrame->argument(1).toInt32(globalObject);
RETURN_IF_EXCEPTION(scope, {});
YGNodeInsertChild(thisObject->internal(), child->internal(), index);
return JSC::JSValue::encode(JSC::jsUndefined());
}
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncRemoveChild, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsDynamicCast<JSYogaNode*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
return JSC::JSValue::encode(throwThisTypeError(globalObject, scope, "Yoga.Node", "removeChild"));
}
auto* child = jsDynamicCast<JSYogaNode*>(callFrame->argument(0));
if (UNLIKELY(!child)) {
return JSC::JSValue::encode(throwTypeError(globalObject, scope, "First argument must be a Yoga.Node instance"_s));
}
YGNodeRemoveChild(thisObject->internal(), child->internal());
return JSC::JSValue::encode(JSC::jsUndefined());
}
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncGetChildCount, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsDynamicCast<JSYogaNode*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
return JSC::JSValue::encode(throwThisTypeError(globalObject, scope, "Yoga.Node", "getChildCount"));
}
return JSC::JSValue::encode(JSC::jsNumber(YGNodeGetChildCount(thisObject->internal())));
}
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncIsDirty, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsDynamicCast<JSYogaNode*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
return JSC::JSValue::encode(throwThisTypeError(globalObject, scope, "Yoga.Node", "isDirty"));
}
return JSC::JSValue::encode(JSC::jsBoolean(YGNodeIsDirty(thisObject->internal())));
}
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncMarkDirty, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsDynamicCast<JSYogaNode*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
return JSC::JSValue::encode(throwThisTypeError(globalObject, scope, "Yoga.Node", "markDirty"));
}
YGNodeMarkDirty(thisObject->internal());
return JSC::JSValue::encode(JSC::jsUndefined());
}
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncReset, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsDynamicCast<JSYogaNode*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
return JSC::JSValue::encode(throwThisTypeError(globalObject, scope, "Yoga.Node", "reset"));
}
YGNodeReset(thisObject->internal());
return JSC::JSValue::encode(JSC::jsUndefined());
}
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncCopyStyle, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsDynamicCast<JSYogaNode*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
return JSC::JSValue::encode(throwThisTypeError(globalObject, scope, "Yoga.Node", "copyStyle"));
}
auto* srcNode = jsDynamicCast<JSYogaNode*>(callFrame->argument(0));
if (UNLIKELY(!srcNode)) {
return JSC::JSValue::encode(throwTypeError(globalObject, scope, "First argument must be a Yoga.Node instance"_s));
}
YGNodeCopyStyle(thisObject->internal(), srcNode->internal());
return JSC::JSValue::encode(JSC::jsUndefined());
}
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncFree, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsDynamicCast<JSYogaNode*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
return JSC::JSValue::encode(throwThisTypeError(globalObject, scope, "Yoga.Node", "free"));
}
// Note: The actual freeing is handled by the destructor
// This just marks it for cleanup
YGNodeFree(thisObject->internal());
return JSC::JSValue::encode(JSC::jsUndefined());
}
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncFreeRecursive, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsDynamicCast<JSYogaNode*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
return JSC::JSValue::encode(throwThisTypeError(globalObject, scope, "Yoga.Node", "freeRecursive"));
}
YGNodeFreeRecursive(thisObject->internal());
return JSC::JSValue::encode(JSC::jsUndefined());
}
// Stub implementations for now
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetWidth, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
// TODO: Implement complex value setter pattern
return JSC::JSValue::encode(JSC::jsUndefined());
}
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetHeight, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
// TODO: Implement complex value setter pattern
return JSC::JSValue::encode(JSC::jsUndefined());
}
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMeasureFunc, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
// TODO: Implement callback pattern
return JSC::JSValue::encode(JSC::jsUndefined());
}
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncUnsetMeasureFunc, (JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame))
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto* thisObject = jsDynamicCast<JSYogaNode*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
return JSC::JSValue::encode(throwThisTypeError(globalObject, scope, "Yoga.Node", "unsetMeasureFunc"));
}
thisObject->m_measureFunc.clear();
YGNodeSetMeasureFunc(thisObject->internal(), nullptr);
return JSC::JSValue::encode(JSC::jsUndefined());
}
// Stub implementations for remaining methods
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedBorder, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedBottom, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedHeight, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedLeft, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedMargin, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedPadding, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedRight, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedTop, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncGetComputedWidth, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetAlignContent, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetAlignItems, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetAlignSelf, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetAspectRatio, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetBorder, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetDisplay, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetFlex, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetFlexBasis, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetFlexBasisPercent, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetFlexDirection, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetFlexGrow, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetFlexShrink, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetFlexWrap, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetGap, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetHeightAuto, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetHeightPercent, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetJustifyContent, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMargin, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMarginAuto, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMarginPercent, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMaxHeight, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMaxHeightPercent, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMaxWidth, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMaxWidthPercent, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMinHeight, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMinHeightPercent, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMinWidth, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetMinWidthPercent, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetOverflow, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetPadding, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetPaddingPercent, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetPosition, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetPositionPercent, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetPositionType, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetWidthAuto, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetWidthPercent, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncSetDirtiedFunc, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncUnsetDirtiedFunc, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
JSC_DEFINE_HOST_FUNCTION(jsYogaNodeProtoFuncGetDirtiedFunc, (JSC::JSGlobalObject*, JSC::CallFrame*)) { return JSC::JSValue::encode(JSC::jsUndefined()); }
} // namespace Bun

View File

@@ -0,0 +1,65 @@
#pragma once
#include "root.h"
#include <JavaScriptCore/JSNonFinalObject.h>
namespace Bun {
// JSYogaConfig Prototype
class JSYogaConfigPrototype final : public JSC::JSNonFinalObject {
public:
using Base = JSC::JSNonFinalObject;
static constexpr unsigned StructureFlags = Base::StructureFlags;
static JSYogaConfigPrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
{
JSYogaConfigPrototype* prototype = new (NotNull, JSC::allocateCell<JSYogaConfigPrototype>(vm)) JSYogaConfigPrototype(vm, structure);
prototype->finishCreation(vm, globalObject);
return prototype;
}
DECLARE_INFO;
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
{
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
}
private:
JSYogaConfigPrototype(JSC::VM& vm, JSC::Structure* structure)
: Base(vm, structure)
{
}
void finishCreation(JSC::VM&, JSC::JSGlobalObject*);
};
// JSYogaNode Prototype
class JSYogaNodePrototype final : public JSC::JSNonFinalObject {
public:
using Base = JSC::JSNonFinalObject;
static constexpr unsigned StructureFlags = Base::StructureFlags;
static JSYogaNodePrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
{
JSYogaNodePrototype* prototype = new (NotNull, JSC::allocateCell<JSYogaNodePrototype>(vm)) JSYogaNodePrototype(vm, structure);
prototype->finishCreation(vm, globalObject);
return prototype;
}
DECLARE_INFO;
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
{
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
}
private:
JSYogaNodePrototype(JSC::VM& vm, JSC::Structure* structure)
: Base(vm, structure)
{
}
void finishCreation(JSC::VM&, JSC::JSGlobalObject*);
};
} // namespace Bun

View File

@@ -177,6 +177,7 @@
#include "JSPrivateKeyObject.h"
#include "webcore/JSMIMEParams.h"
#include "JSNodePerformanceHooksHistogram.h"
#include "JSYogaConstructor.h"
#include "JSS3File.h"
#include "S3Error.h"
#include "ProcessBindingBuffer.h"
@@ -2808,6 +2809,16 @@ void GlobalObject::finishCreation(VM& vm)
Bun::setupJSNodePerformanceHooksHistogramClassStructure(init);
});
m_JSYogaConfigClassStructure.initLater(
[](LazyClassStructure::Initializer& init) {
Bun::setupJSYogaConfigClassStructure(init);
});
m_JSYogaNodeClassStructure.initLater(
[](LazyClassStructure::Initializer& init) {
Bun::setupJSYogaNodeClassStructure(init);
});
m_lazyStackCustomGetterSetter.initLater(
[](const Initializer<CustomGetterSetter>& init) {
init.set(CustomGetterSetter::create(init.vm, errorInstanceLazyStackCustomGetter, errorInstanceLazyStackCustomSetter));
@@ -3783,6 +3794,32 @@ extern "C" void JSC__JSGlobalObject__addGc(JSC::JSGlobalObject* globalObject)
// ====================== end conditional builtin globals ======================
extern "C" void JSC__JSGlobalObject__exposeYoga(JSC::JSGlobalObject* lexicalGlobalObject)
{
auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
auto& vm = globalObject->vm();
// Create the Yoga namespace object
JSC::JSObject* yogaObject = JSC::constructEmptyObject(globalObject, globalObject->objectPrototype());
// Attach Config constructor
yogaObject->putDirect(vm, JSC::Identifier::fromString(vm, "Config"_s),
globalObject->m_JSYogaConfigClassStructure.constructor(globalObject),
PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
// Attach Node constructor
yogaObject->putDirect(vm, JSC::Identifier::fromString(vm, "Node"_s),
globalObject->m_JSYogaNodeClassStructure.constructor(globalObject),
PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
// TODO: Add all the Yoga enums here
// Align, Direction, Edge, etc...
// Expose Yoga globally
globalObject->putDirect(vm, JSC::Identifier::fromString(vm, "Yoga"_s), yogaObject,
PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
}
void GlobalObject::drainMicrotasks()
{
auto& vm = this->vm();

View File

@@ -546,6 +546,8 @@ public:
V(public, LazyClassStructure, m_JSMIMEParamsClassStructure) \
V(public, LazyClassStructure, m_JSMIMETypeClassStructure) \
V(public, LazyClassStructure, m_JSNodePerformanceHooksHistogramClassStructure) \
V(public, LazyClassStructure, m_JSYogaConfigClassStructure) \
V(public, LazyClassStructure, m_JSYogaNodeClassStructure) \
\
V(public, LazyClassStructure, m_JSConnectionsListClassStructure) \
V(public, LazyClassStructure, m_JSHTTPParserClassStructure) \

View File

@@ -71,6 +71,8 @@ public:
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSS3File;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSX509Certificate;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSNodePerformanceHooksHistogram;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSYogaConfig;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSYogaNode;
#include "ZigGeneratedClasses+DOMClientIsoSubspaces.h"
/* --- bun --- */

View File

@@ -68,6 +68,8 @@ public:
std::unique_ptr<IsoSubspace> m_subspaceForJSS3File;
std::unique_ptr<IsoSubspace> m_subspaceForJSX509Certificate;
std::unique_ptr<IsoSubspace> m_subspaceForJSNodePerformanceHooksHistogram;
std::unique_ptr<IsoSubspace> m_subspaceForJSYogaConfig;
std::unique_ptr<IsoSubspace> m_subspaceForJSYogaNode;
#include "ZigGeneratedClasses+DOMIsoSubspaces.h"
/*-- BUN --*/

View File

@@ -0,0 +1,160 @@
import { test, expect } from "bun:test";
test("Yoga global exists", () => {
expect(globalThis.Yoga).toBeDefined();
expect(typeof globalThis.Yoga).toBe("object");
});
test("Yoga.Config exists and can be constructed", () => {
expect(Yoga.Config).toBeDefined();
expect(typeof Yoga.Config).toBe("function");
const config = new Yoga.Config();
expect(config).toBeDefined();
expect(config.constructor.name).toBe("Config");
// Test basic Config methods
expect(typeof config.setUseWebDefaults).toBe("function");
expect(typeof config.useWebDefaults).toBe("function");
expect(typeof config.setPointScaleFactor).toBe("function");
expect(typeof config.isExperimentalFeatureEnabled).toBe("function");
expect(typeof config.setExperimentalFeatureEnabled).toBe("function");
});
test("Yoga.Config.setUseWebDefaults/useWebDefaults", () => {
const config = new Yoga.Config();
// Default should be false
expect(config.useWebDefaults()).toBe(false);
// Set to true
config.setUseWebDefaults(true);
expect(config.useWebDefaults()).toBe(true);
// Set back to false
config.setUseWebDefaults(false);
expect(config.useWebDefaults()).toBe(false);
});
test("Yoga.Config.setPointScaleFactor", () => {
const config = new Yoga.Config();
// Should not throw
expect(() => config.setPointScaleFactor(2.0)).not.toThrow();
expect(() => config.setPointScaleFactor(1.5)).not.toThrow();
expect(() => config.setPointScaleFactor(1.0)).not.toThrow();
});
test("Yoga.Node exists and can be constructed", () => {
expect(Yoga.Node).toBeDefined();
expect(typeof Yoga.Node).toBe("function");
const node = new Yoga.Node();
expect(node).toBeDefined();
expect(node.constructor.name).toBe("Node");
// Test that basic methods exist
expect(typeof node.calculateLayout).toBe("function");
expect(typeof node.getComputedLayout).toBe("function");
expect(typeof node.insertChild).toBe("function");
expect(typeof node.removeChild).toBe("function");
expect(typeof node.getChild).toBe("function");
expect(typeof node.getChildCount).toBe("function");
expect(typeof node.getParent).toBe("function");
expect(typeof node.markDirty).toBe("function");
expect(typeof node.isDirty).toBe("function");
expect(typeof node.reset).toBe("function");
expect(typeof node.copyStyle).toBe("function");
expect(typeof node.free).toBe("function");
expect(typeof node.freeRecursive).toBe("function");
});
test("Yoga.Node can be constructed with Config", () => {
const config = new Yoga.Config();
const node = new Yoga.Node(config);
expect(node).toBeDefined();
expect(node.constructor.name).toBe("Node");
});
test("Yoga.Node hierarchy operations", () => {
const parent = new Yoga.Node();
const child1 = new Yoga.Node();
const child2 = new Yoga.Node();
// Initially no children
expect(parent.getChildCount()).toBe(0);
expect(parent.getChild(0)).toBeNull();
// Insert first child
parent.insertChild(child1, 0);
expect(parent.getChildCount()).toBe(1);
expect(parent.getChild(0)).toBe(child1);
expect(child1.getParent()).toBe(parent);
// Insert second child
parent.insertChild(child2, 1);
expect(parent.getChildCount()).toBe(2);
expect(parent.getChild(1)).toBe(child2);
expect(child2.getParent()).toBe(parent);
// Remove first child
parent.removeChild(child1);
expect(parent.getChildCount()).toBe(1);
expect(parent.getChild(0)).toBe(child2);
expect(child1.getParent()).toBeNull();
});
test("Yoga.Node calculateLayout and getComputedLayout", () => {
const node = new Yoga.Node();
// Should have default layout values
const layout = node.getComputedLayout();
expect(layout).toBeDefined();
expect(typeof layout.left).toBe("number");
expect(typeof layout.top).toBe("number");
expect(typeof layout.width).toBe("number");
expect(typeof layout.height).toBe("number");
// Calculate layout
node.calculateLayout(100, 100);
const newLayout = node.getComputedLayout();
expect(newLayout).toBeDefined();
// After calculation, width and height should reflect the constraints
expect(newLayout.width).toBe(100);
expect(newLayout.height).toBe(100);
});
test("Yoga.Node dirty state", () => {
const node = new Yoga.Node();
// New nodes start dirty
expect(node.isDirty()).toBe(true);
// After calculating layout, should not be dirty
node.calculateLayout();
expect(node.isDirty()).toBe(false);
// Can mark as dirty again
node.markDirty();
expect(node.isDirty()).toBe(true);
});
test("Yoga.Node reset", () => {
const parent = new Yoga.Node();
const child = new Yoga.Node();
parent.insertChild(child, 0);
expect(parent.getChildCount()).toBe(1);
// Reset should clear all style properties but not children
parent.reset();
expect(parent.getChildCount()).toBe(1);
});
test("Yoga.Node copyStyle", () => {
const source = new Yoga.Node();
const target = new Yoga.Node();
// Should not throw
expect(() => target.copyStyle(source)).not.toThrow();
});