npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sshadows/tree-sitter-al

v2.5.2

Published

AL for Business Central

Readme

tree-sitter-al

A tree-sitter parser for the AL programming language used in Microsoft Dynamics 365 Business Central.

PyPI crates.io npm

Parser Status

Validated against 15,358 production AL files from the Business Central codebase:

| Metric | Value | |--------|-------| | Success rate | 100% (15,358 / 15,358 files) | | Tests | 1,437 | | parser.c size | ~25 MB | | grammar.js | ~3,750 lines | | Named keywords | 82 (queryable via highlights/tags) | | Scanner tokens | 8 (stateful, depth-tracking) | | Query files | 5 (highlights, locals, tags, indents, folds) |

Installation

Rust

cargo add tree-sitter-al
use tree_sitter::Parser;

let mut parser = Parser::new();
let language = tree_sitter_al::LANGUAGE;
parser.set_language(&language.into()).expect("Error loading AL grammar");
let tree = parser.parse("codeunit 50100 MyCodeunit { }", None).unwrap();
println!("{}", tree.root_node().to_sexp());

Query constants are also available:

use tree_sitter_al::{HIGHLIGHTS_QUERY, TAGS_QUERY, LOCALS_QUERY, FOLDS_QUERY, INDENTS_QUERY};

Python (tree-sitter 0.24+)

pip install tree-sitter-al
import tree_sitter
import tree_sitter_al

lang = tree_sitter.Language(tree_sitter_al.language())
parser = tree_sitter.Parser(lang)
tree = parser.parse(b'codeunit 50100 MyCodeunit { }')
print(tree.root_node.sexp())

Node.js

npm install tree-sitter-al

Pre-built binaries

Download from GitHub Releases:

| File | Platform | Use case | |------|----------|----------| | tree-sitter-al.wasm | All | web-tree-sitter | | tree-sitter-al.so | Linux x86_64 | ast-grep, native bindings | | tree-sitter-al.dll | Windows x86_64 | ast-grep, native bindings | | tree-sitter-al.dylib | macOS ARM64 | ast-grep, native bindings |

V2 Architecture

The grammar was rewritten from scratch in March 2026, achieving a major reduction in parser size while improving correctness.

Before / After

| Metric | V1 | V2 (current) | |--------|-----|-----| | parser.c | 106 MB (can't push to GitHub) | ~25 MB | | Errors | 14 | 0 | | Success rate | 99.91% | 100% | | Symbols | 2,249 | ~814 | | States | 29,126 | ~10,800 | | grammar.js | 8,500 lines | ~3,750 lines | | Tests | 1,225 | 1,437 | | Keywords | invisible in queries | 82 named nodes | | Query files | 3 (partial) | 5 (comprehensive) |

Key design decisions

  • Stateful external scanner — 8 scanner tokens handle property disambiguation, depth tracking (#if/#endif nesting), named begin/end keywords at depth 0, and split-construct detection via lookahead.
  • Parse structure, don't validate — Accept any Name = Value ; as a property. Semantic validation belongs in linters/LSP servers, not the parser.
  • Generic preprocessor — One preproc_conditional rule + ~15 dedicated rules for genuinely complex split constructs (begin/end, var/begin, brace-close across #if/#else branches).
  • 82 named keyword nodes — All keywords including begin/end are named nodes, enabling proper syntax highlighting and code navigation queries.

See docs/v2-blog-post-notes.md for the full rewrite narrative.

Development

Prerequisites

  • Node.js (v16+)
  • tree-sitter CLI: npm install -g tree-sitter-cli

Building

tree-sitter generate    # Generate parser from grammar.js
tree-sitter test        # Run test suite

Validation

./validate-grammar.sh        # Quick: generation, tests, orphan/duplicate detection
./validate-grammar.sh --full # Full: includes production AL file parsing

For grammar refactors, the parse-tree diff harness proves a change is zero-behavior-change by re-parsing every production file and asserting byte-identical trees:

./tools/tree-harness.sh snapshot ./BC.History .snapshots/bc   # baseline
./tools/tree-harness.sh verify   ./BC.History .snapshots/bc   # verify after a change

Parsing AL files

tree-sitter parse path/to/file.al
tree-sitter parse path/to/file.al -d    # Debug output
tree-sitter parse path/to/file.al -q    # Quiet (errors only)

Key files

| File | Purpose | |------|---------| | grammar.js | Main grammar definition | | src/scanner.c | External scanner (8 tokens: property, depth tracking, named begin/end, split detection) | | test/corpus/ | Test suite (1,437 tests) | | queries/ | Syntax highlighting, code navigation, folding, indentation |

Contributing

See CLAUDE.md for detailed development guidelines including architecture, debugging, and conventions.


Author: Torben Leth ([email protected]) License: MIT (see LICENSE)