How to Add Custom Language Support to code-review-graph: A Complete Guide
You can add custom language support to code-review-graph by creating a languages.toml configuration file in your repository's .code-review-graph/ directory, specifying the file extensions, Tree-sitter grammar, and AST node types for your target language.
The code-review-graph tool analyzes repository source files by mapping file extensions to language identifiers and parsing them with Tree-sitter grammars. While it ships with built-in support for common languages defined in code_review_graph/constants.py via dictionaries like EXTENSION_TO_LANGUAGE and _FUNCTION_TYPES, you can extend the parser to support additional languages without modifying the core codebase using a declarative configuration approach.
How the Custom Language System Works
The custom language mechanism follows a defensive, config-driven architecture that merges user-defined language definitions into the parser at runtime.
Configuration File Location and Structure
The system expects a TOML file named languages.toml placed under the repository's .code-review-graph/ directory. This path is defined by the constant CONFIG_RELATIVE_PATH = Path(".code-review-graph") / "languages.toml" in code_review_graph/custom_languages.py (line 47).
Validation and Caching
The loader implements strict validation through the _validate_entry and _load_uncached functions in custom_languages.py (lines 97-102). Each entry must specify a unique language name, valid file extensions, an existing Tree-sitter grammar (verified via tslp.get_language), and appropriate node-type lists. To optimize performance, the loader maintains a per-path cache keyed by file modification time and size, avoiding unnecessary re-parsing of unchanged configuration files.
Parser Integration
Upon loading, custom language data merges into the parser's internal lookup tables. The CodeParser class in code_review_graph/parser.py combines your custom extensions with built-in mappings, populating node-type dictionaries including _class_types, _function_types, _import_types, and _call_types (lines 53-71). The _get_parser method (lines 72-77) then uses your custom grammar field to instantiate the correct Tree-sitter parser.
Creating Your Custom Language Definition
Define your language by specifying file extensions, the Tree-sitter grammar name, and the AST node types that represent functions, classes, imports, and calls.
Example: Adding Erlang Support
Create a .code-review-graph/languages.toml file in your repository root:
[languages.erlang]
extensions = [".erl", ".hrl"]
grammar = "erlang"
function_node_types = ["function_clause"]
class_node_types = ["record_decl"]
import_node_types = ["import_attribute"]
call_node_types = ["call"]
comment = "Erlang support via bundled grammar"
The grammar field must reference a parser available in the bundled tree-sitter-language-pack. After adding this file, rebuild your code review graph to index .erl and .hrl files.
Handling Non-Standard Name Fields
Some Tree-sitter grammars store identifier names in unconventional AST fields. Use the name_field array to specify alternative field names:
[languages.latex]
extensions = [".tex"]
grammar = "latex"
class_node_types = ["section", "chapter", "subsection"]
name_field = ["name", "text", "declaration"]
Step-by-Step Implementation Guide
Follow these steps to add custom language support to your repository:
-
Create the configuration directory
mkdir -p .code-review-graph -
Write the language definition
Create
.code-review-graph/languages.tomlwith your language specifications, ensuring the grammar exists intree-sitter-language-pack. -
Trigger a rebuild
uv run code-review-graph build -
Verify the integration
uv run code-review-graph graph --path src/math_utils.erlThe output should show nodes with
language = "erlang"containing properly typed Function and Class entries.
Programmatic Access
You can inspect loaded custom languages programmatically using the loader directly:
from pathlib import Path
from code_review_graph.custom_languages import load_custom_languages
repo_root = Path(".")
custom = load_custom_languages(
repo_root,
builtin_extensions=EXTENSION_TO_LANGUAGE,
builtin_languages=_builtin_language_names(),
)
print(custom) # => {'erlang': CustomLanguage(...)}
This approach is useful for testing configuration validity before running a full build.
Summary
- Config-driven approach: Place a
languages.tomlfile in.code-review-graph/to define custom languages without modifying source code. - Validation system: The loader in
code_review_graph/custom_languages.pyvalidates grammar availability and extension uniqueness, logging warnings for invalid entries while allowing the build to continue. - Parser integration: Custom definitions merge into
CodeParser's internal tables (_extension_map,_class_types, etc.) during initialization at lines 53-71 ofparser.py. - Tree-sitter dependency: The
grammarfield must match a language available in the bundledtree-sitter-language-pack.
Frequently Asked Questions
What happens if I specify a grammar that isn't in the tree-sitter-language-pack?
The loader skips the entry with a warning message and continues processing other languages. This defensive behavior ensures that missing grammars never break existing functionality, as implemented in the _validate_entry function within code_review_graph/custom_languages.py.
Can I override built-in language definitions?
Yes. When load_custom_languages() merges custom languages into the parser's tables in code_review_graph/parser.py, your custom extensions and node types take precedence over the built-in mappings defined in code_review_graph/constants.py.
How does the caching mechanism work?
The loader in code_review_graph/custom_languages.py caches parsed configurations based on file modification time and size (line 97). This prevents re-parsing languages.toml on every build, significantly improving performance for large repositories.
What node types should I specify for my language?
You must provide arrays for function_node_types, class_node_types, import_node_types, and call_node_types. These correspond to Tree-sitter AST node names specific to your grammar. Consult your Tree-sitter grammar's documentation or use the tree-sitter parse command to identify correct node names.
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 →