Core Interfaces
You will implement against the following interfaces. All are exported frompackages/core/src/types.ts.
AnalyzerPlugin
The contract every language plugin must satisfy:
StructuralAnalysis
The result returned by analyzeFile:
ImportResolution
The result returned by resolveImports:
CallGraphEntry
The result returned by the optional extractCallGraph:
Step-by-Step Guide
Install a tree-sitter grammar for the language
The easiest path to a robust parser is to use an existing tree-sitter
grammar. Check the
tree-sitter organization on GitHub or
npm for If no tree-sitter grammar exists for your language, you can write a
custom parser or use a regex-based approach inside
tree-sitter-<language> packages.Understand Anything uses
web-tree-sitter (WASM), not native
tree-sitter bindings. When you install a grammar package, you are
installing it for its .wasm artifact — not to call native C code
directly. Confirm the package ships a .wasm file under its package
directory.analyzeFile.Create the plugin file
Create a new file in
understand-anything-plugin/packages/core/src/plugins/. Follow the naming
pattern <language>-plugin.ts.Understand the three analysis methods
Each method has a distinct role in building the knowledge graph:
analyzeFile — structural extractionWalk the AST and populate all four arrays in StructuralAnalysis:functions— every named function/method with its line range, parameter names, and optional return typeclasses— every class with its line range, method names, and property namesimports— every import statement with its source module and imported symbol namesexports— every symbol exported from the file
resolveImports — path resolutionConvert raw import strings into usable paths:- Relative imports (starting with
./or../) should be resolved againstdirname(filePath)usingpath.resolve - Package imports (e.g.
express,@myorg/utils) are left as-is
extractCallGraph (optional) — call relationshipsTrack which function calls which, keyed by function name and line number.
The TreeSitterPlugin implementation uses a function name stack: push when
entering a function-like node, pop when leaving, and emit an entry for every
call_expression encountered while a function name is on the stack.Register the plugin with PluginRegistry
Import your plugin wherever you create the After registration, the registry routes
PluginRegistry and register
it after initialization:.py files to PythonPlugin
automatically via the built-in extension map:The built-in
EXTENSION_TO_LANGUAGE map in registry.ts already
includes common languages. If you are adding support for an extension
that is not listed (e.g. .rb for Ruby is listed; an obscure language
may not be), add an entry to that map inside
packages/core/src/plugins/registry.ts.Reference: TreeSitterPlugin
The built-in TreeSitterPlugin (packages/core/src/plugins/tree-sitter-plugin.ts)
is the reference implementation to study when building your own plugin. Key
patterns to follow:
Async init pattern
Load the WASM runtime and grammar files once in an
async init() method.
All subsequent analysis methods are synchronous.Parser lifecycle
Create a new parser instance per call to
analyzeFile or
extractCallGraph. Always call tree.delete() and parser.delete() when
done to free WASM memory.AST traversal
Use a recursive
traverse(node, visitor) helper to walk every node in the
tree. Match on node.type strings to identify constructs.Call graph stack
Track a
functionStack: string[] during traversal — push on entering a
function-like node, pop on leaving. Emit a CallGraphEntry for every
call_expression when the stack is non-empty.