TypeScript / npm
Decl is a declarative language for describing, generating, and validating structured data — a JSON superset with a strong static type system, constraints with first-class diagnostics, references, physical quantities, generics, and modules. Pure, deterministic, terminating.
This package is the reference implementation of the whole language:
the decl command-line tool, the canonical formatter, the decl-lsp
language server, and a library — in TypeScript, on Node.js ≥ 22, with
no runtime dependencies (the tree-sitter grammar ships as wasm). Its
platform-neutral core also runs in a browser.
npm install -g decl-langCommand line
Section titled “Command line”decl check schema.decl # static checks, module-aware (exit 1 on errors)decl evaluate site.decl # evaluate every exported output -> {"name": value, ...}decl evaluate site.decl --output site # one output -> its canonical JSON on stdoutdecl evaluate site.decl --json # {"ok", "value", "diagnostics"} reportdecl evaluate cfg.decl --input deployed=doc.json --output deployed=out.json # bind a document, write its completed valuedecl evaluate cfg.decl --input deployed=doc.yaml --format yaml --pretty # a document in YAML in, the outputs as YAML outdecl evaluate site.decl --output gateway # a root in the form its @render declares: YAML, a template's text, one file per elementdecl evaluate site.decl --output units=out --template units=unit.j2 # …or with the template and the destination given heredecl validate cfg.decl --input deployed=doc.json # bind a document to an input root (diagnostics only)decl validate tests/validation # judge a fixture corpusdecl fmt src/*.decl # canonical formatting in place (--check: exit 1 if not canonical)decl repl site.decl # an interactive session: expressions, bindings, edits, undodecl-lsp # language server over stdioDiagnostics go to stderr as file: severity [code] id at path: message,
or into the JSON report with --json. The exit code is 1 when any error
was reported. An output declares the form it is emitted in with
@render({ format, indent, template, file, each }) — canonical or
indented JSON, YAML, or the text of a template in a small Jinja-like
dialect with Decl expressions inside, one file per element — and
--format, --indent, --template, --output override it
(docs/tooling/05_render.md). The command line, the REPL, and the
server are documented in the repository (docs/tooling/), and the VS
Code and Zed extensions are clients of decl-lsp.
Library
Section titled “Library”import { evaluate, render, check, validate, formatSource, toYaml, DeclError } from 'decl-lang';
const docs = await evaluate('site.decl'); // { site: {...} } — the exported outputs, by nameconst { site } = await evaluate('site.decl', { outputs: ['site'] });const done = await evaluate('cfg.decl', { inputs: { deployed: 'doc.yaml' }, outputs: ['deployed'] }); // YAML by its extensionconst texts = await render('site.decl'); // { site: 'name: edge\n…', units: { 'units/a.conf': '…' } } — each root in its declared formconst yaml = await render('site.decl', { outputs: ['site'], format: 'yaml', indent: 4 }); // the options overrideconst conf = await render('site.decl', { outputs: ['site'], templates: { site: 'nginx.conf.j2' } }); // or { text }const problems = await check('schema.decl'); // [] when cleanconst report = await validate('cfg.decl', { inputs: { deployed: { host: 'h' } } }); // a document may be a valueconst text = await formatSource('const x=1+2\n'); // 'const x = 1 + 2\n'const y = toYaml({ a: [1, 2] }); // 'a:\n - 1\n - 2' — the layouts, as pure functionsThe functions are the decl command line in its own vocabulary:
inputs binds documents by input name (a JSON or YAML file path, or the
value itself), outputs names the roots to return — outputs, or inputs
bound here or demanded through their fallback — and defaults to the
entry module’s exported outputs; render returns each root’s text in
its declared form (a fan-out root as its files by path), toJson and
toYaml lay a value out; a failure throws DeclError, whose
diagnostics carry the report. The PyPI package (decl.evaluate, …)
and the Rust crate (decl_lang::evaluate, …) offer the same functions
with the same semantics; the modules the functions are built from are
exported as well.
The platform-neutral core is a second entry, decl-lang/core, for
browsers and other non-Node hosts: everything that runs anywhere
JavaScript runs, over an in-memory host, with the grammar wasm’s
location passed in instead of found on disk.
import { initParser, evaluateSource, format } from 'decl-lang/core';await initParser({ grammar: '/assets/tree-sitter-decl.wasm', runtime: '/assets/tree-sitter.wasm' });const report = evaluateSource('output x: int = 1\n'); // { ok, outputs: [{ name, json }], diagnostics, ... }Library layout
Section titled “Library layout”The package is the same modules as the other two implementations, one
language rule in the same-named file everywhere (AGENTS.md in the
repository), and each is exported:
| Module | Holds |
|---|---|
api |
the high-level API above: evaluate, render, check, validate, evaluateSource, formatSource, toJson, toYaml, DeclError |
ast |
the syntax tree (specification chapter 11): declarations, types, members, expressions, source ranges |
parse |
the tree-sitter binding: initParser, parseSource, source text to ast |
semantics |
values, the environment (Env), resolved types, diagnostics (Diag), canonical paths, the JSON reader and writers |
yaml |
documents in YAML: the YAML 1.2 core-schema reader into the JSON model, the block-style writer, the JSON layouts |
render |
the renderer: @render’s form, the template dialect, the fan-out — one root to its text or files |
subsume |
the subsumption judgment ⊑ (§3.17) and structural emptiness (§3.19) |
infer |
expression inference and the static assignability of §4 |
checker |
the static checks of a module (checkModule) |
engine |
binding, lazy evaluation, validation, serialization (Engine) |
pipeline |
one module end to end (runPipeline, evaluateSource) |
module |
modules and the universe (loadModules, runUniverse) |
package |
manifests, the resolver, the lock file (§8.6–8.7) |
fmt |
the canonical formatter (format) |
conformance |
the fixture corpus judge |
session |
the evaluation session behind the REPL and the server (Session) |
repl |
decl repl |
lsp-core, lsp, lsp-web |
the language server’s every answer; decl-lsp over stdio; the server in a web worker |
cli |
decl |
host, node |
the file system behind the core: the disk under Node, memory elsewhere; the Node entry that locates the grammar |
core, index |
the two entries: decl-lang/core (platform-neutral) and decl-lang (Node) |
The package covers the whole language: parsing, the static checks of
chapters 3–4 (type resolution with generics and dimension algebra,
inference, assignability, the absence discipline, match
exhaustiveness), binding with lazy slots and cycle detection,
$referrers, assertions with diagnostic templates, canonical
serialization, modules and packages (decl.toml, decl.lock), the
canonical formatter, the renderer (documents in YAML, @render,
templates, fan-out), the REPL, and the language server. It is the
reference the other two implementations are held to: the repository’s
parity harness (tests/parity/differential.py, run by make verify)
diffs the Rust and Python runtimes against it, byte for byte, over
every example and fixture that produces output.
Building from source
Section titled “Building from source”npm install # once, at the repository root (npm workspaces)npm test -w decl-lang # the corpora under tests/, one driver each, and the internal checksnpm run build -w decl-lang # dist/: the command line, the server, both entries, the grammar wasmnode decl-ts/src/cli.ts evaluate docs/examples/02_config.decl --output prod # without buildingThe grammar comes from ../tree-sitter-decl as the committed
tree-sitter-decl.wasm, consumed through web-tree-sitter — no native
build step.
License
Section titled “License”MIT — see LICENSE.
© 2026 Luuvish. Decl is open source under the MIT License.
Type: Literata and IBM Plex, under the SIL Open Font License. Built with Astro Starlight.