tree-sitter-powershell

A tree-sitter grammar for parsing PowerShell scripts, including obfuscated malware samples, with bindings for Rust, Node, Python, Go, C, and Swift.

Library
PyPI
v0.26.4
85stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
41/100Fair
Development Activity36
Maintenance12
Community44
Maturity52
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
61/100Good
Architecture74
Code Quality55
Innovation68
Learning Curve45

tree-sitter-powershell is an incremental parsing grammar for the PowerShell scripting language, built on the tree-sitter parser generator. Maintained by Airbus CERT, it turns PowerShell source into a concrete syntax tree covering the language’s control flow, classes, pipelines, expressions, and string/number literal forms, and ships a purpose-built test corpus for deliberately obfuscated PowerShell of the kind commonly seen in malicious scripts.

The grammar is authored once in grammar.js and compiled by the tree-sitter CLI into a portable C parser, then re-exported through native bindings for Rust, Node.js, Python, Go, C, and Swift, so the same parse results are available whether you’re building an editor extension, a static-analysis tool, or a security scanner.

What You Get

  • A complete PowerShell grammar (grammar.js) covering variables, pipelines, classes, control flow, and both string and numeric literal forms
  • Precompiled native bindings for Rust, Node.js, Python, Go, C, and Swift, each exposing the same LANGUAGE entry point
  • Ready-to-use tree-sitter query files for syntax highlighting (queries/highlights.scm) and code folding (queries/folds.scm)
  • A dedicated obfuscation test corpus demonstrating how the grammar handles string-format reassembly and backtick-escaped identifiers found in malicious scripts

Common Use Cases

  • Editor and IDE syntax highlighting for PowerShell files via tree-sitter-based highlighters (e.g. Neovim, Zed, Helix)
  • Static analysis and deobfuscation tooling that needs a structured parse tree of suspicious PowerShell scripts
  • Building custom linters or code-intelligence tools (folding, outline views, go-to-definition) on top of PowerShell source
  • Embedding PowerShell parsing inside a larger multi-language tree-sitter-based toolchain

Under The Hood

Architecture The grammar is defined declaratively in grammar.js using a precedence table and an external scanner (src/scanner.c) that resolves PowerShell’s context-sensitive statement-terminator token, something the pure grammar can’t express on its own. tree-sitter-cli compiles this into a generated parser.c plus grammar.json/node-types.json describing the resulting node schema. Every per-language binding (Rust, Node, Python, Go, Swift, C) is a thin FFI shim that re-exports the same compiled LANGUAGE entry point rather than re-implementing any parsing logic, so PowerShell language coverage has a single source of truth across every consumer.

Tech Stack grammar.js is the primary authoring surface, compiled by the tree-sitter CLI into portable C. Each ecosystem ships its own packaging: the Node binding uses node-addon-api, node-gyp-build, and prebuildify for prebuilt native binaries; the Rust crate depends on tree-sitter-language and a cc build-dependency to compile the C sources at cargo-build time; the Python wheel is built via a setuptools Extension with Py_LIMITED_API/abi3 tagging; the Go module wraps go-tree-sitter; and a Package.swift target plus CMakeLists.txt cover Swift and CMake-based consumers. ESLint (eslint-config-treesitter) lints grammar.js, and a Nix flake pins the dev environment.

Code Quality Tests live as tree-sitter’s native corpus format under test/corpus/ (15 files spanning variables, pipelines, classes, loops, operators, and a dedicated obfuscated-code file), each pairing a PowerShell snippet with its expected S-expression parse tree and runnable via tree-sitter test. The Rust crate and the Python/Node bindings each carry a minimal smoke test asserting the language loads. Known grammar ambiguities are explicitly documented in the conflicts array rather than silently resolved. CI is limited to linting grammar.js on push/PR and regenerating-then-publishing the parser on tagged releases for crates.io, npm, and PyPI — there is no CI job that runs the corpus test suite itself, so test coverage is currently verified only locally.

API Design Every binding exposes the same zero-configuration LANGUAGE constant used to register the grammar with a tree-sitter Parser, matching the standard shape of the wider tree-sitter ecosystem, so switching languages/ecosystems requires no relearning. The most distinctive design choice is the dedicated obfuscated-PowerShell test corpus, reflecting the maintainer’s (Airbus CERT, a security incident-response team) practical use case: producing structured parse trees for suspicious scripts that use format-string reassembly and backtick-escaped identifiers to evade plain-text detection, rather than only optimizing for editor tooling.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search