From 31ae9b5110cee597f26711c12e46c0e06eb9a869 Mon Sep 17 00:00:00 2001 From: giles Date: Sat, 28 Mar 2026 19:04:54 +0000 Subject: [PATCH] sx-http: fix serialize_value + include all defines in component-defs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit serialize_value: all lists emit (items...) not (list items...), matching Python serialize() exactly. Empty lists emit (). This fixes let bindings, fn params, and data structures for client-side parsing. Component-defs now include named lambdas, macros, dicts, and other named values from the env — client needs CSSX functions (cssx-process-token, cssx-colour-props, cssx-spacing-props etc.) for island hydration. Fixes: cssx-process-token, cssx-colour-props undefined errors. Geography page: fully rendered with header island hydration working. Homepage: nav renders, no error banners, stepper silent. Co-Authored-By: Claude Opus 4.6 (1M context) --- hosts/ocaml/bin/sx_server.ml | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/hosts/ocaml/bin/sx_server.ml b/hosts/ocaml/bin/sx_server.ml index f82a0df4..3860b652 100644 --- a/hosts/ocaml/bin/sx_server.ml +++ b/hosts/ocaml/bin/sx_server.ml @@ -53,14 +53,10 @@ let rec serialize_value = function | Symbol s -> s | Keyword k -> ":" ^ k | List items | ListRef { contents = items } -> - (* Lists with a symbol head are call expressions: (fn arg1 arg2). - Lists starting with data values are data: (list 1 2 3). - This distinction matters for the client parser. *) - (match items with - | (Symbol _ | Keyword _) :: _ -> - "(" ^ String.concat " " (List.map serialize_value items) ^ ")" - | _ -> - "(list " ^ String.concat " " (List.map serialize_value items) ^ ")") + (* All lists: (items...) — no (list ...) wrapper. + Matches Python serialize() exactly. The SX source code itself uses + (list ...) where data lists are needed; the serializer preserves AST. *) + "(" ^ String.concat " " (List.map serialize_value items) ^ ")" | Dict d -> let pairs = Hashtbl.fold (fun k v acc -> (Printf.sprintf ":%s %s" k (serialize_value v)) :: acc) d [] in @@ -1635,7 +1631,8 @@ let read_css_file path = let http_inject_shell_statics env static_dir sx_sxc = (* Component definitions for client *) let buf = Buffer.create 65536 in - Hashtbl.iter (fun _sym v -> + Hashtbl.iter (fun sym v -> + let name = Sx_types.unintern sym in match v with | Component c -> let ps = String.concat " " ( @@ -1649,6 +1646,22 @@ let http_inject_shell_statics env static_dir sx_sxc = (if i.i_has_children then ["&rest"; "children"] else [])) in Buffer.add_string buf (Printf.sprintf "(defisland ~%s (%s) %s)\n" i.i_name ps (serialize_value i.i_body)) + | Lambda l when l.l_name <> None -> + (* Named lambdas — client needs utility functions like cssx-process-token *) + let fn_name = match l.l_name with Some n -> n | None -> name in + let ps = String.concat " " l.l_params in + Buffer.add_string buf (Printf.sprintf "(define %s (fn (%s) %s))\n" + fn_name ps (serialize_value l.l_body)) + | Macro m -> + let ps = String.concat " " m.m_params in + let mname = match m.m_name with Some n -> n | None -> name in + Buffer.add_string buf (Printf.sprintf "(defmacro %s (%s) %s)\n" + mname ps (serialize_value m.m_body)) + | Dict _ | Number _ | String _ | Bool _ | List _ | ListRef _ -> + (* Named values (dicts, lists, constants) — client needs CSSX config etc. *) + if String.length name > 0 && name.[0] <> '_' && name.[0] <> '*' then + Buffer.add_string buf (Printf.sprintf "(define %s %s)\n" + name (serialize_value v)) | _ -> () ) env.bindings; let raw_defs = Buffer.contents buf in