refactor: preli syntaxual update for zig 0.17

This commit is contained in:
Nurul Huda (Apon) 2026-06-16 01:22:22 +06:00
parent 50eb794479
commit 3b42e9890d
No known key found for this signature in database
GPG Key ID: 5D3F1DE2855A2F79
12 changed files with 82 additions and 86 deletions

View File

@ -2,10 +2,6 @@ pub fn Layout(ctx: zx.LayoutContext, children: zx.Component) zx.Component {
return (
<fragment @allocator={ctx.arena}>
{children}
<div>
<p>Extra data to match with the content size of Next.js</p>
<span>{comptime "ABC" ** 330}</span>
</div>
</fragment>
);
}

View File

@ -79,7 +79,7 @@ pub fn build(b: *std.Build) !void {
}
inline fn fileExists(b: *std.Build, filename: []const u8) bool {
const dir = b.build_root.handle;
const dir = b.root.root_dir.handle;
dir.access(b.graph.io, filename, .{}) catch return false;
return true;
}

View File

@ -79,7 +79,7 @@ pub fn build(b: *std.Build) !void {
}
inline fn fileExists(b: *std.Build, filename: []const u8) bool {
const dir = b.build_root.handle;
const dir = b.root.root_dir.handle;
dir.access(b.graph.io, filename, .{}) catch return false;
return true;
}

View File

@ -44,14 +44,14 @@ pub const Component = union(enum) {
pub fn init(comptime func: anytype, name: []const u8, allocator: Allocator, props: anytype) ComponentFn {
const FuncInfo = @typeInfo(@TypeOf(func));
const param_count = FuncInfo.@"fn".params.len;
const param_count = FuncInfo.@"fn".param_types.len;
const fn_name = @typeName(@TypeOf(func));
// Validation of parameters
if (param_count != 1 and param_count != 2)
@compileError(std.fmt.comptimePrint("{s} must have 1 or 2 parameters found {d} parameters", .{ fn_name, param_count }));
const FirstPropType = FuncInfo.@"fn".params[0].type.?;
const FirstPropType = FuncInfo.@"fn".param_types[0].?;
const first_is_allocator = FirstPropType == std.mem.Allocator;
const first_is_ctx_ptr = @typeInfo(FirstPropType) == .pointer and
@hasField(@typeInfo(FirstPropType).pointer.child, "allocator") and
@ -62,7 +62,7 @@ pub const Component = union(enum) {
// If two parameters are passed with allocator first, the props type must be a struct
if (first_is_allocator and param_count == 2) {
const SecondPropType = FuncInfo.@"fn".params[1].type.?;
const SecondPropType = FuncInfo.@"fn".param_types[1].?;
if (@typeInfo(SecondPropType) != .@"struct")
@compileError("Component" ++ fn_name ++ " must have a struct as the second parameter, found " ++ @typeName(SecondPropType));
}
@ -73,7 +73,7 @@ pub const Component = union(enum) {
// Allocate props on heap to persist
const props_copy = if (first_is_allocator and param_count == 2) blk: {
const SecondPropType = FuncInfo.@"fn".params[1].type.?;
const SecondPropType = FuncInfo.@"fn".param_types[1].?;
const coerced = prp.coerceProps(SecondPropType, props);
const p = allocator.create(SecondPropType) catch @panic("OOM");
p.* = coerced;
@ -140,7 +140,7 @@ pub const Component = union(enum) {
return normalize(func(alloc));
}
if (first_is_allocator and param_count == 2) {
const SecondPropType = FuncInfo.@"fn".params[1].type.?;
const SecondPropType = FuncInfo.@"fn".param_types[1].?;
const p = propsPtr orelse @panic("propsPtr is null for function with props");
const typed_p: *const SecondPropType = @ptrCast(@alignCast(p));
return normalize(func(alloc, typed_p.*));
@ -166,7 +166,7 @@ pub const Component = union(enum) {
return;
}
if (first_is_allocator and param_count == 2) {
const SecondPropType = FuncInfo.@"fn".params[1].type.?;
const SecondPropType = FuncInfo.@"fn".param_types[1].?;
const p = propsPtr orelse @panic("propsPtr is null for function with props");
const typed_p: *const SecondPropType = @ptrCast(@alignCast(p));
alloc.destroy(typed_p);
@ -235,7 +235,6 @@ pub const Component = union(enum) {
/// Recursively search for an element by tag name
/// Returns a mutable pointer to the Component if found, null otherwise
pub const SerializeOptions = struct {
only_components: bool = true,
include_props: bool = true,

View File

@ -109,7 +109,7 @@ pub fn ComponentCtx(comptime PropsType: type) type {
.pointer => |p| p.child,
else => @compileError(BindSignMsg ++ @typeName(HandlerType)),
};
const params = @typeInfo(FnType).@"fn".params;
const params = @typeInfo(FnType).@"fn".param_types;
return switch (FnType) {
// Client
@ -126,13 +126,13 @@ pub fn ComponentCtx(comptime PropsType: type) type {
fn (*ActionContext) void => actionBind(handler, alloc, self),
else => blk: {
if (comptime params.len == 1 and params[0].type.? == *ServerEvent) {
if (comptime params.len == 1 and params[0] == *ServerEvent) {
break :blk zx.EventHandler.server(handler, alloc, &self._internal.handler_idx);
}
if (comptime params.len == 2 and
@typeInfo(params[0].type.?) == .@"struct" and
params[0].type.? != ActionContext and
params[1].type.? == *StateContext)
@typeInfo(params[0]) == .@"struct" and
params[0] != ActionContext and
params[1] == *StateContext)
{
break :blk actionBind(handler, alloc, self);
}
@ -144,10 +144,10 @@ pub fn ComponentCtx(comptime PropsType: type) type {
}
fn actionBind(comptime handler: anytype, alloc: Allocator, ctx: anytype) zx.EventHandler {
const params = @typeInfo(@TypeOf(handler)).@"fn".params;
const arg0 = params[0].type.?;
const params = @typeInfo(@TypeOf(handler)).@"fn".param_types;
const arg0 = params[0];
if (comptime params.len == 2 and params[1].type.? == *StateContext and
if (comptime params.len == 2 and params[1] == *StateContext and
(arg0 == ActionContext or @typeInfo(arg0) == .@"struct"))
{
const FormActionWrapper = struct {

View File

@ -43,10 +43,11 @@ pub const ComponentSerializable = struct {
const ti = @typeInfo(T);
if (ti != .@"struct") return &[_]StateItem{};
const fields = ti.@"struct".fields;
var items = try allocator.alloc(StateItem, fields.len);
inline for (fields, 0..) |field, i| {
items[i] = try toStateItem(allocator, field.type, field.name, @field(value, field.name), 0);
const field_names = ti.@"struct".field_names;
const field_types = ti.@"struct".field_types;
var items = try allocator.alloc(StateItem, field_names.len);
inline for (field_names, 0..) |name, i| {
items[i] = try toStateItem(allocator, field_types[i], name, @field(value, name), 0);
}
return items;
}
@ -55,17 +56,17 @@ pub const ComponentSerializable = struct {
return struct {
fn getStateItems(alloc: Allocator, ptr: *const anyopaque) anyerror![]const StateItem {
const FuncInfo = @typeInfo(@TypeOf(func));
const param_count = FuncInfo.@"fn".params.len;
const param_count = FuncInfo.@"fn".param_types.len;
if (param_count == 0) return &[_]StateItem{};
const FirstPropType = FuncInfo.@"fn".params[0].type.?;
const FirstPropType = FuncInfo.@"fn".param_types[0].?;
const first_is_allocator = FirstPropType == std.mem.Allocator;
const first_is_ctx_ptr = @typeInfo(FirstPropType) == .pointer and
@hasField(@typeInfo(FirstPropType).pointer.child, "allocator") and
@hasField(@typeInfo(FirstPropType).pointer.child, "children");
if (first_is_allocator and param_count == 2) {
const SecondPropType = FuncInfo.@"fn".params[1].type.?;
const SecondPropType = FuncInfo.@"fn".param_types[1];
const typed_p: *const SecondPropType = @ptrCast(@alignCast(ptr));
return toStateItems(alloc, SecondPropType, typed_p.*);
} else if (first_is_ctx_ptr) {
@ -121,9 +122,9 @@ pub const ComponentSerializable = struct {
switch (ti) {
.@"struct" => |s| {
item.value = "Object";
var children = try allocator.alloc(StateItem, s.fields.len);
inline for (s.fields, 0..) |field, i| {
children[i] = try toStateItem(allocator, field.type, field.name, @field(value, field.name), depth + 1);
var children = try allocator.alloc(StateItem, s.field_types.len);
inline for (s.field_types, 0..) |field_type, i| {
children[i] = try toStateItem(allocator, field_type, s.field_names[i], @field(value, s.field_names[i]), depth + 1);
}
item.children = children;
},

View File

@ -11,16 +11,16 @@ pub fn coerceProps(comptime TargetType: type, props: anytype) TargetType {
@compileError("Target type must be a struct");
}
const fields = TargetInfo.@"struct".fields;
const target_struct = TargetInfo.@"struct";
var result: TargetType = undefined;
inline for (fields) |field| {
if (@hasField(@TypeOf(props), field.name)) {
@field(result, field.name) = @field(props, field.name);
} else if (field.defaultValue()) |default_value| {
@field(result, field.name) = default_value;
inline for (target_struct.field_names) |field_name| {
if (@hasField(@TypeOf(props), field_name)) {
@field(result, field_name) = @field(props, field_name);
} else if (@field(target_struct, field_name).defaultValue()) |default_value| {
@field(result, field_name) = default_value;
} else {
@compileError(std.fmt.comptimePrint("Missing required attribute `{s}` in Component `{s}`", .{ field.name, @typeName(TargetType) }));
@compileError(std.fmt.comptimePrint("Missing required attribute `{s}` in Component `{s}`", .{ field_name, @typeName(TargetType) }));
}
}
@ -63,7 +63,7 @@ pub fn propsSerializer(comptime Props: type, allocator: std.mem.Allocator, props
const type_info = @typeInfo(Props);
if (type_info != .@"struct") return .{ .ptr = null, .writeFn = null };
if (type_info.@"struct".fields.len == 0) return .{ .ptr = null, .writeFn = null };
if (type_info.@"struct".field_types.len == 0) return .{ .ptr = null, .writeFn = null };
if (!comptime isSerializable(Props)) {
return .{ .ptr = null, .writeFn = null };
}
@ -92,8 +92,8 @@ pub fn MergedPropsType(comptime BaseType: type, comptime OverrideType: type) typ
@compileError("MergedPropsType expects struct types");
}
const base_fields = base_info.@"struct".fields;
const override_fields = override_info.@"struct".fields;
const base_fields = base_info.@"struct".field_types;
const override_fields = override_info.@"struct".field_types;
// Count unique fields (override fields replace base fields with same name)
comptime var field_count = base_fields.len;
@ -195,8 +195,8 @@ fn isSerializableImpl(comptime T: type, comptime visited: []const type) bool {
.array => |arr| isSerializableImpl(arr.child, new_visited),
.optional => |opt| isSerializableImpl(opt.child, new_visited),
.@"struct" => |s| blk: {
for (s.fields) |field| {
if (!isSerializableImpl(field.type, new_visited)) break :blk false;
for (s.field_types) |field_type| {
if (!isSerializableImpl(field_type, new_visited)) break :blk false;
}
break :blk true;
},

View File

@ -26,12 +26,12 @@ pub const ComponentMeta = struct {
@compileError("Client.ComponentMeta.init requires a function");
}
const param_count = FuncInfo.@"fn".params.len;
const param_count = FuncInfo.@"fn".param_types.len;
if (param_count < 1 or param_count > 2) {
@compileError("Component function must have 1 or 2 parameters");
}
const FirstParamType = FuncInfo.@"fn".params[0].type.?;
const FirstParamType = FuncInfo.@"fn".param_types[0].?;
const first_is_allocator = FirstParamType == std.mem.Allocator;
const first_is_ctx_ptr = @typeInfo(FirstParamType) == .pointer and
@hasField(@typeInfo(FirstParamType).pointer.child, "allocator") and
@ -72,7 +72,7 @@ pub const ComponentMeta = struct {
// Case 2: Component takes allocator and props - fn Component(allocator, props) Component
if (first_is_allocator and param_count == 2) {
const PropsType = FuncInfo.@"fn".params[1].type.?;
const PropsType = FuncInfo.@"fn".param_types[1].?;
const props = if (props_json) |pj| zx.util.zxon.parse(PropsType, allocator, pj, .{}) catch std.mem.zeroes(PropsType) else std.mem.zeroes(PropsType);
return normalizeResult(func(allocator, props));
}

View File

@ -744,13 +744,13 @@ pub const ServerMeta = struct {
const FnType = @TypeOf(pageFn);
const fn_info = @typeInfo(FnType).@"fn";
const R = fn_info.return_type.?;
const n_params = fn_info.params.len;
const n_params = fn_info.param_types.len;
return struct {
fn wrapper(ctx: zx.PageContext, app_ptr: ?*const anyopaque, state_ptr: ?*const anyopaque) anyerror!Component {
if (is_md) {
// TODO: figure out a better design for page.mdzx file, we need a better way to use PageContext in md file without magic
const CtxType = fn_info.params[0].type.?;
const CtxType = fn_info.param_types[0].?;
const CCtxType = @typeInfo(CtxType).pointer.child;
const allocator = ctx.arena;
const cctx = (allocator.create(CCtxType) catch @panic("OOM"));
@ -763,12 +763,12 @@ pub const ServerMeta = struct {
if (R == Component) return pageFn(ctx) else return try pageFn(ctx);
}
if (n_params == 2) {
const app = injectApp(fn_info.params[1].type.?, app_ptr);
const app = injectApp(fn_info.param_types[1].?, app_ptr);
if (R == Component) return pageFn(ctx, app) else return try pageFn(ctx, app);
}
if (n_params == 3) {
const app = injectApp(fn_info.params[1].type.?, app_ptr);
const state = injectState(fn_info.params[2].type.?, state_ptr);
const app = injectApp(fn_info.param_types[1].?, app_ptr);
const state = injectState(fn_info.param_types[2].?, state_ptr);
if (R == Component) return pageFn(ctx, app, state) else return try pageFn(ctx, app, state);
}
@compileError("Page function must have 1-3 parameters: (ctx, app?, state?)");
@ -782,7 +782,7 @@ pub const ServerMeta = struct {
const layoutFn = T.Layout;
const FnType = @TypeOf(layoutFn);
const fn_info = @typeInfo(FnType).@"fn";
const n_params = fn_info.params.len;
const n_params = fn_info.param_types.len;
return struct {
fn wrapper(ctx: zx.LayoutContext, component: Component, app_ptr: ?*const anyopaque, state_ptr: ?*const anyopaque) Component {
@ -790,12 +790,12 @@ pub const ServerMeta = struct {
return layoutFn(ctx, component);
}
if (n_params == 3) {
const app = injectApp(fn_info.params[2].type.?, app_ptr);
const app = injectApp(fn_info.param_types[2].?, app_ptr);
return layoutFn(ctx, component, app);
}
if (n_params == 4) {
const app = injectApp(fn_info.params[2].type.?, app_ptr);
const state = injectState(fn_info.params[3].type.?, state_ptr);
const app = injectApp(fn_info.param_types[2].?, app_ptr);
const state = injectState(fn_info.param_types[3].?, state_ptr);
return layoutFn(ctx, component, app, state);
}
@compileError("Layout function must have 2-4 parameters: (ctx, children, app?, state?)");
@ -834,15 +834,15 @@ pub const ServerMeta = struct {
pub fn mapStruct(comptime T: type, src: anytype) T {
var out: T = .{};
const S = @TypeOf(src);
inline for (@typeInfo(T).@"struct".fields) |f| {
if (comptime T == httpz.Config and std.mem.eql(u8, f.name, "address")) {
inline for (@typeInfo(T).@"struct".field_names, @typeInfo(T).@"struct".field_types) |field_name, field_type| {
if (comptime T == httpz.Config and std.mem.eql(u8, field_name, "address")) {
// handled after the loop because our app config stores host/port
// separately while httpz expects a tagged union
} else if (@hasField(S, f.name)) {
const sv = @field(src, f.name);
switch (@typeInfo(f.type)) {
.@"struct" => @field(out, f.name) = mapStruct(f.type, sv),
else => @field(out, f.name) = sv,
} else if (@hasField(S, field_name)) {
const sv = @field(src, field_name);
switch (@typeInfo(field_type)) {
.@"struct" => @field(out, field_name) = mapStruct(field_type, sv),
else => @field(out, field_name) = sv,
}
}
}

View File

@ -25,9 +25,9 @@ fn writeValue(comptime T: type, value: T, w: *std.Io.Writer) anyerror!void {
switch (@typeInfo(T)) {
.@"struct" => |s| {
try w.writeByte('[');
inline for (s.fields, 0..) |field, i| {
inline for (s.field_names, s.field_types, 0..) |field_name, field_type, i| {
if (i > 0) try w.writeByte(',');
try writeValue(field.type, @field(value, field.name), w);
try writeValue(field_type, @field(value, field_name), w);
}
try w.writeByte(']');
},
@ -112,9 +112,9 @@ fn readValue(comptime T: type, allocator: std.mem.Allocator, d: []const u8, p: *
skip(d, p);
var result: T = undefined;
inline for (s.fields, 0..) |field, i| {
inline for (s.field_names, s.field_types, 0..) |field_name, field_type, i| {
if (i > 0) comma(d, p);
@field(result, field.name) = try readValue(field.type, allocator, d, p);
@field(result, field_name) = try readValue(field_type, allocator, d, p);
}
skip(d, p);

View File

@ -235,9 +235,9 @@ const Context = struct {
}
// Function pointer - treat as event handler
if (@typeInfo(ptr_info.child) == .@"fn") {
const fn_params = @typeInfo(ptr_info.child).@"fn".params;
const fn_params = @typeInfo(ptr_info.child).@"fn".param_types;
const takes_ptr = fn_params.len == 1 and
@typeInfo(fn_params[0].type.?) == .pointer;
@typeInfo(fn_params[0].?) == .pointer;
const handler = if (takes_ptr)
zx.EventHandler.runtimePtr(val)
else
@ -515,8 +515,8 @@ const Context = struct {
const allocator = self.getAlloc();
const FuncInfo = @typeInfo(@TypeOf(func));
const param_count = FuncInfo.@"fn".params.len;
const FirstPropType = FuncInfo.@"fn".params[0].type.?;
const param_count = FuncInfo.@"fn".param_types.len;
const FirstPropType = FuncInfo.@"fn".param_types[0].?;
const first_is_ctx_ptr = @typeInfo(FirstPropType) == .pointer and
@hasField(@typeInfo(FirstPropType).pointer.child, "allocator") and
@hasField(@typeInfo(FirstPropType).pointer.child, "children");
@ -524,7 +524,7 @@ const Context = struct {
const name = options.name orelse "";
// Context-based component or function with props parameter
var comp_fn = if (first_is_ctx_ptr or param_count == 2) blk: {
const PropsType = if (first_is_ctx_ptr) @TypeOf(props) else FuncInfo.@"fn".params[1].type.?;
const PropsType = if (first_is_ctx_ptr) @TypeOf(props) else FuncInfo.@"fn".param_types[1].?;
const coerced_props = prp.coerceProps(PropsType, props);
break :blk Component.ComponentFn.init(func, name, allocator, coerced_props);
} else blk: {
@ -567,7 +567,7 @@ const Context = struct {
}
}
} else if (param_count == 2) {
const FullPropsType = FuncInfo.@"fn".params[1].type.?;
const FullPropsType = FuncInfo.@"fn".param_types[1].?;
if (@typeInfo(FullPropsType) == .@"struct") {
const full_props = prp.coerceProps(FullPropsType, props);
break :blk prp.propsSerializer(FullPropsType, allocator, full_props);

View File

@ -82,18 +82,18 @@ pub fn callAlloc(
// Build our arguments.
const argsInfo = @typeInfo(@TypeOf(args)).@"struct";
assert(argsInfo.is_tuple);
var js_args: [argsInfo.fields.len]js.Value = undefined;
inline for (argsInfo.fields, 0..) |field, i| {
js_args[i] = switch (field.type) {
js.Object => @field(args, field.name).value,
else => js.Value.init(@field(args, field.name)),
var js_args: [argsInfo.field_types.len]js.Value = undefined;
inline for (argsInfo.field_types, 0..) |field_type, i| {
js_args[i] = switch (field_type) {
js.Object => @field(args, argsInfo.field_names[i]).value,
else => js.Value.init(@field(args, argsInfo.field_names[i])),
};
}
// We need to free all the arguments given to use that weren't
// already js.Objects. If they were, its up to the caller to free.
defer inline for (argsInfo.fields, 0..) |field, i| {
if (field.type != js.Object) js_args[i].deinit();
defer inline for (argsInfo.field_types, 0..) |field_type, i| {
if (field_type != js.Object) js_args[i].deinit();
};
// Invoke
@ -112,18 +112,18 @@ pub fn new(
// Build our arguments.
const argsInfo = @typeInfo(@TypeOf(args)).@"struct";
assert(argsInfo.is_tuple);
var js_args: [argsInfo.fields.len]js.Value = undefined;
inline for (argsInfo.fields, 0..) |field, i| {
js_args[i] = switch (field.type) {
js.Object => @field(args, field.name).value,
else => js.Value.init(@field(args, field.name)),
var js_args: [argsInfo.field_types.len]js.Value = undefined;
inline for (argsInfo.field_types, 0..) |field_type, i| {
js_args[i] = switch (field_type) {
js.Object => @field(args, argsInfo.field_names[i]).value,
else => js.Value.init(@field(args, argsInfo.field_names[i])),
};
}
// We need to free all the arguments given to use that weren't
// already js.Objects. If they were, its up to the caller to free.
defer inline for (argsInfo.fields, 0..) |field, i| {
if (field.type != js.Object) js_args[i].deinit();
defer inline for (argsInfo.field_types, 0..) |field_type, i| {
if (field_type != js.Object) js_args[i].deinit();
};
// Invoke