;; Extension — tree-wide block transforms. (st-bootstrap-classes!) (content/bootstrap!) (content-bootstrap-section!) (define d (doc-append (doc-append (doc-empty "d") (mk-heading "h" 1 "Top")) (mk-section "s" (list (mk-text "a" "A") (mk-heading "h2" 2 "Sub"))))) ;; ── map-type bumps heading levels everywhere ── (define d1 (content/map-type d "heading" (fn (b) (blk-set b "level" (+ (blk-get b "level") 1))))) (content-test "map-type top heading" (blk-send (doc-deep-find d1 "h") "level") 2) (content-test "map-type nested heading" (blk-send (doc-deep-find d1 "h2") "level") 3) (content-test "map-type leaves text" (str (blk-send (doc-deep-find d1 "a") "text")) "A") (content-test "map-type immutable" (blk-send (doc-deep-find d "h") "level") 1) (content-test "map-type preserves tree" (doc-tree-ids d1) (doc-tree-ids d)) ;; ── set-field-on rewrites all text blocks ── (define d2 (content/set-field-on d "text" "text" "REDACTED")) (content-test "set-field nested text" (str (blk-send (doc-deep-find d2 "a") "text")) "REDACTED") (content-test "set-field count" (len (filter (fn (b) (= (str (blk-get b "text")) "REDACTED")) (list (doc-deep-find d2 "a")))) 1) ;; ── map-blocks with custom predicate ── (define d3 (content/map-blocks d (fn (b) (= (blk-id b) "h2")) (fn (b) (blk-set b "text" "Changed")))) (content-test "map-blocks predicate hit" (str (blk-send (doc-deep-find d3 "h2") "text")) "Changed") (content-test "map-blocks predicate miss" (str (blk-send (doc-deep-find d3 "h") "text")) "Top") ;; ── image src rewrite (cdn migration) ── (define di (doc-append (doc-empty "d") (mk-image "img" "/old.png" "x"))) (content-test "image src rewrite" (str (blk-send (doc-find (content/set-field-on di "image" "src" "/cdn/new.png") "img") "src")) "/cdn/new.png") ;; ── no matching blocks → unchanged ── (content-test "no match unchanged" (asHTML (content/map-type d "embed" (fn (b) b))) (asHTML d)) ;; ── render after transform ── (content-test "render after map-type" (asHTML d1) "
A