Fix SX client navigation: path-derived names, provide clash, component expansion

- inject_path_name: strip _islands/ convention dirs from path-derived names
- page-functions.sx: fix geography (→ ~geography) and isomorphism (→ ~etc/plan/isomorphic)
- request-handler.sx: rewrite sx-eval-page to call page functions explicitly
  via env-get+apply, avoiding provide special form intercepting (provide) calls
- sx_server.ml: set expand-components? on AJAX aser paths so server-side
  components expand for the browser (islands stay unexpanded for hydration)
- Rename 19 component references in geography/spreads, geography/provide,
  geography/scopes to use path-qualified names matching inject_path_name output

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-18 10:19:00 +00:00
parent 9e0de8831f
commit ac65666f6f
7 changed files with 400 additions and 264 deletions

View File

@@ -1240,6 +1240,9 @@ let inject_path_name expr path base_dir =
let stem = if Filename.check_suffix rel ".sx"
then String.sub rel 0 (String.length rel - 3)
else rel in
(* Strip _islands/ convention directories from the path *)
let stem = let parts = String.split_on_char '/' stem in
String.concat "/" (List.filter (fun p -> p <> "_islands") parts) in
(* index files are known by their directory *)
let name = if Filename.basename stem = "index"
then let d = Filename.dirname stem in
@@ -2165,10 +2168,14 @@ let http_render_page env path headers =
let inner_layout = get_app_str "inner-layout" "~layouts/doc" in
let wrapped = List [Symbol inner_layout; Keyword "path"; String nav_path; page_ast] in
if is_ajax then begin
(* AJAX: return SX wire format (aser output) with text/sx content type *)
(* AJAX: return SX wire format (aser output) with text/sx content type.
Expand server-side components so the browser doesn't need their definitions.
Islands stay as (~ ...) calls — the browser hydrates those. *)
ignore (env_bind env "expand-components?" (NativeFn ("expand-components?", fun _args -> Bool true)));
let body_result =
let call = List [Symbol "aser"; List [Symbol "quote"; wrapped]; Env env] in
eval_with_io_render call env in
Hashtbl.remove env.bindings (Sx_types.intern "expand-components?");
let body_str = match body_result with
| String s | SxExpr s -> s | _ -> serialize_value body_result in
let t1 = Unix.gettimeofday () in
@@ -4078,6 +4085,7 @@ let http_mode port =
if is_ajax then begin
(* AJAX streaming: evaluate shell + data + content synchronously,
return fully-resolved SX wire format (no chunked transfer). *)
ignore (env_bind env "expand-components?" (NativeFn ("expand-components?", fun _args -> Bool true)));
let response = try
let page_def = match env_get env ("page:" ^ sname) with Dict d -> d | _ -> raise Not_found in
let shell_ast = match Hashtbl.find_opt page_def "shell" with Some v -> v | None -> Nil in