;; Extension — block query + table of contents + prose search. (st-bootstrap-classes!) (content/bootstrap!) (content-bootstrap-text!) (content-bootstrap-section!) (content-bootstrap-table!) (content-bootstrap-callout!) (define d (doc-append (doc-append (doc-append (doc-append (doc-empty "d") (mk-heading "h1" 1 "Intro")) (mk-text "p1" "para")) (mk-image "img" "/a.png" "alt")) (mk-section "s" (list (mk-heading "h2" 2 "Sub") (mk-text "p2" "more") (mk-image "img2" "/b.png" "b"))))) ;; ── select-type (tree-wide) ── (content-test "select headings ids" (map (fn (b) (blk-id b)) (content/select-type d "heading")) (list "h1" "h2")) (content-test "select images ids" (map (fn (b) (blk-id b)) (content/select-type d "image")) (list "img" "img2")) (content-test "select text ids" (map (fn (b) (blk-id b)) (content/select-type d "text")) (list "p1" "p2")) (content-test "select section ids" (map (fn (b) (blk-id b)) (content/select-type d "section")) (list "s")) ;; ── count-type ── (content-test "count headings" (content/count-type d "heading") 2) (content-test "count images" (content/count-type d "image") 2) (content-test "count dividers" (content/count-type d "divider") 0) ;; ── select with custom predicate ── (content-test "select-ids custom" (content/select-ids d (fn (b) (= (blk-type b) "image"))) (list "img" "img2")) (content-test "select custom field" (map (fn (b) (blk-id b)) (content/select d (fn (b) (if (= (blk-type b) "heading") (= (blk-get b "level") 2) false)))) (list "h2")) ;; ── headings / TOC ── (content-test "headings TOC" (content/headings d) (list {:id "h1" :text "Intro" :level 1} {:id "h2" :text "Sub" :level 2})) (content-test "empty doc no headings" (content/headings (doc-empty "e")) (list)) ;; ── deeply nested ── (define deep (doc-append (doc-empty "d") (mk-section "o" (list (mk-section "i" (list (mk-heading "deep" 3 "Deep"))))))) (content-test "deep heading found" (map (fn (b) (blk-id b)) (content/select-type deep "heading")) (list "deep")) (content-test "deep toc level" (get (first (content/headings deep)) :level) 3) ;; ── prose search (content/search-text) ── ;; "cat" appears in text, image alt, a list item, a table cell, and a callout ;; — every text-bearing field — so search must find all five via asText. (define sd (doc-append (doc-append (doc-append (doc-append (doc-append (doc-empty "sd") (mk-heading "sh" 1 "Welcome aboard")) (mk-text "st" "the cat sat")) (mk-image "si" "/x.png" "a cat photo")) (mk-list "sl" false (list "first cat" "second dog"))) (mk-section "sec" (list (mk-table "stb" (list "Animal") (list (list "cat") (list "fish"))) (mk-callout "sc" "note" "beware of cat"))))) (content-test "search across every text-bearing field" (content/search-text-ids sd "cat") (list "st" "si" "sl" "stb" "sc")) (content-test "search count" (len (content/search-text sd "cat")) 5) (content-test "search heading text" (content/search-text-ids sd "Welcome") (list "sh")) (content-test "search list item only" (content/search-text-ids sd "dog") (list "sl")) (content-test "search no match" (content/search-text-ids sd "zzz") (list)) ;; section containers are excluded — a term living only inside a section's ;; children returns the child, never the section wrapper. (content-test "search excludes section wrapper" (content/search-text-ids sd "fish") (list "stb")) (content-test "search returns block objects" (blk-id (first (content/search-text sd "Welcome"))) "sh")