# How Understand-Anything Language Extractors Parse TypeScript, Python, Rust, and Go

> Learn how Understand Anything's Language Extractors parse TypeScript, Python, Rust, and Go. Discover how tree-sitter ASTs create unified code analysis and call graphs with a single interface.

- Repository: [Yuxiang Lin/Understand-Anything](https://github.com/Lum1104/Understand-Anything)
- Tags: how-to-guide
- Published: 2026-06-06

---

**Understand-Anything normalizes multi-language code analysis through a single `LanguageExtractor` interface, where each implementation traverses tree-sitter ASTs to generate standardized structural data and call graphs.**

Understand-Anything is an open-source code comprehension framework that unifies parsing across heterogeneous languages. Its **language extractors** convert language-specific syntax into two consistent outputs: a `StructuralAnalysis` object containing functions, classes, and imports, and a `CallGraphEntry` array mapping caller-callee relationships. According to the [Understand-Anything](https://github.com/Lum1104/Understand-Anything) source code, each extractor implements an identical interface while handling the unique AST node types of its target language.

## The LanguageExtractor Interface and Core Architecture

All extractors inherit from the shared `LanguageExtractor` interface defined in [[`types.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/types.ts)](https://github.com/Lum1104/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/plugins/extractors/types.ts). The contract requires two primary methods: `extractStructure()` and `extractCallGraph()`, both accepting a tree-sitter `rootNode` and returning normalized data.

Every extractor follows a four-phase pipeline:

1. **Walk top-level AST nodes** via `rootNode.children`.
2. **Dispatch** each node to specialized helpers like `processTopLevelNode()` based on `node.type`.
3. **Collect** parameters, return types, imports, and exports using utility functions that understand language-specific AST shapes.
4. **Build call graphs** by recursively traversing the tree, maintaining a stack of current function names, and recording call expressions.

## TypeScript and JavaScript Parsing

The TypeScript extractor ([[`typescript-extractor.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/typescript-extractor.ts)](https://github.com/Lum1104/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/plugins/extractors/typescript-extractor.ts)) handles both JavaScript and TypeScript source files by targeting the tree-sitter TypeScript grammar.

### Parameter and Return Type Extraction

The `extractParams()` method walks `formal_parameters` nodes, processing `required_parameter`, `optional_parameter`, and rest patterns (`...args`). It extracts identifiers from simple bindings and typed parameters. Return types are captured via `extractReturnType()`, which reads the optional `type_annotation` field attached to function declarations.

### Import and Export Processing

`extractImportSpecifiers()` parses three import variants: `named_imports` (destructured imports), `namespace_import` (`* as ns`), and default identifiers. The `processTopLevelNode()` router directs `function_declaration`, `class_declaration`, `lexical_declaration` (const/let), `import_statement`, and `export_statement` nodes to appropriate handlers, building the exports list from top-level declarations.

### Call Graph Construction

`extractCallGraph()` identifies function-like nodes—including `function_declaration`, `method_definition`, `arrow_function`, and `function_expression`—to maintain a scope stack. It records every `call_expression` where the callee contains a `function` field, associating the call with the current function context and line number.

## Python Parsing

The Python implementation ([[`python-extractor.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/python-extractor.ts)](https://github.com/Lum1104/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/plugins/extractors/python-extractor.ts)) adapts to Python's dynamic nature and explicit self-references.

### Dynamic Parameter Handling

`extractParams()` supports plain identifiers, typed parameters, default values, and splat patterns (`*args`, `**kwargs`). It explicitly skips the implicit first parameter when it equals `self` or `cls`, avoiding noise in method signatures. Return type annotations are retrieved via `extractReturnType()`, which reads the `return_type` field on `function_definition` nodes.

### Import Statements and Implicit Exports

Python uses two extraction helpers: `extractImport()` handles `import` statements by collecting `dotted_name` and `aliased_import` nodes, while `extractFromImport()` processes `from ... import ...` forms, including wildcard imports. Unlike TypeScript, Python has no explicit export syntax; the private `addExport()` method automatically registers top-level functions and classes as exports.

### Call Graph Generation

The extractor records `call` nodes where the callee is an `identifier` or `attribute` (method access). It maintains a function name stack by tracking `function_definition` and `class_definition` entries, creating `CallGraphEntry` objects linking the current scope to the callee with line numbers.

## Rust Parsing

The Rust extractor ([[`rust-extractor.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/rust-extractor.ts)](https://github.com/Lum1104/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/plugins/extractors/rust-extractor.ts)) manages Rust's complex type system and visibility modifiers.

### Visibility Controls and Export Detection

The `isPublic()` helper checks for `visibility_modifier` nodes starting with `pub`, determining which items are exported. Only public functions, structs, and traits are added to the exports list. The `extractParams()` method walks `parameters` nodes while ignoring `self_parameter` receivers, and `extractReturnType()` reads the `return_type` named field of `function_item` nodes.

### Type System Extraction

The extractor maps Rust's type system to the `classes` array through specialized methods: `extractStruct()`, `extractEnum()`, and `extractTrait()`. These populate `properties` (struct fields or enum variants) and `methods` (including trait signatures). `extractImpl()` processes implementation blocks, attaching methods to types via a `methodsByType` map and treating `pub` methods as exports.

### Call Graph and Path Extraction

`extractUseDeclaration()` handles Rust's `use` statement variations—single, scoped, list, and wildcard—extracting source paths via `extractScopedPath()`. For call graphs, `extractCallGraph()` captures `call_expression` nodes and resolves callee names using `extractCalleeName()`, which handles simple identifiers, field expressions (`obj.method`), and scoped identifiers (`Vec::new`).

## Go Parsing

The Go extractor ([[`go-extractor.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/go-extractor.ts)](https://github.com/Lum1104/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/plugins/extractors/go-extractor.ts)) implements Go-specific conventions including exported identifiers and receiver methods.

### Export Conventions and Method Receivers

`isExported()` checks if a name begins with an uppercase letter, following Go's capitalization-based export rules. `extractParams()` iterates over `parameter_declaration` nodes, collecting multiple identifiers from single declarations (e.g., `a, b int`). `extractReceiverType()` reads receiver declarations to associate methods with their underlying struct types.

### Struct and Interface Analysis

Both structs and interfaces are stored in the `classes` array. `extractStruct()` gathers field identifiers from struct literals, while `extractInterface()` records method names from `method_elem` nodes within interface definitions.

### Import Handling and Call Graphs

`extractImportDeclaration()` parses grouped and single imports, unquoting path strings and determining specifiers from aliases or the last path component. The call graph walker records `call_expression` nodes, pushing function and method names onto a scope stack before associating calls with their containing functions.

## Using the Extractors Programmatically

You can invoke any extractor directly by loading the appropriate tree-sitter WASM grammar and calling the standardized interface:

```typescript
import { LanguageExtractor } from './packages/core/src/plugins/extractors/types.js';
import { TypeScriptExtractor } from './packages/core/src/plugins/extractors/typescript-extractor.js';
import { parse } from 'web-tree-sitter';

async function analyzeSource(source: string) {
  await parse.init();
  const parser = new parse.Parser();
  const Lang = await parse.Language.load(
    'node_modules/tree-sitter-typescript/tsx.wasm'
  );
  parser.setLanguage(Lang);
  const tree = parser.parse(source);
  
  const extractor: LanguageExtractor = new TypeScriptExtractor();
  const structure = extractor.extractStructure(tree.rootNode);
  const callGraph = extractor.extractCallGraph(tree.rootNode);
  
  return { structure, callGraph };
}

```

Replace `TypeScriptExtractor` with `PythonExtractor`, `RustExtractor`, or `GoExtractor`, and load the corresponding WASM file (`tree-sitter-python`, `tree-sitter-rust`, or `tree-sitter-go`). The public API remains identical across all languages.

## Summary

- **Unified Interface**: All extractors implement `LanguageExtractor` from [[`types.ts`](https://github.com/Lum1104/Understand-Anything/blob/main/types.ts)](https://github.com/Lum1104/Understand-Anything/blob/main/understand-anything-plugin/packages/core/src/plugins/extractors/types.ts), providing `extractStructure()` and `extractCallGraph()` methods.
- **Tree-sitter Foundation**: Every extractor operates on tree-sitter ASTs, using language-specific node types like `function_definition` (Python) or `function_item` (Rust).
- **Normalization**: Language quirks—such as Go's uppercase exports, Rust's visibility modifiers, or Python's implicit exports—are normalized into consistent `StructuralAnalysis` and `CallGraphEntry` formats.
- **Extensibility**: New languages can be supported by implementing the interface and walking the appropriate AST nodes, following the patterns established in the four reference implementations.

## Frequently Asked Questions

### What is the LanguageExtractor interface in Understand-Anything?

The `LanguageExtractor` interface is a TypeScript contract defined in the core types module that standardizes how the framework interacts with language-specific parsers. It requires implementations to provide two methods: `extractStructure()`, which returns function signatures, classes, and imports, and `extractCallGraph()`, which returns caller-callee relationships. This abstraction allows Understand-Anything to treat TypeScript, Python, Rust, and Go uniformly despite their syntactic differences.

### How does Understand-Anything handle language-specific AST differences?

Each extractor contains private helper methods—such as `extractParams()`, `extractReturnType()`, and `processTopLevelNode()`—that understand the specific AST node types of their target language. For example, the Rust extractor handles `visibility_modifier` nodes to determine exports, while the Go extractor checks for uppercase identifiers. These helpers normalize the diverse AST structures into the common `StructuralAnalysis` format before returning data to the caller.

### Can I add support for additional languages to Understand-Anything?

Yes, you can extend the system by creating a new class that implements the `LanguageExtractor` interface and writing tree-sitter traversal logic for your target language. You must implement logic to extract functions, classes or structs, imports, and exports into the standardized output format, plus build a call graph by tracking function scopes and call expressions. Follow the file structure in [`packages/core/src/plugins/extractors/`](https://github.com/Lum1104/Understand-Anything/tree/main/understand-anything-plugin/packages/core/src/plugins/extractors) and reference existing extractors for implementation patterns.

### How does the call graph extraction work across different languages?

Call graph extraction follows a consistent pattern across all extractors: the walker maintains a stack of function names as it descends the AST, and when it encounters a call node—such as `call_expression` in TypeScript/Rust/Go or `call` in Python—it records the relationship between the current function scope and the callee. Language-specific logic in helpers like `extractCalleeName()` handles how the callee identifier is extracted, whether through simple identifiers, attribute access (Python), or scoped paths (Rust).