@@ -337,6 +337,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
337337 const env = self .env ;
338338 const isolate = env .isolate ;
339339 const Global = @TypeOf (global .* );
340+ const templates = & self .env .templates ;
340341
341342 var v8_context : v8.Context = blk : {
342343 var temp_scope : v8.HandleScope = undefined ;
@@ -351,7 +352,6 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
351352
352353 // All the FunctionTemplates that we created and setup in Env.init
353354 // are now going to get associated with our global instance.
354- const templates = & self .env .templates ;
355355 inline for (Types , 0.. ) | s , i | {
356356 const Struct = s .defaultValue ().? ;
357357 const class_name = v8 .String .initUtf8 (isolate , comptime classNameForStruct (Struct ));
@@ -463,6 +463,38 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
463463 }
464464 }
465465
466+ // Primitive attributes are set directly on the FunctionTemplate
467+ // when we setup the environment. But we cannot set more complex
468+ // types (v8 will crash).
469+ //
470+ // Plus, just to create more complex types, we always need a
471+ // context, i.e. an Array has to have a Context to exist.
472+ //
473+ // As far as I can tell, getting the FunctionTemplate's object
474+ // and setting values directly on it, for each context, is the
475+ // way to do this.
476+ inline for (Types , 0.. ) | s , i | {
477+ const Struct = s .defaultValue ().? ;
478+ inline for (@typeInfo (Struct ).@"struct" .decls ) | declaration | {
479+ const name = declaration .name ;
480+ if (comptime name [0 ] == '_' ) {
481+ const value = @field (Struct , name );
482+
483+ if (comptime isComplexAttributeType (@typeInfo (@TypeOf (value )))) {
484+ const js_obj = templates [i ].getFunction (v8_context ).toObject ();
485+ const js_name = v8 .String .initUtf8 (isolate , name [1.. ]).toName ();
486+ const js_val = try js_context .zigValueToJs (value );
487+ if (! js_obj .setValue (v8_context , js_name , js_val )) {
488+ log .fatal (.app , "set class attribute" , .{
489+ .@"struct" = @typeName (Struct ),
490+ .name = name ,
491+ });
492+ }
493+ }
494+ }
495+ }
496+ }
497+
466498 _ = try js_context ._mapZigInstanceToJs (v8_context .getGlobal (), global );
467499 return js_context ;
468500 }
@@ -1809,7 +1841,9 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
18091841 if (comptime name [0 ] == '_' ) {
18101842 switch (@typeInfo (@TypeOf (@field (Struct , name )))) {
18111843 .@"fn" = > generateMethod (Struct , name , isolate , template_proto ),
1812- else = > generateAttribute (Struct , name , isolate , template , template_proto ),
1844+ else = > | ti | if (! comptime isComplexAttributeType (ti )) {
1845+ generateAttribute (Struct , name , isolate , template , template_proto );
1846+ },
18131847 }
18141848 } else if (comptime std .mem .startsWith (u8 , name , "get_" )) {
18151849 generateProperty (Struct , name [4.. ], isolate , template_proto );
@@ -1930,7 +1964,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
19301964 // apply it both to the type itself
19311965 template .set (js_name , js_value , v8 .PropertyAttribute .ReadOnly + v8 .PropertyAttribute .DontDelete );
19321966
1933- // andto instances of the type
1967+ // and to instances of the type
19341968 template_proto .set (js_name , js_value , v8 .PropertyAttribute .ReadOnly + v8 .PropertyAttribute .DontDelete );
19351969 }
19361970
@@ -2396,6 +2430,20 @@ fn isEmpty(comptime T: type) bool {
23962430 return @typeInfo (T ) != .@"opaque" and @sizeOf (T ) == 0 and @hasDecl (T , "js_legacy_factory" ) == false ;
23972431}
23982432
2433+ // Attributes that return a primitive type are setup directly on the
2434+ // FunctionTemplate when the Env is setup. More complex types need a v8.Context
2435+ // and cannot be set directly on the FunctionTemplate.
2436+ // We default to saying types are primitives because that's mostly what
2437+ // we have. If we add a new complex type that isn't explictly handled here,
2438+ // we'll get a compiler error in simpleZigValueToJs, and can then explicitly
2439+ // add the type here.
2440+ fn isComplexAttributeType (ti : std.builtin.Type ) bool {
2441+ return switch (ti ) {
2442+ .array = > true ,
2443+ else = > false ,
2444+ };
2445+ }
2446+
23992447// Responsible for calling Zig functions from JS invokations. This could
24002448// probably just contained in ExecutionWorld, but having this specific logic, which
24012449// is somewhat repetitive between constructors, functions, getters, etc contained
0 commit comments