Merge branch 'worktree-api-urls' into macros
This commit is contained in:
@@ -48,7 +48,7 @@
|
||||
"string" (escape-html expr)
|
||||
"number" (escape-html (str expr))
|
||||
"raw-html" (raw-html-content expr)
|
||||
"spread" expr
|
||||
"spread" (do (emit! "element-attrs" (spread-attrs expr)) "")
|
||||
"symbol" (let ((val (async-eval expr env ctx)))
|
||||
(async-render val env ctx))
|
||||
"keyword" (escape-html (keyword-name expr))
|
||||
@@ -80,10 +80,9 @@
|
||||
(= name "raw!")
|
||||
(async-render-raw args env ctx)
|
||||
|
||||
;; Fragment (spreads filtered — no parent element)
|
||||
;; Fragment
|
||||
(= name "<>")
|
||||
(join "" (filter (fn (r) (not (spread? r)))
|
||||
(async-map-render args env ctx)))
|
||||
(join "" (async-map-render args env ctx))
|
||||
|
||||
;; html: prefix
|
||||
(starts-with? name "html:")
|
||||
@@ -171,18 +170,19 @@
|
||||
(css-class-collect! (str class-val))))
|
||||
(if (contains? VOID_ELEMENTS tag)
|
||||
(str "<" tag (render-attrs attrs) ">")
|
||||
;; Render children, collecting spreads and content separately
|
||||
;; Provide scope for spread emit!
|
||||
(let ((token (if (or (= tag "svg") (= tag "math"))
|
||||
(svg-context-set! true)
|
||||
nil))
|
||||
(content-parts (list)))
|
||||
(provide-push! "element-attrs" nil)
|
||||
(for-each
|
||||
(fn (c)
|
||||
(let ((result (async-render c env ctx)))
|
||||
(if (spread? result)
|
||||
(merge-spread-attrs attrs (spread-attrs result))
|
||||
(append! content-parts result))))
|
||||
(fn (c) (append! content-parts (async-render c env ctx)))
|
||||
children)
|
||||
(for-each
|
||||
(fn (spread-dict) (merge-spread-attrs attrs spread-dict))
|
||||
(emitted "element-attrs"))
|
||||
(provide-pop! "element-attrs")
|
||||
(when token (svg-context-reset! token))
|
||||
(str "<" tag (render-attrs attrs) ">"
|
||||
(join "" content-parts)
|
||||
@@ -231,14 +231,11 @@
|
||||
(for-each
|
||||
(fn (p) (env-set! local p (if (dict-has? kwargs p) (dict-get kwargs p) nil)))
|
||||
(component-params comp))
|
||||
;; Pre-render children to raw HTML (filter spreads — no parent element)
|
||||
;; Pre-render children to raw HTML
|
||||
(when (component-has-children? comp)
|
||||
(let ((parts (list)))
|
||||
(for-each
|
||||
(fn (c)
|
||||
(let ((r (async-render c env ctx)))
|
||||
(when (not (spread? r))
|
||||
(append! parts r))))
|
||||
(fn (c) (append! parts (async-render c env ctx)))
|
||||
children)
|
||||
(env-set! local "children"
|
||||
(make-raw-html (join "" parts)))))
|
||||
@@ -259,14 +256,11 @@
|
||||
(for-each
|
||||
(fn (p) (env-set! local p (if (dict-has? kwargs p) (dict-get kwargs p) nil)))
|
||||
(component-params island))
|
||||
;; Pre-render children (filter spreads — no parent element)
|
||||
;; Pre-render children
|
||||
(when (component-has-children? island)
|
||||
(let ((parts (list)))
|
||||
(for-each
|
||||
(fn (c)
|
||||
(let ((r (async-render c env ctx)))
|
||||
(when (not (spread? r))
|
||||
(append! parts r))))
|
||||
(fn (c) (append! parts (async-render c env ctx)))
|
||||
children)
|
||||
(env-set! local "children"
|
||||
(make-raw-html (join "" parts)))))
|
||||
@@ -367,14 +361,13 @@
|
||||
(async-render (nth expr 3) env ctx)
|
||||
"")))
|
||||
|
||||
;; when — single body: pass through (spread propagates). Multi: join strings.
|
||||
;; when — single body: pass through. Multi: join strings.
|
||||
(= name "when")
|
||||
(if (not (async-eval (nth expr 1) env ctx))
|
||||
""
|
||||
(if (= (len expr) 3)
|
||||
(async-render (nth expr 2) env ctx)
|
||||
(let ((results (async-map-render (slice expr 2) env ctx)))
|
||||
(join "" (filter (fn (r) (not (spread? r))) results)))))
|
||||
(join "" (async-map-render (slice expr 2) env ctx))))
|
||||
|
||||
;; cond — uses cond-scheme? (every? check) from eval.sx
|
||||
(= name "cond")
|
||||
@@ -392,47 +385,39 @@
|
||||
(let ((local (async-process-bindings (nth expr 1) env ctx)))
|
||||
(if (= (len expr) 3)
|
||||
(async-render (nth expr 2) local ctx)
|
||||
(let ((results (async-map-render (slice expr 2) local ctx)))
|
||||
(join "" (filter (fn (r) (not (spread? r))) results)))))
|
||||
(join "" (async-map-render (slice expr 2) local ctx))))
|
||||
|
||||
;; begin / do — single body: pass through. Multi: join strings.
|
||||
(or (= name "begin") (= name "do"))
|
||||
(if (= (len expr) 2)
|
||||
(async-render (nth expr 1) env ctx)
|
||||
(let ((results (async-map-render (rest expr) env ctx)))
|
||||
(join "" (filter (fn (r) (not (spread? r))) results))))
|
||||
(join "" (async-map-render (rest expr) env ctx)))
|
||||
|
||||
;; Definition forms
|
||||
(definition-form? name)
|
||||
(do (async-eval expr env ctx) "")
|
||||
|
||||
;; map — spreads filtered
|
||||
;; map
|
||||
(= name "map")
|
||||
(let ((f (async-eval (nth expr 1) env ctx))
|
||||
(coll (async-eval (nth expr 2) env ctx)))
|
||||
(join ""
|
||||
(filter (fn (r) (not (spread? r)))
|
||||
(async-map-fn-render f coll env ctx))))
|
||||
(join "" (async-map-fn-render f coll env ctx)))
|
||||
|
||||
;; map-indexed — spreads filtered
|
||||
;; map-indexed
|
||||
(= name "map-indexed")
|
||||
(let ((f (async-eval (nth expr 1) env ctx))
|
||||
(coll (async-eval (nth expr 2) env ctx)))
|
||||
(join ""
|
||||
(filter (fn (r) (not (spread? r)))
|
||||
(async-map-indexed-fn-render f coll env ctx))))
|
||||
(join "" (async-map-indexed-fn-render f coll env ctx)))
|
||||
|
||||
;; filter — eval fully then render
|
||||
(= name "filter")
|
||||
(async-render (async-eval expr env ctx) env ctx)
|
||||
|
||||
;; for-each (render variant) — spreads filtered
|
||||
;; for-each (render variant)
|
||||
(= name "for-each")
|
||||
(let ((f (async-eval (nth expr 1) env ctx))
|
||||
(coll (async-eval (nth expr 2) env ctx)))
|
||||
(join ""
|
||||
(filter (fn (r) (not (spread? r)))
|
||||
(async-map-fn-render f coll env ctx))))
|
||||
(join "" (async-map-fn-render f coll env ctx)))
|
||||
|
||||
;; provide — render-time dynamic scope
|
||||
(= name "provide")
|
||||
@@ -443,8 +428,7 @@
|
||||
(provide-push! prov-name prov-val)
|
||||
(let ((result (if (= body-count 1)
|
||||
(async-render (nth expr body-start) env ctx)
|
||||
(let ((results (async-map-render (slice expr body-start) env ctx)))
|
||||
(join "" (filter (fn (r) (not (spread? r))) results))))))
|
||||
(join "" (async-map-render (slice expr body-start) env ctx)))))
|
||||
(provide-pop! prov-name)
|
||||
result))
|
||||
|
||||
@@ -595,35 +579,34 @@
|
||||
|
||||
(define-async async-aser :effects [render io]
|
||||
(fn (expr (env :as dict) ctx)
|
||||
(case (type-of expr)
|
||||
"number" expr
|
||||
"string" expr
|
||||
"boolean" expr
|
||||
"nil" nil
|
||||
|
||||
"symbol"
|
||||
(let ((name (symbol-name expr)))
|
||||
(cond
|
||||
(env-has? env name) (env-get env name)
|
||||
(primitive? name) (get-primitive name)
|
||||
(= name "true") true
|
||||
(= name "false") false
|
||||
(= name "nil") nil
|
||||
:else (error (str "Undefined symbol: " name))))
|
||||
|
||||
"keyword" (keyword-name expr)
|
||||
|
||||
"dict" (async-aser-dict expr env ctx)
|
||||
|
||||
;; Spread — pass through for client rendering
|
||||
"spread" expr
|
||||
|
||||
"list"
|
||||
(if (empty? expr)
|
||||
(list)
|
||||
(async-aser-list expr env ctx))
|
||||
|
||||
:else expr)))
|
||||
(let ((t (type-of expr))
|
||||
(result nil))
|
||||
(cond
|
||||
(= t "number") (set! result expr)
|
||||
(= t "string") (set! result expr)
|
||||
(= t "boolean") (set! result expr)
|
||||
(= t "nil") (set! result nil)
|
||||
(= t "symbol")
|
||||
(let ((name (symbol-name expr)))
|
||||
(set! result
|
||||
(cond
|
||||
(env-has? env name) (env-get env name)
|
||||
(primitive? name) (get-primitive name)
|
||||
(= name "true") true
|
||||
(= name "false") false
|
||||
(= name "nil") nil
|
||||
:else (error (str "Undefined symbol: " name)))))
|
||||
(= t "keyword") (set! result (keyword-name expr))
|
||||
(= t "dict") (set! result (async-aser-dict expr env ctx))
|
||||
;; Spread — emit attrs to nearest element provider
|
||||
(= t "spread") (do (emit! "element-attrs" (spread-attrs expr))
|
||||
(set! result nil))
|
||||
(= t "list") (set! result (if (empty? expr) (list) (async-aser-list expr env ctx)))
|
||||
:else (set! result expr))
|
||||
;; Catch spread values from function calls and symbol lookups
|
||||
(if (spread? result)
|
||||
(do (emit! "element-attrs" (spread-attrs result)) nil)
|
||||
result))))
|
||||
|
||||
|
||||
(define-async async-aser-dict :effects [render io]
|
||||
@@ -775,7 +758,6 @@
|
||||
|
||||
(define-async async-aser-fragment :effects [render io]
|
||||
(fn ((children :as list) (env :as dict) ctx)
|
||||
;; Spreads are filtered — fragments have no parent element to merge into
|
||||
(let ((parts (list)))
|
||||
(for-each
|
||||
(fn (c)
|
||||
@@ -783,10 +765,10 @@
|
||||
(if (= (type-of result) "list")
|
||||
(for-each
|
||||
(fn (item)
|
||||
(when (and (not (nil? item)) (not (spread? item)))
|
||||
(when (not (nil? item))
|
||||
(append! parts (serialize item))))
|
||||
result)
|
||||
(when (and (not (nil? result)) (not (spread? result)))
|
||||
(when (not (nil? result))
|
||||
(append! parts (serialize result))))))
|
||||
children)
|
||||
(if (empty? parts)
|
||||
@@ -860,9 +842,12 @@
|
||||
(let ((token (if (or (= name "svg") (= name "math"))
|
||||
(svg-context-set! true)
|
||||
nil))
|
||||
(parts (list name))
|
||||
(attr-parts (list))
|
||||
(child-parts (list))
|
||||
(skip false)
|
||||
(i 0))
|
||||
;; Provide scope for spread emit!
|
||||
(provide-push! "element-attrs" nil)
|
||||
(for-each
|
||||
(fn (arg)
|
||||
(if skip
|
||||
@@ -872,39 +857,43 @@
|
||||
(< (inc i) (len args)))
|
||||
(let ((val (async-aser (nth args (inc i)) env ctx)))
|
||||
(when (not (nil? val))
|
||||
(append! parts (str ":" (keyword-name arg)))
|
||||
(append! attr-parts (str ":" (keyword-name arg)))
|
||||
(if (= (type-of val) "list")
|
||||
(let ((live (filter (fn (v) (not (nil? v))) val)))
|
||||
(if (empty? live)
|
||||
(append! parts "nil")
|
||||
(append! attr-parts "nil")
|
||||
(let ((items (map serialize live)))
|
||||
(if (some (fn (v) (sx-expr? v)) live)
|
||||
(append! parts (str "(<> " (join " " items) ")"))
|
||||
(append! parts (str "(list " (join " " items) ")"))))))
|
||||
(append! parts (serialize val))))
|
||||
(append! attr-parts (str "(<> " (join " " items) ")"))
|
||||
(append! attr-parts (str "(list " (join " " items) ")"))))))
|
||||
(append! attr-parts (serialize val))))
|
||||
(set! skip true)
|
||||
(set! i (inc i)))
|
||||
(let ((result (async-aser arg env ctx)))
|
||||
(when (not (nil? result))
|
||||
(if (spread? result)
|
||||
;; Spread child — merge attrs as keyword args into parent element
|
||||
(if (= (type-of result) "list")
|
||||
(for-each
|
||||
(fn (k)
|
||||
(let ((v (dict-get (spread-attrs result) k)))
|
||||
(append! parts (str ":" k))
|
||||
(append! parts (serialize v))))
|
||||
(keys (spread-attrs result)))
|
||||
(if (= (type-of result) "list")
|
||||
(for-each
|
||||
(fn (item)
|
||||
(when (not (nil? item))
|
||||
(append! parts (serialize item))))
|
||||
result)
|
||||
(append! parts (serialize result)))))
|
||||
(fn (item)
|
||||
(when (not (nil? item))
|
||||
(append! child-parts (serialize item))))
|
||||
result)
|
||||
(append! child-parts (serialize result))))
|
||||
(set! i (inc i))))))
|
||||
args)
|
||||
;; Collect emitted spread attrs — after explicit attrs, before children
|
||||
(for-each
|
||||
(fn (spread-dict)
|
||||
(for-each
|
||||
(fn (k)
|
||||
(let ((v (dict-get spread-dict k)))
|
||||
(append! attr-parts (str ":" k))
|
||||
(append! attr-parts (serialize v))))
|
||||
(keys spread-dict)))
|
||||
(emitted "element-attrs"))
|
||||
(provide-pop! "element-attrs")
|
||||
(when token (svg-context-reset! token))
|
||||
(make-sx-expr (str "(" (join " " parts) ")")))))
|
||||
(let ((parts (concat (list name) attr-parts child-parts)))
|
||||
(make-sx-expr (str "(" (join " " parts) ")"))))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
@@ -44,8 +44,8 @@
|
||||
;; Pre-rendered DOM node → pass through
|
||||
"dom-node" expr
|
||||
|
||||
;; Spread → pass through (parent element handles it)
|
||||
"spread" expr
|
||||
;; Spread → emit attrs to nearest element provider, pass through for reactive-spread
|
||||
"spread" (do (emit! "element-attrs" (spread-attrs expr)) expr)
|
||||
|
||||
;; Dict → empty
|
||||
"dict" (create-fragment)
|
||||
@@ -180,6 +180,9 @@
|
||||
:else ns))
|
||||
(el (dom-create-element tag new-ns)))
|
||||
|
||||
;; Provide scope for spread emit! — deeply nested spreads emit here
|
||||
(provide-push! "element-attrs" nil)
|
||||
|
||||
;; Process args: keywords → attrs, others → children
|
||||
(reduce
|
||||
(fn (state arg)
|
||||
@@ -236,28 +239,8 @@
|
||||
;; Reactive spread: track signal deps, update attrs on change
|
||||
(and (spread? child) *island-scope*)
|
||||
(reactive-spread el (fn () (render-to-dom arg env new-ns)))
|
||||
;; Static spread: one-shot merge attrs onto parent element
|
||||
(spread? child)
|
||||
(for-each
|
||||
(fn ((key :as string))
|
||||
(let ((val (dict-get (spread-attrs child) key)))
|
||||
(if (= key "class")
|
||||
;; Class: append to existing
|
||||
(let ((existing (dom-get-attr el "class")))
|
||||
(dom-set-attr el "class"
|
||||
(if (and existing (not (= existing "")))
|
||||
(str existing " " val)
|
||||
val)))
|
||||
(if (= key "style")
|
||||
;; Style: append with semicolon
|
||||
(let ((existing (dom-get-attr el "style")))
|
||||
(dom-set-attr el "style"
|
||||
(if (and existing (not (= existing "")))
|
||||
(str existing ";" val)
|
||||
val)))
|
||||
;; Other attrs: overwrite
|
||||
(dom-set-attr el key (str val))))))
|
||||
(keys (spread-attrs child)))
|
||||
;; Static spread: already emitted via provide, skip
|
||||
(spread? child) nil
|
||||
;; Normal child: append to element
|
||||
:else
|
||||
(dom-append el child))))
|
||||
@@ -265,6 +248,29 @@
|
||||
(dict "i" 0 "skip" false)
|
||||
args)
|
||||
|
||||
;; Collect emitted spread attrs and merge onto DOM element
|
||||
(for-each
|
||||
(fn (spread-dict)
|
||||
(for-each
|
||||
(fn ((key :as string))
|
||||
(let ((val (dict-get spread-dict key)))
|
||||
(if (= key "class")
|
||||
(let ((existing (dom-get-attr el "class")))
|
||||
(dom-set-attr el "class"
|
||||
(if (and existing (not (= existing "")))
|
||||
(str existing " " val)
|
||||
val)))
|
||||
(if (= key "style")
|
||||
(let ((existing (dom-get-attr el "style")))
|
||||
(dom-set-attr el "style"
|
||||
(if (and existing (not (= existing "")))
|
||||
(str existing ";" val)
|
||||
val)))
|
||||
(dom-set-attr el key (str val))))))
|
||||
(keys spread-dict)))
|
||||
(emitted "element-attrs"))
|
||||
(provide-pop! "element-attrs")
|
||||
|
||||
el)))
|
||||
|
||||
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
"keyword" (escape-html (keyword-name expr))
|
||||
;; Raw HTML passthrough
|
||||
"raw-html" (raw-html-content expr)
|
||||
;; Spread — pass through as-is (parent element will merge attrs)
|
||||
"spread" expr
|
||||
;; Spread — emit attrs to nearest element provider
|
||||
"spread" (do (emit! "element-attrs" (spread-attrs expr)) "")
|
||||
;; Everything else — evaluate first
|
||||
:else (render-value-to-html (trampoline (eval-expr expr env)) env))))
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
"boolean" (if val "true" "false")
|
||||
"list" (render-list-to-html val env)
|
||||
"raw-html" (raw-html-content val)
|
||||
"spread" val
|
||||
"spread" (do (emit! "element-attrs" (spread-attrs val)) "")
|
||||
:else (escape-html (str val)))))
|
||||
|
||||
|
||||
@@ -73,16 +73,14 @@
|
||||
""
|
||||
(let ((head (first expr)))
|
||||
(if (not (= (type-of head) "symbol"))
|
||||
;; Data list — render each item (spreads filtered — no parent element)
|
||||
(join "" (filter (fn (x) (not (spread? x)))
|
||||
(map (fn (x) (render-value-to-html x env)) expr)))
|
||||
;; Data list — render each item
|
||||
(join "" (map (fn (x) (render-value-to-html x env)) expr))
|
||||
(let ((name (symbol-name head))
|
||||
(args (rest expr)))
|
||||
(cond
|
||||
;; Fragment (spreads filtered — no parent element)
|
||||
;; Fragment
|
||||
(= name "<>")
|
||||
(join "" (filter (fn (x) (not (spread? x)))
|
||||
(map (fn (x) (render-to-html x env)) args)))
|
||||
(join "" (map (fn (x) (render-to-html x env)) args))
|
||||
|
||||
;; Raw HTML passthrough
|
||||
(= name "raw!")
|
||||
@@ -152,15 +150,14 @@
|
||||
(render-to-html (nth expr 3) env)
|
||||
"")))
|
||||
|
||||
;; when — single body: pass through (spread propagates). Multi: join strings.
|
||||
;; when — single body: pass through. Multi: join strings.
|
||||
(= name "when")
|
||||
(if (not (trampoline (eval-expr (nth expr 1) env)))
|
||||
""
|
||||
(if (= (len expr) 3)
|
||||
(render-to-html (nth expr 2) env)
|
||||
(let ((results (map (fn (i) (render-to-html (nth expr i) env))
|
||||
(range 2 (len expr)))))
|
||||
(join "" (filter (fn (r) (not (spread? r))) results)))))
|
||||
(join "" (map (fn (i) (render-to-html (nth expr i) env))
|
||||
(range 2 (len expr))))))
|
||||
|
||||
;; cond
|
||||
(= name "cond")
|
||||
@@ -178,64 +175,59 @@
|
||||
(let ((local (process-bindings (nth expr 1) env)))
|
||||
(if (= (len expr) 3)
|
||||
(render-to-html (nth expr 2) local)
|
||||
(let ((results (map (fn (i) (render-to-html (nth expr i) local))
|
||||
(range 2 (len expr)))))
|
||||
(join "" (filter (fn (r) (not (spread? r))) results)))))
|
||||
(join "" (map (fn (i) (render-to-html (nth expr i) local))
|
||||
(range 2 (len expr))))))
|
||||
|
||||
;; begin / do — single body: pass through. Multi: join strings.
|
||||
(or (= name "begin") (= name "do"))
|
||||
(if (= (len expr) 2)
|
||||
(render-to-html (nth expr 1) env)
|
||||
(let ((results (map (fn (i) (render-to-html (nth expr i) env))
|
||||
(range 1 (len expr)))))
|
||||
(join "" (filter (fn (r) (not (spread? r))) results))))
|
||||
(join "" (map (fn (i) (render-to-html (nth expr i) env))
|
||||
(range 1 (len expr)))))
|
||||
|
||||
;; Definition forms — eval for side effects
|
||||
(definition-form? name)
|
||||
(do (trampoline (eval-expr expr env)) "")
|
||||
|
||||
;; map — spreads filtered (no parent element in list context)
|
||||
;; map
|
||||
(= name "map")
|
||||
(let ((f (trampoline (eval-expr (nth expr 1) env)))
|
||||
(coll (trampoline (eval-expr (nth expr 2) env))))
|
||||
(join ""
|
||||
(filter (fn (r) (not (spread? r)))
|
||||
(map
|
||||
(fn (item)
|
||||
(if (lambda? f)
|
||||
(render-lambda-html f (list item) env)
|
||||
(render-to-html (apply f (list item)) env)))
|
||||
coll))))
|
||||
(map
|
||||
(fn (item)
|
||||
(if (lambda? f)
|
||||
(render-lambda-html f (list item) env)
|
||||
(render-to-html (apply f (list item)) env)))
|
||||
coll)))
|
||||
|
||||
;; map-indexed — spreads filtered
|
||||
;; map-indexed
|
||||
(= name "map-indexed")
|
||||
(let ((f (trampoline (eval-expr (nth expr 1) env)))
|
||||
(coll (trampoline (eval-expr (nth expr 2) env))))
|
||||
(join ""
|
||||
(filter (fn (r) (not (spread? r)))
|
||||
(map-indexed
|
||||
(fn (i item)
|
||||
(if (lambda? f)
|
||||
(render-lambda-html f (list i item) env)
|
||||
(render-to-html (apply f (list i item)) env)))
|
||||
coll))))
|
||||
(map-indexed
|
||||
(fn (i item)
|
||||
(if (lambda? f)
|
||||
(render-lambda-html f (list i item) env)
|
||||
(render-to-html (apply f (list i item)) env)))
|
||||
coll)))
|
||||
|
||||
;; filter — evaluate fully then render
|
||||
(= name "filter")
|
||||
(render-to-html (trampoline (eval-expr expr env)) env)
|
||||
|
||||
;; for-each (render variant) — spreads filtered
|
||||
;; for-each (render variant)
|
||||
(= name "for-each")
|
||||
(let ((f (trampoline (eval-expr (nth expr 1) env)))
|
||||
(coll (trampoline (eval-expr (nth expr 2) env))))
|
||||
(join ""
|
||||
(filter (fn (r) (not (spread? r)))
|
||||
(map
|
||||
(fn (item)
|
||||
(if (lambda? f)
|
||||
(render-lambda-html f (list item) env)
|
||||
(render-to-html (apply f (list item)) env)))
|
||||
coll))))
|
||||
(map
|
||||
(fn (item)
|
||||
(if (lambda? f)
|
||||
(render-lambda-html f (list item) env)
|
||||
(render-to-html (apply f (list item)) env)))
|
||||
coll)))
|
||||
|
||||
;; provide — render-time dynamic scope
|
||||
(= name "provide")
|
||||
@@ -246,9 +238,8 @@
|
||||
(provide-push! prov-name prov-val)
|
||||
(let ((result (if (= body-count 1)
|
||||
(render-to-html (nth expr body-start) env)
|
||||
(join "" (filter (fn (r) (not (spread? r)))
|
||||
(map (fn (i) (render-to-html (nth expr i) env))
|
||||
(range body-start (+ body-start body-count))))))))
|
||||
(join "" (map (fn (i) (render-to-html (nth expr i) env))
|
||||
(range body-start (+ body-start body-count)))))))
|
||||
(provide-pop! prov-name)
|
||||
result))
|
||||
|
||||
@@ -307,17 +298,9 @@
|
||||
(env-set! local p (if (dict-has? kwargs p) (dict-get kwargs p) nil)))
|
||||
(component-params comp))
|
||||
;; If component accepts children, pre-render them to raw HTML
|
||||
;; Spread values are filtered out (no parent element to merge onto)
|
||||
(when (component-has-children? comp)
|
||||
(let ((parts (list)))
|
||||
(for-each
|
||||
(fn (c)
|
||||
(let ((r (render-to-html c env)))
|
||||
(when (not (spread? r))
|
||||
(append! parts r))))
|
||||
children)
|
||||
(env-set! local "children"
|
||||
(make-raw-html (join "" parts)))))
|
||||
(env-set! local "children"
|
||||
(make-raw-html (join "" (map (fn (c) (render-to-html c env)) children)))))
|
||||
(render-to-html (component-body comp) local)))))
|
||||
|
||||
|
||||
@@ -329,18 +312,17 @@
|
||||
(is-void (contains? VOID_ELEMENTS tag)))
|
||||
(if is-void
|
||||
(str "<" tag (render-attrs attrs) " />")
|
||||
;; Render children, collecting spreads and content separately
|
||||
(let ((content-parts (list)))
|
||||
(for-each
|
||||
(fn (c)
|
||||
(let ((result (render-to-html c env)))
|
||||
(if (spread? result)
|
||||
(merge-spread-attrs attrs (spread-attrs result))
|
||||
(append! content-parts result))))
|
||||
children)
|
||||
(str "<" tag (render-attrs attrs) ">"
|
||||
(join "" content-parts)
|
||||
"</" tag ">"))))))
|
||||
;; Provide scope for spread emit!
|
||||
(do
|
||||
(provide-push! "element-attrs" nil)
|
||||
(let ((content (join "" (map (fn (c) (render-to-html c env)) children))))
|
||||
(for-each
|
||||
(fn (spread-dict) (merge-spread-attrs attrs spread-dict))
|
||||
(emitted "element-attrs"))
|
||||
(provide-pop! "element-attrs")
|
||||
(str "<" tag (render-attrs attrs) ">"
|
||||
content
|
||||
"</" tag ">")))))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
@@ -375,19 +357,17 @@
|
||||
(assoc state "i" (inc (get state "i"))))))))
|
||||
(dict "i" 0 "skip" false)
|
||||
args)
|
||||
;; Render children, handling spreads
|
||||
(let ((lake-attrs (dict "data-sx-lake" (or lake-id "")))
|
||||
(content-parts (list)))
|
||||
(for-each
|
||||
(fn (c)
|
||||
(let ((result (render-to-html c env)))
|
||||
(if (spread? result)
|
||||
(merge-spread-attrs lake-attrs (spread-attrs result))
|
||||
(append! content-parts result))))
|
||||
children)
|
||||
(str "<" lake-tag (render-attrs lake-attrs) ">"
|
||||
(join "" content-parts)
|
||||
"</" lake-tag ">")))))
|
||||
;; Provide scope for spread emit!
|
||||
(let ((lake-attrs (dict "data-sx-lake" (or lake-id ""))))
|
||||
(provide-push! "element-attrs" nil)
|
||||
(let ((content (join "" (map (fn (c) (render-to-html c env)) children))))
|
||||
(for-each
|
||||
(fn (spread-dict) (merge-spread-attrs lake-attrs spread-dict))
|
||||
(emitted "element-attrs"))
|
||||
(provide-pop! "element-attrs")
|
||||
(str "<" lake-tag (render-attrs lake-attrs) ">"
|
||||
content
|
||||
"</" lake-tag ">"))))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
@@ -425,19 +405,17 @@
|
||||
(assoc state "i" (inc (get state "i"))))))))
|
||||
(dict "i" 0 "skip" false)
|
||||
args)
|
||||
;; Render children, handling spreads
|
||||
(let ((marsh-attrs (dict "data-sx-marsh" (or marsh-id "")))
|
||||
(content-parts (list)))
|
||||
(for-each
|
||||
(fn (c)
|
||||
(let ((result (render-to-html c env)))
|
||||
(if (spread? result)
|
||||
(merge-spread-attrs marsh-attrs (spread-attrs result))
|
||||
(append! content-parts result))))
|
||||
children)
|
||||
(str "<" marsh-tag (render-attrs marsh-attrs) ">"
|
||||
(join "" content-parts)
|
||||
"</" marsh-tag ">")))))
|
||||
;; Provide scope for spread emit!
|
||||
(let ((marsh-attrs (dict "data-sx-marsh" (or marsh-id ""))))
|
||||
(provide-push! "element-attrs" nil)
|
||||
(let ((content (join "" (map (fn (c) (render-to-html c env)) children))))
|
||||
(for-each
|
||||
(fn (spread-dict) (merge-spread-attrs marsh-attrs spread-dict))
|
||||
(emitted "element-attrs"))
|
||||
(provide-pop! "element-attrs")
|
||||
(str "<" marsh-tag (render-attrs marsh-attrs) ">"
|
||||
content
|
||||
"</" marsh-tag ">"))))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
@@ -487,17 +465,9 @@
|
||||
(component-params island))
|
||||
|
||||
;; If island accepts children, pre-render them to raw HTML
|
||||
;; Spread values filtered out (no parent element)
|
||||
(when (component-has-children? island)
|
||||
(let ((parts (list)))
|
||||
(for-each
|
||||
(fn (c)
|
||||
(let ((r (render-to-html c env)))
|
||||
(when (not (spread? r))
|
||||
(append! parts r))))
|
||||
children)
|
||||
(env-set! local "children"
|
||||
(make-raw-html (join "" parts)))))
|
||||
(env-set! local "children"
|
||||
(make-raw-html (join "" (map (fn (c) (render-to-html c env)) children)))))
|
||||
|
||||
;; Render the island body as HTML
|
||||
(let ((body-html (render-to-html (component-body island) local))
|
||||
|
||||
@@ -25,33 +25,38 @@
|
||||
;; Evaluate for SX wire format — serialize rendering forms,
|
||||
;; evaluate control flow and function calls.
|
||||
(set-render-active! true)
|
||||
(case (type-of expr)
|
||||
"number" expr
|
||||
"string" expr
|
||||
"boolean" expr
|
||||
"nil" nil
|
||||
(let ((result
|
||||
(case (type-of expr)
|
||||
"number" expr
|
||||
"string" expr
|
||||
"boolean" expr
|
||||
"nil" nil
|
||||
|
||||
"symbol"
|
||||
(let ((name (symbol-name expr)))
|
||||
(cond
|
||||
(env-has? env name) (env-get env name)
|
||||
(primitive? name) (get-primitive name)
|
||||
(= name "true") true
|
||||
(= name "false") false
|
||||
(= name "nil") nil
|
||||
:else (error (str "Undefined symbol: " name))))
|
||||
"symbol"
|
||||
(let ((name (symbol-name expr)))
|
||||
(cond
|
||||
(env-has? env name) (env-get env name)
|
||||
(primitive? name) (get-primitive name)
|
||||
(= name "true") true
|
||||
(= name "false") false
|
||||
(= name "nil") nil
|
||||
:else (error (str "Undefined symbol: " name))))
|
||||
|
||||
"keyword" (keyword-name expr)
|
||||
"keyword" (keyword-name expr)
|
||||
|
||||
"list"
|
||||
(if (empty? expr)
|
||||
(list)
|
||||
(aser-list expr env))
|
||||
"list"
|
||||
(if (empty? expr)
|
||||
(list)
|
||||
(aser-list expr env))
|
||||
|
||||
;; Spread — pass through for client rendering
|
||||
"spread" expr
|
||||
;; Spread — emit attrs to nearest element provider
|
||||
"spread" (do (emit! "element-attrs" (spread-attrs expr)) nil)
|
||||
|
||||
:else expr)))
|
||||
:else expr)))
|
||||
;; Catch spread values from function calls and symbol lookups
|
||||
(if (spread? result)
|
||||
(do (emit! "element-attrs" (spread-attrs result)) nil)
|
||||
result))))
|
||||
|
||||
|
||||
(define aser-list :effects [render]
|
||||
@@ -110,7 +115,6 @@
|
||||
(fn ((children :as list) (env :as dict))
|
||||
;; Serialize (<> child1 child2 ...) to sx source string
|
||||
;; Must flatten list results (e.g. from map/filter) to avoid nested parens
|
||||
;; Spreads are filtered — fragments have no parent element to merge into
|
||||
(let ((parts (list)))
|
||||
(for-each
|
||||
(fn (c)
|
||||
@@ -118,10 +122,10 @@
|
||||
(if (= (type-of result) "list")
|
||||
(for-each
|
||||
(fn (item)
|
||||
(when (and (not (nil? item)) (not (spread? item)))
|
||||
(when (not (nil? item))
|
||||
(append! parts (serialize item))))
|
||||
result)
|
||||
(when (and (not (nil? result)) (not (spread? result)))
|
||||
(when (not (nil? result))
|
||||
(append! parts (serialize result))))))
|
||||
children)
|
||||
(if (empty? parts)
|
||||
@@ -134,9 +138,13 @@
|
||||
;; Serialize (name :key val child ...) — evaluate args but keep as sx
|
||||
;; Uses for-each + mutable state (not reduce) so bootstrapper emits for-loops
|
||||
;; that can contain nested for-each for list flattening.
|
||||
(let ((parts (list name))
|
||||
;; Separate attrs and children so emitted spread attrs go before children.
|
||||
(let ((attr-parts (list))
|
||||
(child-parts (list))
|
||||
(skip false)
|
||||
(i 0))
|
||||
;; Provide scope for spread emit!
|
||||
(provide-push! "element-attrs" nil)
|
||||
(for-each
|
||||
(fn (arg)
|
||||
(if skip
|
||||
@@ -146,30 +154,34 @@
|
||||
(< (inc i) (len args)))
|
||||
(let ((val (aser (nth args (inc i)) env)))
|
||||
(when (not (nil? val))
|
||||
(append! parts (str ":" (keyword-name arg)))
|
||||
(append! parts (serialize val)))
|
||||
(append! attr-parts (str ":" (keyword-name arg)))
|
||||
(append! attr-parts (serialize val)))
|
||||
(set! skip true)
|
||||
(set! i (inc i)))
|
||||
(let ((val (aser arg env)))
|
||||
(when (not (nil? val))
|
||||
(if (spread? val)
|
||||
;; Spread child — merge attrs as keyword args into parent element
|
||||
(if (= (type-of val) "list")
|
||||
(for-each
|
||||
(fn (k)
|
||||
(let ((v (dict-get (spread-attrs val) k)))
|
||||
(append! parts (str ":" k))
|
||||
(append! parts (serialize v))))
|
||||
(keys (spread-attrs val)))
|
||||
(if (= (type-of val) "list")
|
||||
(for-each
|
||||
(fn (item)
|
||||
(when (not (nil? item))
|
||||
(append! parts (serialize item))))
|
||||
val)
|
||||
(append! parts (serialize val)))))
|
||||
(fn (item)
|
||||
(when (not (nil? item))
|
||||
(append! child-parts (serialize item))))
|
||||
val)
|
||||
(append! child-parts (serialize val))))
|
||||
(set! i (inc i))))))
|
||||
args)
|
||||
(str "(" (join " " parts) ")"))))
|
||||
;; Collect emitted spread attrs — goes after explicit attrs, before children
|
||||
(for-each
|
||||
(fn (spread-dict)
|
||||
(for-each
|
||||
(fn (k)
|
||||
(let ((v (dict-get spread-dict k)))
|
||||
(append! attr-parts (str ":" k))
|
||||
(append! attr-parts (serialize v))))
|
||||
(keys spread-dict)))
|
||||
(emitted "element-attrs"))
|
||||
(provide-pop! "element-attrs")
|
||||
(let ((parts (concat (list name) attr-parts child-parts)))
|
||||
(str "(" (join " " parts) ")")))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
|
||||
@@ -1203,8 +1203,6 @@ PLATFORM_JS_PRE = '''
|
||||
function sxEmit(name, value) {
|
||||
if (_provideStacks[name] && _provideStacks[name].length) {
|
||||
_provideStacks[name][_provideStacks[name].length - 1].emitted.push(value);
|
||||
} else {
|
||||
throw new Error("No provider for emit!: " + name);
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
@@ -126,11 +126,9 @@ def sx_context(name, *default):
|
||||
|
||||
|
||||
def sx_emit(name, value):
|
||||
"""Append value to nearest enclosing provider's accumulator. Error if no provider."""
|
||||
"""Append value to nearest enclosing provider's accumulator. No-op if no provider."""
|
||||
if name in _provide_stacks and _provide_stacks[name]:
|
||||
_provide_stacks[name][-1]["emitted"].append(value)
|
||||
else:
|
||||
raise RuntimeError(f"No provider for emit!: {name}")
|
||||
return NIL
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# WARNING: special-forms.sx declares forms not in eval.sx: reset, shift
|
||||
# WARNING: eval.sx dispatches forms not in special-forms.sx: form?, provide
|
||||
"""
|
||||
sx_ref.py -- Generated from reference SX evaluator specification.
|
||||
|
||||
@@ -87,11 +85,9 @@ def sx_context(name, *default):
|
||||
|
||||
|
||||
def sx_emit(name, value):
|
||||
"""Append value to nearest enclosing provider's accumulator. Error if no provider."""
|
||||
"""Append value to nearest enclosing provider's accumulator. No-op if no provider."""
|
||||
if name in _provide_stacks and _provide_stacks[name]:
|
||||
_provide_stacks[name][-1]["emitted"].append(value)
|
||||
else:
|
||||
raise RuntimeError(f"No provider for emit!: {name}")
|
||||
return NIL
|
||||
|
||||
|
||||
@@ -2225,7 +2221,8 @@ def render_to_html(expr, env):
|
||||
elif _match == 'raw-html':
|
||||
return raw_html_content(expr)
|
||||
elif _match == 'spread':
|
||||
return expr
|
||||
sx_emit('element-attrs', spread_attrs(expr))
|
||||
return ''
|
||||
else:
|
||||
return render_value_to_html(trampoline(eval_expr(expr, env)), env)
|
||||
|
||||
@@ -2248,7 +2245,8 @@ def render_value_to_html(val, env):
|
||||
elif _match == 'raw-html':
|
||||
return raw_html_content(val)
|
||||
elif _match == 'spread':
|
||||
return val
|
||||
sx_emit('element-attrs', spread_attrs(val))
|
||||
return ''
|
||||
else:
|
||||
return escape_html(sx_str(val))
|
||||
|
||||
@@ -2266,12 +2264,12 @@ def render_list_to_html(expr, env):
|
||||
else:
|
||||
head = first(expr)
|
||||
if sx_truthy((not sx_truthy((type_of(head) == 'symbol')))):
|
||||
return join('', filter(lambda x: (not sx_truthy(is_spread(x))), map(lambda x: render_value_to_html(x, env), expr)))
|
||||
return join('', map(lambda x: render_value_to_html(x, env), expr))
|
||||
else:
|
||||
name = symbol_name(head)
|
||||
args = rest(expr)
|
||||
if sx_truthy((name == '<>')):
|
||||
return join('', filter(lambda x: (not sx_truthy(is_spread(x))), map(lambda x: render_to_html(x, env), args)))
|
||||
return join('', map(lambda x: render_to_html(x, env), args))
|
||||
elif sx_truthy((name == 'raw!')):
|
||||
return join('', map(lambda x: sx_str(trampoline(eval_expr(x, env))), args))
|
||||
elif sx_truthy((name == 'lake')):
|
||||
@@ -2315,8 +2313,7 @@ def dispatch_html_form(name, expr, env):
|
||||
if sx_truthy((len(expr) == 3)):
|
||||
return render_to_html(nth(expr, 2), env)
|
||||
else:
|
||||
results = map(lambda i: render_to_html(nth(expr, i), env), range(2, len(expr)))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), results))
|
||||
return join('', map(lambda i: render_to_html(nth(expr, i), env), range(2, len(expr))))
|
||||
elif sx_truthy((name == 'cond')):
|
||||
branch = eval_cond(rest(expr), env)
|
||||
if sx_truthy(branch):
|
||||
@@ -2330,38 +2327,36 @@ def dispatch_html_form(name, expr, env):
|
||||
if sx_truthy((len(expr) == 3)):
|
||||
return render_to_html(nth(expr, 2), local)
|
||||
else:
|
||||
results = map(lambda i: render_to_html(nth(expr, i), local), range(2, len(expr)))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), results))
|
||||
return join('', map(lambda i: render_to_html(nth(expr, i), local), range(2, len(expr))))
|
||||
elif sx_truthy(((name == 'begin') if sx_truthy((name == 'begin')) else (name == 'do'))):
|
||||
if sx_truthy((len(expr) == 2)):
|
||||
return render_to_html(nth(expr, 1), env)
|
||||
else:
|
||||
results = map(lambda i: render_to_html(nth(expr, i), env), range(1, len(expr)))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), results))
|
||||
return join('', map(lambda i: render_to_html(nth(expr, i), env), range(1, len(expr))))
|
||||
elif sx_truthy(is_definition_form(name)):
|
||||
trampoline(eval_expr(expr, env))
|
||||
return ''
|
||||
elif sx_truthy((name == 'map')):
|
||||
f = trampoline(eval_expr(nth(expr, 1), env))
|
||||
coll = trampoline(eval_expr(nth(expr, 2), env))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), map(lambda item: (render_lambda_html(f, [item], env) if sx_truthy(is_lambda(f)) else render_to_html(apply(f, [item]), env)), coll)))
|
||||
return join('', map(lambda item: (render_lambda_html(f, [item], env) if sx_truthy(is_lambda(f)) else render_to_html(apply(f, [item]), env)), coll))
|
||||
elif sx_truthy((name == 'map-indexed')):
|
||||
f = trampoline(eval_expr(nth(expr, 1), env))
|
||||
coll = trampoline(eval_expr(nth(expr, 2), env))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), map_indexed(lambda i, item: (render_lambda_html(f, [i, item], env) if sx_truthy(is_lambda(f)) else render_to_html(apply(f, [i, item]), env)), coll)))
|
||||
return join('', map_indexed(lambda i, item: (render_lambda_html(f, [i, item], env) if sx_truthy(is_lambda(f)) else render_to_html(apply(f, [i, item]), env)), coll))
|
||||
elif sx_truthy((name == 'filter')):
|
||||
return render_to_html(trampoline(eval_expr(expr, env)), env)
|
||||
elif sx_truthy((name == 'for-each')):
|
||||
f = trampoline(eval_expr(nth(expr, 1), env))
|
||||
coll = trampoline(eval_expr(nth(expr, 2), env))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), map(lambda item: (render_lambda_html(f, [item], env) if sx_truthy(is_lambda(f)) else render_to_html(apply(f, [item]), env)), coll)))
|
||||
return join('', map(lambda item: (render_lambda_html(f, [item], env) if sx_truthy(is_lambda(f)) else render_to_html(apply(f, [item]), env)), coll))
|
||||
elif sx_truthy((name == 'provide')):
|
||||
prov_name = trampoline(eval_expr(nth(expr, 1), env))
|
||||
prov_val = trampoline(eval_expr(nth(expr, 2), env))
|
||||
body_start = 3
|
||||
body_count = (len(expr) - 3)
|
||||
provide_push(prov_name, prov_val)
|
||||
result = (render_to_html(nth(expr, body_start), env) if sx_truthy((body_count == 1)) else join('', filter(lambda r: (not sx_truthy(is_spread(r))), map(lambda i: render_to_html(nth(expr, i), env), range(body_start, (body_start + body_count))))))
|
||||
result = (render_to_html(nth(expr, body_start), env) if sx_truthy((body_count == 1)) else join('', map(lambda i: render_to_html(nth(expr, i), env), range(body_start, (body_start + body_count)))))
|
||||
provide_pop(prov_name)
|
||||
return result
|
||||
else:
|
||||
@@ -2382,12 +2377,7 @@ def render_html_component(comp, args, env):
|
||||
for p in component_params(comp):
|
||||
local[p] = (dict_get(kwargs, p) if sx_truthy(dict_has(kwargs, p)) else NIL)
|
||||
if sx_truthy(component_has_children(comp)):
|
||||
parts = []
|
||||
for c in children:
|
||||
r = render_to_html(c, env)
|
||||
if sx_truthy((not sx_truthy(is_spread(r)))):
|
||||
parts.append(r)
|
||||
local['children'] = make_raw_html(join('', parts))
|
||||
local['children'] = make_raw_html(join('', map(lambda c: render_to_html(c, env), children)))
|
||||
return render_to_html(component_body(comp), local)
|
||||
|
||||
# render-html-element
|
||||
@@ -2399,14 +2389,12 @@ def render_html_element(tag, args, env):
|
||||
if sx_truthy(is_void):
|
||||
return sx_str('<', tag, render_attrs(attrs), ' />')
|
||||
else:
|
||||
content_parts = []
|
||||
for c in children:
|
||||
result = render_to_html(c, env)
|
||||
if sx_truthy(is_spread(result)):
|
||||
merge_spread_attrs(attrs, spread_attrs(result))
|
||||
else:
|
||||
content_parts.append(result)
|
||||
return sx_str('<', tag, render_attrs(attrs), '>', join('', content_parts), '</', tag, '>')
|
||||
provide_push('element-attrs', NIL)
|
||||
content = join('', map(lambda c: render_to_html(c, env), children))
|
||||
for spread_dict in sx_emitted('element-attrs'):
|
||||
merge_spread_attrs(attrs, spread_dict)
|
||||
provide_pop('element-attrs')
|
||||
return sx_str('<', tag, render_attrs(attrs), '>', content, '</', tag, '>')
|
||||
|
||||
# render-html-lake
|
||||
def render_html_lake(args, env):
|
||||
@@ -2416,14 +2404,12 @@ def render_html_lake(args, env):
|
||||
children = []
|
||||
reduce(lambda state, arg: (lambda skip: (assoc(state, 'skip', False, 'i', (get(state, 'i') + 1)) if sx_truthy(skip) else ((lambda kname: (lambda kval: _sx_begin((_sx_cell_set(_cells, 'lake_id', kval) if sx_truthy((kname == 'id')) else (_sx_cell_set(_cells, 'lake_tag', kval) if sx_truthy((kname == 'tag')) else NIL)), assoc(state, 'skip', True, 'i', (get(state, 'i') + 1))))(trampoline(eval_expr(nth(args, (get(state, 'i') + 1)), env))))(keyword_name(arg)) if sx_truthy(((type_of(arg) == 'keyword') if not sx_truthy((type_of(arg) == 'keyword')) else ((get(state, 'i') + 1) < len(args)))) else _sx_begin(_sx_append(children, arg), assoc(state, 'i', (get(state, 'i') + 1))))))(get(state, 'skip')), {'i': 0, 'skip': False}, args)
|
||||
lake_attrs = {'data-sx-lake': (_cells['lake_id'] if sx_truthy(_cells['lake_id']) else '')}
|
||||
content_parts = []
|
||||
for c in children:
|
||||
result = render_to_html(c, env)
|
||||
if sx_truthy(is_spread(result)):
|
||||
merge_spread_attrs(lake_attrs, spread_attrs(result))
|
||||
else:
|
||||
content_parts.append(result)
|
||||
return sx_str('<', _cells['lake_tag'], render_attrs(lake_attrs), '>', join('', content_parts), '</', _cells['lake_tag'], '>')
|
||||
provide_push('element-attrs', NIL)
|
||||
content = join('', map(lambda c: render_to_html(c, env), children))
|
||||
for spread_dict in sx_emitted('element-attrs'):
|
||||
merge_spread_attrs(lake_attrs, spread_dict)
|
||||
provide_pop('element-attrs')
|
||||
return sx_str('<', _cells['lake_tag'], render_attrs(lake_attrs), '>', content, '</', _cells['lake_tag'], '>')
|
||||
|
||||
# render-html-marsh
|
||||
def render_html_marsh(args, env):
|
||||
@@ -2433,14 +2419,12 @@ def render_html_marsh(args, env):
|
||||
children = []
|
||||
reduce(lambda state, arg: (lambda skip: (assoc(state, 'skip', False, 'i', (get(state, 'i') + 1)) if sx_truthy(skip) else ((lambda kname: (lambda kval: _sx_begin((_sx_cell_set(_cells, 'marsh_id', kval) if sx_truthy((kname == 'id')) else (_sx_cell_set(_cells, 'marsh_tag', kval) if sx_truthy((kname == 'tag')) else (NIL if sx_truthy((kname == 'transform')) else NIL))), assoc(state, 'skip', True, 'i', (get(state, 'i') + 1))))(trampoline(eval_expr(nth(args, (get(state, 'i') + 1)), env))))(keyword_name(arg)) if sx_truthy(((type_of(arg) == 'keyword') if not sx_truthy((type_of(arg) == 'keyword')) else ((get(state, 'i') + 1) < len(args)))) else _sx_begin(_sx_append(children, arg), assoc(state, 'i', (get(state, 'i') + 1))))))(get(state, 'skip')), {'i': 0, 'skip': False}, args)
|
||||
marsh_attrs = {'data-sx-marsh': (_cells['marsh_id'] if sx_truthy(_cells['marsh_id']) else '')}
|
||||
content_parts = []
|
||||
for c in children:
|
||||
result = render_to_html(c, env)
|
||||
if sx_truthy(is_spread(result)):
|
||||
merge_spread_attrs(marsh_attrs, spread_attrs(result))
|
||||
else:
|
||||
content_parts.append(result)
|
||||
return sx_str('<', _cells['marsh_tag'], render_attrs(marsh_attrs), '>', join('', content_parts), '</', _cells['marsh_tag'], '>')
|
||||
provide_push('element-attrs', NIL)
|
||||
content = join('', map(lambda c: render_to_html(c, env), children))
|
||||
for spread_dict in sx_emitted('element-attrs'):
|
||||
merge_spread_attrs(marsh_attrs, spread_dict)
|
||||
provide_pop('element-attrs')
|
||||
return sx_str('<', _cells['marsh_tag'], render_attrs(marsh_attrs), '>', content, '</', _cells['marsh_tag'], '>')
|
||||
|
||||
# render-html-island
|
||||
def render_html_island(island, args, env):
|
||||
@@ -2452,12 +2436,7 @@ def render_html_island(island, args, env):
|
||||
for p in component_params(island):
|
||||
local[p] = (dict_get(kwargs, p) if sx_truthy(dict_has(kwargs, p)) else NIL)
|
||||
if sx_truthy(component_has_children(island)):
|
||||
parts = []
|
||||
for c in children:
|
||||
r = render_to_html(c, env)
|
||||
if sx_truthy((not sx_truthy(is_spread(r)))):
|
||||
parts.append(r)
|
||||
local['children'] = make_raw_html(join('', parts))
|
||||
local['children'] = make_raw_html(join('', map(lambda c: render_to_html(c, env), children)))
|
||||
body_html = render_to_html(component_body(island), local)
|
||||
state_sx = serialize_island_state(kwargs)
|
||||
return sx_str('<span data-sx-island="', escape_attr(island_name), '"', (sx_str(' data-sx-state="', escape_attr(state_sx), '"') if sx_truthy(state_sx) else ''), '>', body_html, '</span>')
|
||||
@@ -2483,40 +2462,12 @@ def render_to_sx(expr, env):
|
||||
# aser
|
||||
def aser(expr, env):
|
||||
set_render_active_b(True)
|
||||
_match = type_of(expr)
|
||||
if _match == 'number':
|
||||
return expr
|
||||
elif _match == 'string':
|
||||
return expr
|
||||
elif _match == 'boolean':
|
||||
return expr
|
||||
elif _match == 'nil':
|
||||
result = _sx_case(type_of(expr), [('number', lambda: expr), ('string', lambda: expr), ('boolean', lambda: expr), ('nil', lambda: NIL), ('symbol', lambda: (lambda name: (env_get(env, name) if sx_truthy(env_has(env, name)) else (get_primitive(name) if sx_truthy(is_primitive(name)) else (True if sx_truthy((name == 'true')) else (False if sx_truthy((name == 'false')) else (NIL if sx_truthy((name == 'nil')) else error(sx_str('Undefined symbol: ', name))))))))(symbol_name(expr))), ('keyword', lambda: keyword_name(expr)), ('list', lambda: ([] if sx_truthy(empty_p(expr)) else aser_list(expr, env))), ('spread', lambda: _sx_begin(sx_emit('element-attrs', spread_attrs(expr)), NIL)), (None, lambda: expr)])
|
||||
if sx_truthy(is_spread(result)):
|
||||
sx_emit('element-attrs', spread_attrs(result))
|
||||
return NIL
|
||||
elif _match == 'symbol':
|
||||
name = symbol_name(expr)
|
||||
if sx_truthy(env_has(env, name)):
|
||||
return env_get(env, name)
|
||||
elif sx_truthy(is_primitive(name)):
|
||||
return get_primitive(name)
|
||||
elif sx_truthy((name == 'true')):
|
||||
return True
|
||||
elif sx_truthy((name == 'false')):
|
||||
return False
|
||||
elif sx_truthy((name == 'nil')):
|
||||
return NIL
|
||||
else:
|
||||
return error(sx_str('Undefined symbol: ', name))
|
||||
elif _match == 'keyword':
|
||||
return keyword_name(expr)
|
||||
elif _match == 'list':
|
||||
if sx_truthy(empty_p(expr)):
|
||||
return []
|
||||
else:
|
||||
return aser_list(expr, env)
|
||||
elif _match == 'spread':
|
||||
return expr
|
||||
else:
|
||||
return expr
|
||||
return result
|
||||
|
||||
# aser-list
|
||||
def aser_list(expr, env):
|
||||
@@ -2561,10 +2512,10 @@ def aser_fragment(children, env):
|
||||
result = aser(c, env)
|
||||
if sx_truthy((type_of(result) == 'list')):
|
||||
for item in result:
|
||||
if sx_truthy(((not sx_truthy(is_nil(item))) if not sx_truthy((not sx_truthy(is_nil(item)))) else (not sx_truthy(is_spread(item))))):
|
||||
if sx_truthy((not sx_truthy(is_nil(item)))):
|
||||
parts.append(serialize(item))
|
||||
else:
|
||||
if sx_truthy(((not sx_truthy(is_nil(result))) if not sx_truthy((not sx_truthy(is_nil(result)))) else (not sx_truthy(is_spread(result))))):
|
||||
if sx_truthy((not sx_truthy(is_nil(result)))):
|
||||
parts.append(serialize(result))
|
||||
if sx_truthy(empty_p(parts)):
|
||||
return ''
|
||||
@@ -2574,9 +2525,11 @@ def aser_fragment(children, env):
|
||||
# aser-call
|
||||
def aser_call(name, args, env):
|
||||
_cells = {}
|
||||
parts = [name]
|
||||
attr_parts = []
|
||||
child_parts = []
|
||||
_cells['skip'] = False
|
||||
_cells['i'] = 0
|
||||
provide_push('element-attrs', NIL)
|
||||
for arg in args:
|
||||
if sx_truthy(_cells['skip']):
|
||||
_cells['skip'] = False
|
||||
@@ -2585,26 +2538,27 @@ def aser_call(name, args, env):
|
||||
if sx_truthy(((type_of(arg) == 'keyword') if not sx_truthy((type_of(arg) == 'keyword')) else ((_cells['i'] + 1) < len(args)))):
|
||||
val = aser(nth(args, (_cells['i'] + 1)), env)
|
||||
if sx_truthy((not sx_truthy(is_nil(val)))):
|
||||
parts.append(sx_str(':', keyword_name(arg)))
|
||||
parts.append(serialize(val))
|
||||
attr_parts.append(sx_str(':', keyword_name(arg)))
|
||||
attr_parts.append(serialize(val))
|
||||
_cells['skip'] = True
|
||||
_cells['i'] = (_cells['i'] + 1)
|
||||
else:
|
||||
val = aser(arg, env)
|
||||
if sx_truthy((not sx_truthy(is_nil(val)))):
|
||||
if sx_truthy(is_spread(val)):
|
||||
for k in keys(spread_attrs(val)):
|
||||
v = dict_get(spread_attrs(val), k)
|
||||
parts.append(sx_str(':', k))
|
||||
parts.append(serialize(v))
|
||||
if sx_truthy((type_of(val) == 'list')):
|
||||
for item in val:
|
||||
if sx_truthy((not sx_truthy(is_nil(item)))):
|
||||
child_parts.append(serialize(item))
|
||||
else:
|
||||
if sx_truthy((type_of(val) == 'list')):
|
||||
for item in val:
|
||||
if sx_truthy((not sx_truthy(is_nil(item)))):
|
||||
parts.append(serialize(item))
|
||||
else:
|
||||
parts.append(serialize(val))
|
||||
child_parts.append(serialize(val))
|
||||
_cells['i'] = (_cells['i'] + 1)
|
||||
for spread_dict in sx_emitted('element-attrs'):
|
||||
for k in keys(spread_dict):
|
||||
v = dict_get(spread_dict, k)
|
||||
attr_parts.append(sx_str(':', k))
|
||||
attr_parts.append(serialize(v))
|
||||
provide_pop('element-attrs')
|
||||
parts = concat([name], attr_parts, child_parts)
|
||||
return sx_str('(', join(' ', parts), ')')
|
||||
|
||||
# SPECIAL_FORM_NAMES
|
||||
@@ -3659,7 +3613,8 @@ async def async_render(expr, env, ctx):
|
||||
elif _match == 'raw-html':
|
||||
return raw_html_content(expr)
|
||||
elif _match == 'spread':
|
||||
return expr
|
||||
sx_emit('element-attrs', spread_attrs(expr))
|
||||
return ''
|
||||
elif _match == 'symbol':
|
||||
val = (await async_eval(expr, env, ctx))
|
||||
return (await async_render(val, env, ctx))
|
||||
@@ -3691,7 +3646,7 @@ async def async_render_list(expr, env, ctx):
|
||||
elif sx_truthy((name == 'raw!')):
|
||||
return (await async_render_raw(args, env, ctx))
|
||||
elif sx_truthy((name == '<>')):
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), (await async_map_render(args, env, ctx))))
|
||||
return join('', (await async_map_render(args, env, ctx)))
|
||||
elif sx_truthy(starts_with_p(name, 'html:')):
|
||||
return (await async_render_element(slice(name, 5), args, env, ctx))
|
||||
elif sx_truthy(async_render_form_p(name)):
|
||||
@@ -3746,12 +3701,12 @@ async def async_render_element(tag, args, env, ctx):
|
||||
else:
|
||||
token = (svg_context_set(True) if sx_truthy(((tag == 'svg') if sx_truthy((tag == 'svg')) else (tag == 'math'))) else NIL)
|
||||
content_parts = []
|
||||
provide_push('element-attrs', NIL)
|
||||
for c in children:
|
||||
result = (await async_render(c, env, ctx))
|
||||
if sx_truthy(is_spread(result)):
|
||||
merge_spread_attrs(attrs, spread_attrs(result))
|
||||
else:
|
||||
content_parts.append(result)
|
||||
content_parts.append((await async_render(c, env, ctx)))
|
||||
for spread_dict in sx_emitted('element-attrs'):
|
||||
merge_spread_attrs(attrs, spread_dict)
|
||||
provide_pop('element-attrs')
|
||||
if sx_truthy(token):
|
||||
svg_context_reset(token)
|
||||
return sx_str('<', tag, render_attrs(attrs), '>', join('', content_parts), '</', tag, '>')
|
||||
@@ -3787,9 +3742,7 @@ async def async_render_component(comp, args, env, ctx):
|
||||
if sx_truthy(component_has_children(comp)):
|
||||
parts = []
|
||||
for c in children:
|
||||
r = (await async_render(c, env, ctx))
|
||||
if sx_truthy((not sx_truthy(is_spread(r)))):
|
||||
parts.append(r)
|
||||
parts.append((await async_render(c, env, ctx)))
|
||||
local['children'] = make_raw_html(join('', parts))
|
||||
return (await async_render(component_body(comp), local, ctx))
|
||||
|
||||
@@ -3805,9 +3758,7 @@ async def async_render_island(island, args, env, ctx):
|
||||
if sx_truthy(component_has_children(island)):
|
||||
parts = []
|
||||
for c in children:
|
||||
r = (await async_render(c, env, ctx))
|
||||
if sx_truthy((not sx_truthy(is_spread(r)))):
|
||||
parts.append(r)
|
||||
parts.append((await async_render(c, env, ctx)))
|
||||
local['children'] = make_raw_html(join('', parts))
|
||||
body_html = (await async_render(component_body(island), local, ctx))
|
||||
state_json = serialize_island_state(kwargs)
|
||||
@@ -3871,8 +3822,7 @@ async def dispatch_async_render_form(name, expr, env, ctx):
|
||||
if sx_truthy((len(expr) == 3)):
|
||||
return (await async_render(nth(expr, 2), env, ctx))
|
||||
else:
|
||||
results = (await async_map_render(slice(expr, 2), env, ctx))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), results))
|
||||
return join('', (await async_map_render(slice(expr, 2), env, ctx)))
|
||||
elif sx_truthy((name == 'cond')):
|
||||
clauses = rest(expr)
|
||||
if sx_truthy(cond_scheme_p(clauses)):
|
||||
@@ -3886,38 +3836,36 @@ async def dispatch_async_render_form(name, expr, env, ctx):
|
||||
if sx_truthy((len(expr) == 3)):
|
||||
return (await async_render(nth(expr, 2), local, ctx))
|
||||
else:
|
||||
results = (await async_map_render(slice(expr, 2), local, ctx))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), results))
|
||||
return join('', (await async_map_render(slice(expr, 2), local, ctx)))
|
||||
elif sx_truthy(((name == 'begin') if sx_truthy((name == 'begin')) else (name == 'do'))):
|
||||
if sx_truthy((len(expr) == 2)):
|
||||
return (await async_render(nth(expr, 1), env, ctx))
|
||||
else:
|
||||
results = (await async_map_render(rest(expr), env, ctx))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), results))
|
||||
return join('', (await async_map_render(rest(expr), env, ctx)))
|
||||
elif sx_truthy(is_definition_form(name)):
|
||||
(await async_eval(expr, env, ctx))
|
||||
return ''
|
||||
elif sx_truthy((name == 'map')):
|
||||
f = (await async_eval(nth(expr, 1), env, ctx))
|
||||
coll = (await async_eval(nth(expr, 2), env, ctx))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), (await async_map_fn_render(f, coll, env, ctx))))
|
||||
return join('', (await async_map_fn_render(f, coll, env, ctx)))
|
||||
elif sx_truthy((name == 'map-indexed')):
|
||||
f = (await async_eval(nth(expr, 1), env, ctx))
|
||||
coll = (await async_eval(nth(expr, 2), env, ctx))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), (await async_map_indexed_fn_render(f, coll, env, ctx))))
|
||||
return join('', (await async_map_indexed_fn_render(f, coll, env, ctx)))
|
||||
elif sx_truthy((name == 'filter')):
|
||||
return (await async_render((await async_eval(expr, env, ctx)), env, ctx))
|
||||
elif sx_truthy((name == 'for-each')):
|
||||
f = (await async_eval(nth(expr, 1), env, ctx))
|
||||
coll = (await async_eval(nth(expr, 2), env, ctx))
|
||||
return join('', filter(lambda r: (not sx_truthy(is_spread(r))), (await async_map_fn_render(f, coll, env, ctx))))
|
||||
return join('', (await async_map_fn_render(f, coll, env, ctx)))
|
||||
elif sx_truthy((name == 'provide')):
|
||||
prov_name = (await async_eval(nth(expr, 1), env, ctx))
|
||||
prov_val = (await async_eval(nth(expr, 2), env, ctx))
|
||||
body_start = 3
|
||||
body_count = (len(expr) - 3)
|
||||
provide_push(prov_name, prov_val)
|
||||
result = ((await async_render(nth(expr, body_start), env, ctx)) if sx_truthy((body_count == 1)) else (lambda results: join('', filter(lambda r: (not sx_truthy(is_spread(r))), results)))((await async_map_render(slice(expr, body_start), env, ctx))))
|
||||
result = ((await async_render(nth(expr, body_start), env, ctx)) if sx_truthy((body_count == 1)) else join('', (await async_map_render(slice(expr, body_start), env, ctx))))
|
||||
provide_pop(prov_name)
|
||||
return result
|
||||
else:
|
||||
@@ -4019,42 +3967,35 @@ async def async_invoke(f, *args):
|
||||
|
||||
# async-aser
|
||||
async def async_aser(expr, env, ctx):
|
||||
_match = type_of(expr)
|
||||
if _match == 'number':
|
||||
return expr
|
||||
elif _match == 'string':
|
||||
return expr
|
||||
elif _match == 'boolean':
|
||||
return expr
|
||||
elif _match == 'nil':
|
||||
return NIL
|
||||
elif _match == 'symbol':
|
||||
t = type_of(expr)
|
||||
result = NIL
|
||||
if sx_truthy((t == 'number')):
|
||||
result = expr
|
||||
elif sx_truthy((t == 'string')):
|
||||
result = expr
|
||||
elif sx_truthy((t == 'boolean')):
|
||||
result = expr
|
||||
elif sx_truthy((t == 'nil')):
|
||||
result = NIL
|
||||
elif sx_truthy((t == 'symbol')):
|
||||
name = symbol_name(expr)
|
||||
if sx_truthy(env_has(env, name)):
|
||||
return env_get(env, name)
|
||||
elif sx_truthy(is_primitive(name)):
|
||||
return get_primitive(name)
|
||||
elif sx_truthy((name == 'true')):
|
||||
return True
|
||||
elif sx_truthy((name == 'false')):
|
||||
return False
|
||||
elif sx_truthy((name == 'nil')):
|
||||
return NIL
|
||||
else:
|
||||
return error(sx_str('Undefined symbol: ', name))
|
||||
elif _match == 'keyword':
|
||||
return keyword_name(expr)
|
||||
elif _match == 'dict':
|
||||
return (await async_aser_dict(expr, env, ctx))
|
||||
elif _match == 'spread':
|
||||
return expr
|
||||
elif _match == 'list':
|
||||
if sx_truthy(empty_p(expr)):
|
||||
return []
|
||||
else:
|
||||
return (await async_aser_list(expr, env, ctx))
|
||||
result = (env_get(env, name) if sx_truthy(env_has(env, name)) else (get_primitive(name) if sx_truthy(is_primitive(name)) else (True if sx_truthy((name == 'true')) else (False if sx_truthy((name == 'false')) else (NIL if sx_truthy((name == 'nil')) else error(sx_str('Undefined symbol: ', name)))))))
|
||||
elif sx_truthy((t == 'keyword')):
|
||||
result = keyword_name(expr)
|
||||
elif sx_truthy((t == 'dict')):
|
||||
result = (await async_aser_dict(expr, env, ctx))
|
||||
elif sx_truthy((t == 'spread')):
|
||||
sx_emit('element-attrs', spread_attrs(expr))
|
||||
result = NIL
|
||||
elif sx_truthy((t == 'list')):
|
||||
result = ([] if sx_truthy(empty_p(expr)) else (await async_aser_list(expr, env, ctx)))
|
||||
else:
|
||||
return expr
|
||||
result = expr
|
||||
if sx_truthy(is_spread(result)):
|
||||
sx_emit('element-attrs', spread_attrs(result))
|
||||
return NIL
|
||||
else:
|
||||
return result
|
||||
|
||||
# async-aser-dict
|
||||
async def async_aser_dict(expr, env, ctx):
|
||||
@@ -4148,10 +4089,10 @@ async def async_aser_fragment(children, env, ctx):
|
||||
result = (await async_aser(c, env, ctx))
|
||||
if sx_truthy((type_of(result) == 'list')):
|
||||
for item in result:
|
||||
if sx_truthy(((not sx_truthy(is_nil(item))) if not sx_truthy((not sx_truthy(is_nil(item)))) else (not sx_truthy(is_spread(item))))):
|
||||
if sx_truthy((not sx_truthy(is_nil(item)))):
|
||||
parts.append(serialize(item))
|
||||
else:
|
||||
if sx_truthy(((not sx_truthy(is_nil(result))) if not sx_truthy((not sx_truthy(is_nil(result)))) else (not sx_truthy(is_spread(result))))):
|
||||
if sx_truthy((not sx_truthy(is_nil(result)))):
|
||||
parts.append(serialize(result))
|
||||
if sx_truthy(empty_p(parts)):
|
||||
return make_sx_expr('')
|
||||
@@ -4204,9 +4145,11 @@ async def async_parse_aser_kw_args(args, kwargs, children, env, ctx):
|
||||
async def async_aser_call(name, args, env, ctx):
|
||||
_cells = {}
|
||||
token = (svg_context_set(True) if sx_truthy(((name == 'svg') if sx_truthy((name == 'svg')) else (name == 'math'))) else NIL)
|
||||
parts = [name]
|
||||
attr_parts = []
|
||||
child_parts = []
|
||||
_cells['skip'] = False
|
||||
_cells['i'] = 0
|
||||
provide_push('element-attrs', NIL)
|
||||
for arg in args:
|
||||
if sx_truthy(_cells['skip']):
|
||||
_cells['skip'] = False
|
||||
@@ -4215,39 +4158,40 @@ async def async_aser_call(name, args, env, ctx):
|
||||
if sx_truthy(((type_of(arg) == 'keyword') if not sx_truthy((type_of(arg) == 'keyword')) else ((_cells['i'] + 1) < len(args)))):
|
||||
val = (await async_aser(nth(args, (_cells['i'] + 1)), env, ctx))
|
||||
if sx_truthy((not sx_truthy(is_nil(val)))):
|
||||
parts.append(sx_str(':', keyword_name(arg)))
|
||||
attr_parts.append(sx_str(':', keyword_name(arg)))
|
||||
if sx_truthy((type_of(val) == 'list')):
|
||||
live = filter(lambda v: (not sx_truthy(is_nil(v))), val)
|
||||
if sx_truthy(empty_p(live)):
|
||||
parts.append('nil')
|
||||
attr_parts.append('nil')
|
||||
else:
|
||||
items = map(serialize, live)
|
||||
if sx_truthy(some(lambda v: is_sx_expr(v), live)):
|
||||
parts.append(sx_str('(<> ', join(' ', items), ')'))
|
||||
attr_parts.append(sx_str('(<> ', join(' ', items), ')'))
|
||||
else:
|
||||
parts.append(sx_str('(list ', join(' ', items), ')'))
|
||||
attr_parts.append(sx_str('(list ', join(' ', items), ')'))
|
||||
else:
|
||||
parts.append(serialize(val))
|
||||
attr_parts.append(serialize(val))
|
||||
_cells['skip'] = True
|
||||
_cells['i'] = (_cells['i'] + 1)
|
||||
else:
|
||||
result = (await async_aser(arg, env, ctx))
|
||||
if sx_truthy((not sx_truthy(is_nil(result)))):
|
||||
if sx_truthy(is_spread(result)):
|
||||
for k in keys(spread_attrs(result)):
|
||||
v = dict_get(spread_attrs(result), k)
|
||||
parts.append(sx_str(':', k))
|
||||
parts.append(serialize(v))
|
||||
if sx_truthy((type_of(result) == 'list')):
|
||||
for item in result:
|
||||
if sx_truthy((not sx_truthy(is_nil(item)))):
|
||||
child_parts.append(serialize(item))
|
||||
else:
|
||||
if sx_truthy((type_of(result) == 'list')):
|
||||
for item in result:
|
||||
if sx_truthy((not sx_truthy(is_nil(item)))):
|
||||
parts.append(serialize(item))
|
||||
else:
|
||||
parts.append(serialize(result))
|
||||
child_parts.append(serialize(result))
|
||||
_cells['i'] = (_cells['i'] + 1)
|
||||
for spread_dict in sx_emitted('element-attrs'):
|
||||
for k in keys(spread_dict):
|
||||
v = dict_get(spread_dict, k)
|
||||
attr_parts.append(sx_str(':', k))
|
||||
attr_parts.append(serialize(v))
|
||||
provide_pop('element-attrs')
|
||||
if sx_truthy(token):
|
||||
svg_context_reset(token)
|
||||
parts = concat([name], attr_parts, child_parts)
|
||||
return make_sx_expr(sx_str('(', join(' ', parts), ')'))
|
||||
|
||||
# ASYNC_ASER_FORM_NAMES
|
||||
|
||||
@@ -285,6 +285,19 @@
|
||||
(assert-equal "(div :class \"card\" :style \"color:red\" \"hello\")"
|
||||
(render-sx "(div (make-spread {:class \"card\"}) (make-spread {:style \"color:red\"}) \"hello\")")))
|
||||
|
||||
(deftest "spread in fragment is filtered"
|
||||
(deftest "spread in fragment is silently dropped"
|
||||
(assert-equal "(<> \"hello\")"
|
||||
(render-sx "(<> (make-spread {:class \"card\"}) \"hello\")"))))
|
||||
(render-sx "(<> (make-spread {:class \"card\"}) \"hello\")")))
|
||||
|
||||
(deftest "stored spread in let binding"
|
||||
(assert-equal "(div :class \"card\" \"hello\")"
|
||||
(render-sx "(let ((card (make-spread {:class \"card\"})))
|
||||
(div card \"hello\"))")))
|
||||
|
||||
(deftest "spread in nested element"
|
||||
(assert-equal "(div (span :class \"inner\" \"hi\"))"
|
||||
(render-sx "(div (span (make-spread {:class \"inner\"}) \"hi\"))")))
|
||||
|
||||
(deftest "spread in non-element context silently drops"
|
||||
(assert-equal "hello"
|
||||
(render-sx "(do (make-spread {:class \"card\"}) \"hello\")"))))
|
||||
|
||||
Reference in New Issue
Block a user