aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-09-27 21:01:34 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-09-27 21:01:34 -0700
commit13f62973128aea9266b43cc2e0de1e7bf1768b52 (patch)
tree4c3544ead51e6fabcec3716468d52ecf25099d8b
parentf9dfa226a56eb02f33e81aa675e1011fbcf405fe (diff)
downloadbun-13f62973128aea9266b43cc2e0de1e7bf1768b52.tar.gz
bun-13f62973128aea9266b43cc2e0de1e7bf1768b52.tar.zst
bun-13f62973128aea9266b43cc2e0de1e7bf1768b52.zip
Access object properties from macros
-rw-r--r--src/javascript/jsc/base.zig13
-rw-r--r--src/js_ast.zig119
2 files changed, 128 insertions, 4 deletions
diff --git a/src/javascript/jsc/base.zig b/src/javascript/jsc/base.zig
index a5f2d336d..b0583dc53 100644
--- a/src/javascript/jsc/base.zig
+++ b/src/javascript/jsc/base.zig
@@ -1360,6 +1360,16 @@ pub fn NewClass(
).rfn;
def.callAsFunction = callback;
+ } else if (comptime strings.eqlComptime(function_names[i], "hasProperty")) {
+ def.hasProperty = @field(staticFunctions, "hasProperty").rfn;
+ } else if (comptime strings.eqlComptime(function_names[i], "getProperty")) {
+ def.getProperty = @field(staticFunctions, "getProperty").rfn;
+ } else if (comptime strings.eqlComptime(function_names[i], "setProperty")) {
+ def.setProperty = @field(staticFunctions, "setProperty").rfn;
+ } else if (comptime strings.eqlComptime(function_names[i], "deleteProperty")) {
+ def.deleteProperty = @field(staticFunctions, "deleteProperty").rfn;
+ } else if (comptime strings.eqlComptime(function_names[i], "getPropertyNames")) {
+ def.getPropertyNames = @field(staticFunctions, "getPropertyNames").rfn;
} else {
const CtxField = @field(staticFunctions, function_names[i]);
if (comptime !@hasField(@TypeOf(CtxField), "rfn")) {
@@ -1540,7 +1550,7 @@ pub fn castObj(obj: js.JSObjectRef, comptime Type: type) *Type {
return JSPrivateDataPtr.from(js.JSObjectGetPrivate(obj)).as(Type);
}
const JSNode = @import("../../js_ast.zig").Macro.JSNode;
-
+const LazyPropertiesObject = @import("../../js_ast.zig").Macro.LazyPropertiesObject;
pub const JSPrivateDataPtr = TaggedPointerUnion(.{
ResolveError,
BuildError,
@@ -1551,6 +1561,7 @@ pub const JSPrivateDataPtr = TaggedPointerUnion(.{
Body,
Router,
JSNode,
+ LazyPropertiesObject,
});
pub inline fn GetJSPrivateData(comptime Type: type, ref: js.JSObjectRef) ?*Type {
diff --git a/src/js_ast.zig b/src/js_ast.zig
index 4e1f091d0..aabc756b6 100644
--- a/src/js_ast.zig
+++ b/src/js_ast.zig
@@ -4160,6 +4160,10 @@ pub const Macro = struct {
.get = JSBindings.getProperties,
.ro = true,
},
+ .propertyNodes = .{
+ .get = JSBindings.getPropertyNodes,
+ .ro = true,
+ },
},
);
@@ -4209,6 +4213,22 @@ pub const Macro = struct {
prop: js.JSStringRef,
exception: js.ExceptionRef,
) js.JSObjectRef {
+ if (this.data != .e_object) {
+ return js.JSObjectMake(ctx, null, null);
+ }
+
+ var lazy = getAllocator(ctx).create(LazyPropertiesObject) catch unreachable;
+ lazy.* = LazyPropertiesObject{ .node = this.* };
+ return LazyPropertiesObject.Class.make(ctx, lazy);
+ }
+
+ pub fn getPropertyNodes(
+ this: *JSNode,
+ ctx: js.JSContextRef,
+ thisObject: js.JSValueRef,
+ prop: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) js.JSObjectRef {
const args = if (this.data == .e_object) this.data.e_object.properties else &[_]G.Property{};
switch (args.len) {
@@ -4317,7 +4337,9 @@ pub const Macro = struct {
}
fn toObjectPrimitive(this: *JSNode, ctx: js.JSContextRef, obj: E.Object, exception: js.ExceptionRef) js.JSObjectRef {
- return toObjectValue(this, ctx, obj, exception);
+ var lazy = getAllocator(ctx).create(LazyPropertiesObject) catch unreachable;
+ lazy.* = LazyPropertiesObject{ .node = this.* };
+ return LazyPropertiesObject.Class.make(ctx, lazy);
}
fn toPropertyPrimitive(this: *JSNode, ctx: js.JSContextRef, prop: G.Property, exception: js.ExceptionRef) js.JSObjectRef {
@@ -4426,11 +4448,9 @@ pub const Macro = struct {
return JSBindings.toRegexValue(this, ctx, regex, exception);
},
.e_object => |object| {
- if (comptime !allow_recursion) return js.JSValueMakeUndefined(ctx);
return JSBindings.toObjectPrimitive(this, ctx, object.*, exception);
},
.e_array => |array| {
- if (comptime !allow_recursion) return js.JSValueMakeUndefined(ctx);
return JSBindings.toArrayPrimitive(this, ctx, array.*, exception);
},
@@ -6213,6 +6233,99 @@ pub const Macro = struct {
}
};
+ pub const LazyPropertiesObject = struct {
+ node: JSNode,
+
+ pub const Class = JSCBase.NewClass(
+ LazyPropertiesObject,
+ .{
+ .name = "LazyPropertiesObject",
+ .read_only = true,
+ },
+ .{
+ .getProperty = .{
+ .rfn = getProperty,
+ },
+ .hasProperty = .{
+ .rfn = hasProperty,
+ },
+ .getPropertyNames = .{
+ .rfn = getPropertyNames,
+ },
+ },
+ .{},
+ );
+
+ pub fn getProperty(
+ ctx: js.JSContextRef,
+ thisObject: js.JSObjectRef,
+ propertyName: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) callconv(.C) js.JSValueRef {
+ var this: *LazyPropertiesObject = JSCBase.GetJSPrivateData(LazyPropertiesObject, thisObject) orelse return null;
+
+ const len = js.JSStringGetLength(propertyName);
+ const properties = this.node.data.e_object.properties;
+ var ptr = js.JSStringGetCharacters8Ptr(propertyName);
+ var property_slice = ptr[0..len];
+ var value_node: JSNode = undefined;
+
+ for (properties) |property| {
+ const key = property.key orelse continue;
+ if (key.data != .e_string) continue;
+ const str = key.data.e_string.utf8;
+
+ if (strings.eql(property_slice, str)) {
+ const value = property.value orelse return js.JSValueMakeUndefined(ctx);
+ value_node = JSNode.initExpr(value);
+ return JSNode.JSBindings.toPrimitive(&value_node, ctx, exception);
+ }
+ }
+
+ return js.JSValueMakeUndefined(ctx);
+ }
+
+ pub fn hasProperty(
+ ctx: js.JSContextRef,
+ thisObject: js.JSObjectRef,
+ propertyName: js.JSStringRef,
+ ) callconv(.C) bool {
+ var this: *LazyPropertiesObject = JSCBase.GetJSPrivateData(LazyPropertiesObject, thisObject) orelse return false;
+
+ const len = js.JSStringGetLength(propertyName);
+ const properties = this.node.data.e_object.properties;
+ var ptr = js.JSStringGetCharacters8Ptr(propertyName);
+ var property_slice = ptr[0..len];
+
+ for (properties) |property| {
+ const key = property.key orelse continue;
+ if (key.data != .e_string) continue;
+ const str = key.data.e_string.utf8;
+
+ if (strings.eql(property_slice, str)) return true;
+ }
+
+ return false;
+ }
+
+ pub fn getPropertyNames(
+ ctx: js.JSContextRef,
+ thisObject: js.JSObjectRef,
+ props: js.JSPropertyNameAccumulatorRef,
+ ) callconv(.C) void {
+ var this: *LazyPropertiesObject = JSCBase.GetJSPrivateData(LazyPropertiesObject, thisObject) orelse return;
+
+ const properties = this.node.data.e_object.properties;
+
+ for (properties) |property| {
+ const key = property.key orelse continue;
+ if (key.data != .e_string) continue;
+ const str = key.data.e_string.utf8;
+ js.JSPropertyNameAccumulatorAddName(props, js.JSStringCreateStatic(str.ptr, str.len));
+ }
+ }
+ };
+
resolver: *Resolver,
vm: *JavaScript.VirtualMachine = undefined,