Tree-sitter grammar for the Paradox family of games (e.g., Europa Universalis IV, Crusader Kings, Hearts of Iron) configuration and scripting files. This repository defines the grammar and ships bindings for multiple ecosystems so editors and tools can parse and highlight Paradox scripts.
- Incremental parsing via Tree-sitter
- Query files for syntax highlighting (queries/*.scm)
- Multi-language bindings: Node.js, Python, Rust, Swift, and C
- Corpus tests to validate grammar behavior (test/corpus)
- grammar.js — Tree-sitter grammar specification (source of truth)
- src/ — C sources for the generated parser
- queries/ — Highlighting and other Tree-sitter queries
- test/corpus — Tree-sitter CLI corpus tests
- bindings/ — Bindings and packaging for Node, Python, Rust, Swift, C
- tree-sitter.json — Grammar metadata
- A C/C++ toolchain (for native builds)
- Node.js (for Node binding/tests)
- Python 3.10+ (for Python binding/tests)
- Rust (optional; for crate build)
- Tree-sitter CLI (optional; for developing and running corpus tests)
- Install:
npm i -g tree-sitter-clior use the devDependency vianpx tree-sitter
- Install:
Install dependencies (builds the native addon):
npm installParse some Paradox code:
const Parser = require('tree-sitter');
const Paradox = require('tree-sitter-paradox');
const parser = new Parser();
parser.setLanguage(Paradox);
const source = 'country_event = { id = 42 }';
const tree = parser.parse(source);
console.log(tree.rootNode.toString());Run the Node tests:
npm testInstall the package in editable mode and run the binding test:
pip install -e .[core]
python -m unittest bindings/python/tests/test_binding.pyUse it from Python:
from tree_sitter import Parser
import tree_sitter_paradox as tsp
parser = Parser()
parser.set_language(tsp.language())
source = b"country_event = { id = 42 }"
tree = parser.parse(source)
print(tree.root_node)Add the crate in your Cargo.toml (if using this as a dependency from crates.io; otherwise use a path dependency):
[dependencies]
tree-sitter = "0.25"
tree-sitter-paradox = "0.2"Example usage:
use tree_sitter::{Parser, Language};
use tree_sitter_paradox as paradox;
fn main() {
let mut parser = Parser::new();
parser.set_language(&Language::from(paradox::language())).unwrap();
let source = "country_event = { id = 42 }";
let tree = parser.parse(source, None).unwrap();
println!("{}", tree.root_node().to_sexp());
}Build the crate in this repo:
cargo buildCommon tasks:
-
Run corpus tests (via Tree-sitter CLI):
npx tree-sitter test # or make test
-
Rebuild the native addon for Node:
npm install
-
Build WASM for playground (optional):
npm run prestart
-
Build the C library (optional):
make
When changing grammar.js:
- Keep changes minimal and add/adjust fixtures in test/corpus to cover new syntax or bug fixes.
- Update queries/*.scm if node types or structure affecting highlighting change.
This repository uses the official tree-sitter/workflows reusable workflows for release assets plus npm publication. Crates and PyPI are published separately with trusted publishing so no long-lived registry tokens need to live in GitHub secrets.
Release flow:
- Update the version consistently in
tree-sitter.json,package.json,Cargo.toml, andpyproject.toml. - Merge that change to
master. - The
Version tagworkflow verifies the four versions match, creates the annotated tagvX.Y.Z, and pushes it. - The tag triggers:
Create releaseviatree-sitter/workflows- npm publication via
tree-sitter/workflows - PyPI wheel and sdist builds in
.github/workflows/package.yml - PyPI publication via trusted publishing in
.github/workflows/package.yml - crates.io publication via trusted publishing in
.github/workflows/package.yml
If you need a manual recovery path, rerun Version tag after fixing the version files, or rerun the existing tag-triggered publish job in GitHub Actions. Publishing itself is intentionally restricted to v* tag pushes.
Repository configuration required:
- GitHub secret
NPM_TOKENfor npm publication - A crates.io trusted publisher configured for this repository with workflow file
package.ymland environmentrelease - A PyPI trusted publisher configured for this repository with workflow file
package.ymland environmentpypi
The first crates.io release still has to be published manually before trusted publishing can be enabled on crates.io.
Any editor integrating Tree-sitter can load this grammar. For Neovim or Helix, use a plugin that sources the parser and the queries/highlights.scm file, or configure them to find the generated library.
AGPL-3.0-only. See LICENSE for details.
- Built on Tree-sitter.
- Inspired by community grammars and Paradox modding documentation.