Sitting Duck v1.8.0¶
Release date: 2026-04-26
A feature release adding parse-time filtering, call graph macros, and cross-language modifier fixes.
Highlights¶
- Parse-time filtering:
max_depthandpruneparameters onread_ast(). Reduce AST size at parse time instead of filtering after the fact.max_depthcaps tree depth;pruneremoves categories of nodes (syntax, comments, literals, imports, types, punctuation, unnamed, leaves, internal) with automatic tree healing — parent/child relationships, sibling indices, and descendant counts stay valid. ast_get_calls()andast_call_graph()macros for extracting function/method calls with call-type classification (function, method, constructor, macro) and building caller-to-callee graphs.ast_find_references()macro for scope-chain-aware symbol resolution — finds all references to a named symbol, correctly handling shadowed definitions.- C# method name extraction fix (#010). Methods like
private async Task<int> PrivateAsync()now correctly extractPrivateAsyncinstead of the return typeTask. Uses tree-sitter's field API (ts_node_child_by_field_name) for reliable name extraction. - Async/modifier extraction across 7 languages (#009).
async,static,suspend,pub,unsafe,mutating,inline, and access modifiers now correctly populate themodifiers[]column for Python, JavaScript, TypeScript, Rust, Kotlin, Swift, Dart, and C#.
New parameters¶
max_depth¶
Type: INTEGER
Default: -1 (unlimited)
Limit AST tree depth at parse time.
-- Root node only
SELECT * FROM read_ast('file.py', max_depth := 0);
-- Root + direct children
SELECT * FROM read_ast('file.py', max_depth := 1);
Boundary nodes at the depth limit have children_count = 0 and
descendant_count = 0 — the tree is structurally valid at the cut.
prune¶
Type: LIST(VARCHAR)
Default: [] (no pruning)
Remove categories of nodes at parse time with automatic tree healing.
-- Remove syntax-only nodes (keywords, punctuation)
SELECT * FROM read_ast('file.py', prune := ['syntax']);
-- Remove comments and literals
SELECT * FROM read_ast('file.py', prune := ['comments', 'literals']);
-- Combine with max_depth
SELECT * FROM read_ast('file.py', prune := ['syntax'], max_depth := 3);
| Policy | Removes | Mode |
|---|---|---|
syntax |
Syntax-only nodes (keywords, operators, brackets) | Node prune (re-parents children) |
comments |
Comment nodes | Node prune |
punctuation |
Parser punctuation tokens | Node prune |
unnamed |
Nodes with empty names | Node prune |
literals |
Literal value nodes | Subtree prune |
imports |
Import/use statements | Subtree prune |
types |
Type annotation nodes | Subtree prune |
leaves |
Leaf nodes (no children) | Node prune |
internal |
Non-exported internal definitions | Subtree prune |
Node prune removes the node but re-parents its children to the
grandparent. Subtree prune removes the node and all descendants.
Both modes heal the tree: parent_id, children_count,
descendant_count, and sibling_index are all recomputed.
New macros¶
ast_get_calls(source, language := NULL)¶
Extract all function/method calls with caller attribution and call-type classification.
SELECT caller_name, called_name, call_type, start_line
FROM ast_get_calls('src/**/*.py')
WHERE call_type = 'method';
| Column | Description |
|---|---|
file_path |
Source file |
caller_name |
Containing function (or <module>) |
called_name |
Called function/method name |
call_expression |
Code preview |
call_type |
function, method, constructor, or macro |
language |
Source language |
start_line |
Call site line |
node_id |
Call node ID |
caller_node_id |
Caller function node ID |
ast_call_graph(source, language := NULL)¶
Build an aggregated caller-to-callee graph.
SELECT caller, callee, call_type, call_count
FROM ast_call_graph('src/**/*.py')
WHERE caller = 'main';
| Column | Description |
|---|---|
file_path |
Source file |
caller |
Caller function name |
callee |
Called function name |
call_type |
Call classification |
call_count |
Number of calls |
ast_find_references(source, target_name, language := NULL)¶
Find all uses of a symbol via scope-chain resolution. Handles shadowed names correctly.
| Column | Description |
|---|---|
file_path |
Source file |
name |
Target symbol name |
ref_kind |
definition, call, or reference |
node_type |
AST node type |
start_line |
Location |
peek |
Code preview |
scope_name |
Containing function (or <module>) |
def_node_id |
Resolved definition's node ID |
Bug fixes¶
- C# method name extraction (#010):
method_declarationnodes now use tree-sitter's field API for thenamefield instead of the generic FIND_IDENTIFIER strategy, which incorrectly matched return type identifiers. - Async modifier extraction (#009): Seven language adapters
(Python, JavaScript, TypeScript, Rust, Kotlin, Swift, Dart, C#) now
correctly extract async/modifier keywords into the
modifiers[]column. Includes cross-language test audit harness with 88 assertions. ast_imports/ast_exportscorrectness (#68): Fixed parent filter for nested import nodes and IS_EXPORTED flag propagation.- IS_EXPORTED flag (#65): New bit-4 flag for file-level visibility,
used by
ast_exportsand the:exportedCSS pseudo-class.
Other changes¶
- Custom selector predicates via
ast_selector_predicate_*macros (#67) withPRAGMA sitting_duck_enable_dynamic_predicatesfor opt-in. - Documentation restructured into Divio framework (tutorials, how-to guides, reference, explanation).
- New doc pages: cookbook, call graphs tutorial, complexity analysis, security audit, parse-once-query-many, find dead code.
Stats¶
- 108 tests, 6084 assertions, 0 failures
- 44 commits since v1.7.4
Key commits¶
| Commit | Description |
|---|---|
2de7b74 |
fix: C# method name extraction uses field API (#010) |
de570c9 |
feat: add SemanticFilter struct and prune fields to ExtractionConfig |
7e106bb |
feat: implement CompilePrunePolicy for prune parameter compilation |
1edaf41 |
feat: register max_depth and prune parameters on all read_ast variants |
7939f96 |
feat: implement max_depth cutoff and prune traversal with tree healing |
d98cb59 |
fix: explicit subtree flag on SemanticFilter, re-parenting tests |
6e924fb |
feat: add ast_get_calls() and ast_call_graph() macros (#017) |
b0100cd |
feat: add ast_find_references() macro with scope-chain resolution (#016) |
3b82918 |
fix: extract async/modifier keywords for 7 languages (#009) |
a71cfb2 |
feat: add IS_EXPORTED flag for file-level visibility (#65) |
1ba713f |
feat: custom selector predicates via ast_selector_predicate_* macros (#67) |