Language detection and PARSE VERDICTS for the anchored patch gate.
Two questions, answered through tree-sitter (com.blockether/tree-sitter-language-pack, which sources Clojure from our own grammar fork):
code-languages)?error-nodes)?patch spends both: it re-parses what a write would produce and refuses an
edit that introduces a syntax error the file did not already have, naming the
line and the unpaired delimiter instead of a bare error count.
All native handles (Parser/Tree/Node) are opened and closed inside each call; only plain Clojure data escapes. Requiring this namespace also requires the native resolver, which selects the right per-platform FFI library at runtime.
Language detection and PARSE VERDICTS for the anchored `patch` gate.
Two questions, answered through tree-sitter (com.blockether/tree-sitter-language-pack,
which sources Clojure from our own grammar fork):
1. what language is this file, and is it a language where a parse error
means the file is genuinely broken (`code-languages`)?
2. where exactly does the new content fail to parse (`error-nodes`)?
`patch` spends both: it re-parses what a write would produce and refuses an
edit that introduces a syntax error the file did not already have, naming the
line and the unpaired delimiter instead of a bare error count.
All native handles (Parser/Tree/Node) are opened and closed inside each call;
only plain Clojure data escapes. Requiring this namespace also requires the
native resolver, which selects the right per-platform FFI library at runtime.Curated allowlist of tree-sitter languages vis treats as CODE — where a parse
ERROR means a genuinely broken file, worth refusing an edit over. Deliberately
EXCLUDES the pack's prose / markup / loose grammars (vimdoc — remember .txt
maps to it! — markdown, rst, csv, html, xml, ini …) that carry error nodes on
normal content and would fire false positives. Real programming languages plus
the STRICT structured-config formats (json/yaml/toml). This is the vetted subset
the syntax guard runs on; extend it as vis takes on more languages.
Curated allowlist of tree-sitter languages vis treats as CODE — where a parse ERROR means a genuinely broken file, worth refusing an edit over. Deliberately EXCLUDES the pack's prose / markup / loose grammars (vimdoc — remember `.txt` maps to it! — markdown, rst, csv, html, xml, ini …) that carry error nodes on normal content and would fire false positives. Real programming languages plus the STRICT structured-config formats (json/yaml/toml). This is the vetted subset the syntax guard runs on; extend it as vis takes on more languages.
(detect-language path)tree-sitter language name for path (by extension/shebang), or nil. NOTE: the
pack recognizes HUNDREDS of grammars, including prose/markup — .txt maps to
vimdoc (Vim :help files), .md→markdown, .csv→csv — which parse WITH error
nodes on ordinary content. For 'is a syntax error meaningful here?' test the
result against code-languages.
Falls back to extra-extension->language (currently .edn→clojure) ONLY
when the pack returns nil, covering Clojure-family extensions the pack's table
omits so their files are still parse-checked.
tree-sitter language name for `path` (by extension/shebang), or nil. NOTE: the pack recognizes HUNDREDS of grammars, including prose/markup — `.txt` maps to `vimdoc` (Vim `:help` files), `.md`→markdown, `.csv`→csv — which parse WITH error nodes on ordinary content. For 'is a syntax error meaningful here?' test the result against `code-languages`. Falls back to `extra-extension->language` (currently `.edn`→`clojure`) ONLY when the pack returns nil, covering Clojure-family extensions the pack's table omits so their files are still parse-checked.
(error-nodes lang source)Every ERROR / MISSING node tree-sitter finds in source (parsed as lang),
as [{:line :col :byte-col :end-line :end-col :start-byte :end-byte :kind
:missing? :text} …] in document order (1-based line, 0-based Unicode
code-point col; :byte-col preserves tree-sitter's raw UTF-8 column). Empty
when the source parses clean or the language can't be parsed. Public so an
edit guard can turn a bare "N syntax error(s)" rejection into a LOCATED,
actionable message — a MISSING node even NAMES the delimiter the parser
expected (:kind = ], ), …).
An ERROR node reports the most actionable UNBALANCED DELIMITER directly inside
it, not necessarily the node's own start: an unclosed form can make tree-sitter
open one ERROR over the whole file whose start is line 1. Those rows carry
:delimiter and :error-line (where recovery began), and :text is the
offending LINE. Raw byte spans remain available so a diagnostic can recognize
and look through a broad recovery wrapper that contains a more specific ERROR.
Every ERROR / MISSING node tree-sitter finds in `source` (parsed as `lang`),
as [{:line :col :byte-col :end-line :end-col :start-byte :end-byte :kind
:missing? :text} …] in document order (1-based line, 0-based Unicode
code-point col; `:byte-col` preserves tree-sitter's raw UTF-8 column). Empty
when the source parses clean or the language can't be parsed. Public so an
edit guard can turn a bare "N syntax error(s)" rejection into a LOCATED,
actionable message — a MISSING node even NAMES the delimiter the parser
expected (`:kind` = `]`, `)`, …).
An ERROR node reports the most actionable UNBALANCED DELIMITER directly inside
it, not necessarily the node's own start: an unclosed form can make tree-sitter
open one ERROR over the whole file whose start is line 1. Those rows carry
`:delimiter` and `:error-line` (where recovery began), and `:text` is the
offending LINE. Raw byte spans remain available so a diagnostic can recognize
and look through a broad recovery wrapper that contains a more specific ERROR.(guarded-language path)The detected language for path when Vis treats its parse errors as real syntax
failures, otherwise nil. This is the single policy boundary shared by patch and
sandboxed Python writers; broad language detection alone must never gate prose.
The detected language for `path` when Vis treats its parse errors as real syntax failures, otherwise nil. This is the single policy boundary shared by `patch` and sandboxed Python writers; broad language detection alone must never gate prose.
(top-level-nodes lang source)The NAMED direct children of the parse root of source (read as lang), in
document order: [{:kind :text :children [{:kind :text} …]} …]. One level of
grandchildren comes along, which is what a DECLARATION scan needs — punctuation
tokens are skipped, so a TOML table's own header key IS its child 0. Empty when
lang is nil; input that does not parse answers the recovery nodes tree-sitter
produced (ERROR …), never a declaration.
PARSED, never scanned: a [tool.uv] written inside a comment or a string stays a
comment / string node here, so a caller reading declarations out of a config file
never mistakes prose for a declaration.
The NAMED direct children of the parse root of `source` (read as `lang`), in
document order: [{:kind :text :children [{:kind :text} …]} …]. One level of
grandchildren comes along, which is what a DECLARATION scan needs — punctuation
tokens are skipped, so a TOML table's own header key IS its child 0. Empty when
`lang` is nil; input that does not parse answers the recovery nodes tree-sitter
produced (`ERROR` …), never a declaration.
PARSED, never scanned: a `[tool.uv]` written inside a comment or a string stays a
comment / string node here, so a caller reading declarations out of a config file
never mistakes prose for a declaration.(transition-verdict lang original candidate)Compare original and candidate under lang. Returns a plain-data verdict:
:clean, :still-broken, or :introduced-error, with parser rows when relevant.
A pre-existing broken file remains writable so a caller can repair it. Callers own
policy beyond this verdict: patch may attempt an explicit delimiter repair while
raw writers must either preserve the exact candidate or refuse it.
Compare `original` and `candidate` under `lang`. Returns a plain-data verdict: `:clean`, `:still-broken`, or `:introduced-error`, with parser rows when relevant. A pre-existing broken file remains writable so a caller can repair it. Callers own policy beyond this verdict: `patch` may attempt an explicit delimiter repair while raw writers must either preserve the exact candidate or refuse it.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |