Tree-Sitter-Bash Parser API: How to Use the MoonshotAI Parser Safely
TLDR: The @moonshot-ai/tree-sitter-bash package provides a pure-TypeScript Bash parser with a parse(source, options?) function that returns a discriminated ParseResult. Use it safely by setting budget limits, checking result.ok, and handling error states.
The tree-sitter-bash parser API from MoonshotAI offers a deterministic, type-safe way to parse Bash scripts in TypeScript without native dependencies. This complete guide covers the core API, safety guarantees, and best practices for reliable integration.
Understanding the Parse Function
The parse() function in src/parse.ts serves as the primary entry point for all tree-sitter-bash parser operations.
parse(source: string, options?: ParseOptions): ParseResult
The function accepts a Bash source string and optional configuration. It returns a discriminated union: { ok: true, root: SyntaxNode } on success, or { ok: false, error: ParseError } when parsing fails.
Key parameters to understand:
source— The complete Bash script to parseParseOptions— ExtendsParseBudgetfromsrc/budget.tswithtimeoutMsandmaxNodes
ParseBudget: Enforcing Safe Execution
Safety in the tree-sitter-bash parser API centers on the budget system defined in src/budget.ts.
The parser enforces deterministic limits to prevent runaway execution:
| Budget Parameter | Default Value | Purpose |
|---|---|---|
timeoutMs |
50 ms | Maximum parsing duration |
maxNodes |
50,000 | Maximum AST nodes generated |
When limits are exceeded, the parser throws a custom Aborted error. This prevents denial-of-service scenarios with malformed or malicious input.
import { parse } from '@moonshot-ai/tree-sitter-bash';
// Safe parsing with strict limits for untrusted input
const result = parse(untrustedScript, {
timeoutMs: 30,
maxNodes: 5_000
});
if (!result.ok) {
// Handle budget exhaustion or parse error
console.error('Parsing failed:', result.error);
}
Working with SyntaxNode Objects
The SyntaxNode interface in src/node.ts represents elements of the parsed Bash AST.
Each node provides:
type— Grammar node type (e.g.,"program","command","variable_name")text— Source text spanstartByte/endByte— Position in sourcehasError— Boolean indicating parse errors in this subtreedescendants— Array of child nodes for tree traversal
Helper functions assist common operations:
import { parse, descendantsOfType, createNode } from '@moonshot-ai/tree-sitter-bash';
const result = parse('echo $HOME && ls -la');
if (result.ok) {
// Find all variable references
const variables = descendantsOfType(result.root, 'variable_name');
// Check for partial parse errors
const errorNodes = result.root.descendants.filter(n => n.hasError);
}
Safe Usage Patterns for Tree-Sitter-Bash
Follow these four rules to use the tree-sitter-bash parser API safely in production.
1. Always Validate Parse Results
Never access result.root without confirming success.
const result = parse(script);
// Correct: check ok before accessing root
if (result.ok) {
analyzeTree(result.root);
} else {
failGracefully(result.error);
}
// Dangerous: throws if parsing failed
doSomething(result.root); // Never do this
2. Respect Node Error State
A successful parse may still contain error nodes indicating incomplete or invalid syntax.
if (result.ok) {
const hasErrors = result.root.descendants.some(n => n.hasError);
if (hasErrors) {
// Treat as unreliable — partial parse only
return { confidence: 'low', tree: result.root };
}
}
3. Configure Appropriate Budgets
Match limits to your threat model and latency requirements.
// Interactive editing: tight limits for responsiveness
const quickParse = parse(script, { timeoutMs: 10, maxNodes: 1_000 });
// Batch analysis of known-good files: relaxed limits
const thoroughParse = parse(script, { timeoutMs: 500, maxNodes: 500_000 });
4. Maintain Parser Purity
The tree-sitter-bash parser is pure: identical inputs produce identical outputs. Avoid mutable state patterns that could introduce non-determinism.
// Safe: parser has no side effects
const r1 = parse(source);
const r2 = parse(source);
// r1 and r2 are structurally equal
Complete Integration Example
This production-ready pattern demonstrates safe tree-sitter-bash parser API usage:
import { parse, SyntaxNode, ParseError } from '@moonshot-ai/tree-sitter-bash';
interface ParseAttempt {
success: boolean;
tree?: SyntaxNode;
error?: ParseError;
hasSyntaxErrors: boolean;
confidence: 'high' | 'medium' | 'low' | 'failed';
}
function safeParseBash(
source: string,
budget = { timeoutMs: 50, maxNodes: 50_000 }
): ParseAttempt {
const result = parse(source, budget);
if (!result.ok) {
return {
success: false,
error: result.error,
hasSyntaxErrors: true,
confidence: 'failed'
};
}
const errorNodes = result.root.descendants.filter(n => n.hasError);
const hasSyntaxErrors = errorNodes.length > 0;
return {
success: true,
tree: result.root,
hasSyntaxErrors,
confidence: hasSyntaxErrors ? 'low' : 'high'
};
}
// Usage
const analysis = safeParseBash(userInput, { timeoutMs: 30, maxNodes: 10_000 });
if (!analysis.success || analysis.confidence === 'low') {
// Degrade: skip advanced features, show warning
return basicFallbackMode(userInput);
}
// Proceed with full AST analysis
performRefactoring(analysis.tree!);
Key Source Files Reference
| File | Location | Responsibility |
|---|---|---|
src/index.ts |
Package root | Public API exports (parse, SyntaxNode, ParseBudget) |
src/parse.ts |
Core implementation | parse() function and ParseResult types |
src/node.ts |
AST structures | SyntaxNode interface and traversal helpers |
src/budget.ts |
Safety enforcement | ParseBudget, Aborted error class |
src/lexer.ts |
Tokenization | Low-level lexical scanner |
src/grammar.ts |
Language definition | Reserved words, operators, grammar constants |
Summary
- Entry point:
parse()insrc/parse.tsreturns a discriminated union — always checkresult.ok - Safety mechanism:
ParseBudgetinsrc/budget.tsenforcestimeoutMsandmaxNodeslimits withAbortederrors - Error handling: Treat
!result.okandnode.hasErroras unreliable states requiring graceful degradation - Pure design: Parser has no side effects; reuse for deterministic results
Frequently Asked Questions
What happens if parsing exceeds the budget limits?
The parser throws an Aborted error from src/budget.ts, and parse() returns { ok: false, error }. This prevents resource exhaustion from malicious or pathological input. Set limits appropriate to your workload and always handle the error case.
Can I parse partial or syntactically invalid Bash scripts?
Yes, but with caution. The parser may return result.ok: true with hasError: true on specific nodes. These error nodes indicate where the grammar failed. Inspect node.hasError throughout the tree before trusting any analysis results.
How do I find specific node types in the AST?
Use descendantsOfType(root, typeString) from src/node.ts or filter root.descendants manually. Both approaches traverse the complete tree — consider caching results for large documents to avoid repeated walks.
Is this parser API compatible with standard tree-sitter tools?
The @moonshot-ai/tree-sitter-bash API mirrors the official tree-sitter grammar but implements a pure-TypeScript parser. While node types and tree structure align with tree-sitter conventions, this is a standalone implementation without WebAssembly dependencies.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →