Files
rose-ash/web/request-handler.sx
giles 394c86b474 sx-http: SX request handler — move routing logic from OCaml to SX
New web/request-handler.sx: configurable SX function (sx-handle-request)
that receives path + headers + env and returns rendered HTML.
The handler decides full page vs AJAX fragment.

OCaml server: http_render_page now just calls the SX handler.
All routing, layout selection, AJAX detection moved to SX.
Header parsing added. is_sx_request removed from OCaml.

Configurable via SX_REQUEST_HANDLER env var (default: sx-handle-request).

WIP: handler has parse errors on some URL formats. Needs debugging.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 07:45:57 +00:00

104 lines
3.5 KiB
Plaintext

(define
sx-handle-request
(fn
(path headers env)
(let
((is-ajax (or (has-key? headers "sx-request") (has-key? headers "hx-request")))
(path-expr (sx-parse-url path))
(page-ast (sx-eval-page path-expr env)))
(if
(nil? page-ast)
nil
(let
((nav-path (if (starts-with? path "/sx/") path (str "/sx" path))))
(if
is-ajax
(sx-render-ajax page-ast nav-path env)
(sx-render-full-page page-ast nav-path env)))))))
(define
sx-parse-url
(fn
(path)
(let
((p (cond (or (= path "/") (= path "/sx/") (= path "/sx")) "home" (starts-with? path "/sx/") (substring path 4 (string-length path)) (starts-with? path "/") (substring path 1 (string-length path)) :else path)))
(let ((spaced (join " " (split p ".")))) spaced))))
(define
sx-eval-page
(fn
(path-expr env)
(let
((exprs (sx-parse path-expr)))
(when
(not (empty? exprs))
(let
((expr (if (= (len exprs) 1) (first exprs) exprs))
(quoted (sx-auto-quote expr env)))
(let
((callable (if (symbol? quoted) (list quoted) quoted)))
(cek-try (fn () (eval-expr callable env)) (fn (err) nil))))))))
(define
sx-auto-quote
(fn
(expr env)
(cond
(and (symbol? expr) (not (env-has? env (symbol-name expr))))
(symbol-name expr)
(list? expr)
(map (fn (e) (sx-auto-quote e env)) expr)
:else expr)))
(define
sx-render-ajax
(fn
(page-ast nav-path env)
(let
((wrapped (list (make-symbol "~layouts/doc") :path nav-path page-ast))
(aser-result (aser (list (make-symbol "quote") wrapped) env)))
(let
((body-exprs (sx-parse aser-result)))
(let
((body-expr (if (= (len body-exprs) 1) (first body-exprs) (cons (make-symbol "<>") body-exprs))))
(render-to-html body-expr env))))))
(define
sx-render-full-page
(fn
(page-ast nav-path env)
(let
((wrapped (list (make-symbol "~layouts/doc") :path nav-path page-ast))
(full-ast
(list (make-symbol "~shared:layout/app-body") :content wrapped)))
(let
((aser-result (aser (list (make-symbol "quote") full-ast) env)))
(let
((body-exprs (sx-parse aser-result)))
(let
((body-expr (if (= (len body-exprs) 1) (first body-exprs) (cons (make-symbol "<>") body-exprs))))
(let
((body-html (render-to-html body-expr env))
(page-source (serialize full-ast)))
(~shared:shell/sx-page-shell
:title "SX"
:csrf ""
:page-sx page-source
:body-html body-html
:component-defs __shell-component-defs
:component-hash __shell-component-hash
:pages-sx __shell-pages-sx
:sx-css __shell-sx-css
:sx-css-classes __shell-sx-css-classes
:asset-url __shell-asset-url
:sx-js-hash __shell-sx-js-hash
:body-js-hash __shell-body-js-hash
:wasm-hash __shell-wasm-hash
:head-scripts __shell-head-scripts
:body-scripts __shell-body-scripts
:inline-css __shell-inline-css
:inline-head-js __shell-inline-head-js
:init-sx __shell-init-sx
:use-wasm (= (or (env-get env "SX_USE_WASM") "") "1")
:meta-html ""))))))))