content: validation vets list items + table cells element-deep (787/787)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 19s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 19s
validate only checked that list items / table rows-headers ARE lists; a non-string item or non-list/non-string-cell row passed yet crashes asText/ render/find-replace/search. Added ct-all-str?/ct-all-rows? + deepened list/ table branches (guarded against double-reporting). +9 validate tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,11 @@
|
||||
;; Tree detection is inline (class + st-iv-get) so this file needs no section.sx.
|
||||
;; Dispatch on block type is a validation-boundary concern, not core behaviour.
|
||||
;;
|
||||
;; Collection blocks are vetted element-deep: list items must all be strings and
|
||||
;; table rows must all be lists of strings — exactly what render/asText/
|
||||
;; find-replace/search assume — so malformed nested collections are caught at the
|
||||
;; boundary instead of crashing the render layer downstream.
|
||||
;;
|
||||
;; Requires (loaded by harness): block.sx, doc.sx.
|
||||
|
||||
(define ct-issue (fn (id kind detail) {:id id :detail detail :kind kind}))
|
||||
@@ -36,6 +41,28 @@
|
||||
|
||||
(define ct-uniq (fn (xs) (ct-uniq-loop xs (list))))
|
||||
|
||||
;; every element a string? / every row a list of strings? (for collection blocks)
|
||||
(define
|
||||
ct-all-str?
|
||||
(fn
|
||||
(xs)
|
||||
(if
|
||||
(= (len xs) 0)
|
||||
true
|
||||
(if (string? (first xs)) (ct-all-str? (rest xs)) false))))
|
||||
|
||||
(define
|
||||
ct-all-rows?
|
||||
(fn
|
||||
(rows)
|
||||
(if
|
||||
(= (len rows) 0)
|
||||
true
|
||||
(if
|
||||
(if (list? (first rows)) (ct-all-str? (first rows)) false)
|
||||
(ct-all-rows? (rest rows))
|
||||
false))))
|
||||
|
||||
;; ── tree flatten (descends into CtSection children; guards malformed children) ──
|
||||
(define
|
||||
ct-section-block?
|
||||
@@ -136,30 +163,43 @@
|
||||
"embed provider must be a string")))
|
||||
((= t "divider") (list))
|
||||
((= t "list")
|
||||
(append
|
||||
(ct-field-issue
|
||||
id
|
||||
(boolean? (blk-get b "ordered"))
|
||||
"list ordered must be a boolean")
|
||||
(ct-field-issue
|
||||
id
|
||||
(list? (blk-get b "items"))
|
||||
"list items must be a list")))
|
||||
(let
|
||||
((items (blk-get b "items")))
|
||||
(append
|
||||
(ct-field-issue
|
||||
id
|
||||
(boolean? (blk-get b "ordered"))
|
||||
"list ordered must be a boolean")
|
||||
(append
|
||||
(ct-field-issue id (list? items) "list items must be a list")
|
||||
(ct-field-issue
|
||||
id
|
||||
(if (list? items) (ct-all-str? items) true)
|
||||
"list items must all be strings")))))
|
||||
((= t "section")
|
||||
(ct-field-issue
|
||||
id
|
||||
(list? (blk-get b "children"))
|
||||
"section children must be a list"))
|
||||
((= t "table")
|
||||
(append
|
||||
(ct-field-issue
|
||||
id
|
||||
(list? (blk-get b "headers"))
|
||||
"table headers must be a list")
|
||||
(ct-field-issue
|
||||
id
|
||||
(list? (blk-get b "rows"))
|
||||
"table rows must be a list")))
|
||||
(let
|
||||
((headers (blk-get b "headers")) (rows (blk-get b "rows")))
|
||||
(append
|
||||
(append
|
||||
(ct-field-issue
|
||||
id
|
||||
(list? headers)
|
||||
"table headers must be a list")
|
||||
(ct-field-issue
|
||||
id
|
||||
(if (list? headers) (ct-all-str? headers) true)
|
||||
"table headers must all be strings"))
|
||||
(append
|
||||
(ct-field-issue id (list? rows) "table rows must be a list")
|
||||
(ct-field-issue
|
||||
id
|
||||
(if (list? rows) (ct-all-rows? rows) true)
|
||||
"table rows must all be lists of strings")))))
|
||||
((= t "callout")
|
||||
(append
|
||||
(ct-field-issue
|
||||
|
||||
Reference in New Issue
Block a user