Getting Started
There is no npm package yet. The package name is yuku-tsrx and the version in
npm/yuku-tsrx/package.json is 0.0.0; nothing has been published, and neither
are the twelve @yuku-tsrx/binding-* packages that carry the native addon. So
getting started means building from source.
What you need#
- Zig 0.16.
build.zig.zonsets.minimum_zig_version = "0.16.0". - pnpm, for the JavaScript side.
- A Yuku checkout of the branch in yuku-toolchain/yuku#164 (opens in new tab),
in a sibling directory named
yuku-minimal-seam.
That last one is the part that is not optional. The compile-time extension
points yuku-tsrx builds against are the subject of that pull request, which is
open, and build.zig.zon declares the dependency by path:
.yuku = .{ .path = "../yuku-minimal-seam" },A path dependency resolves relative to this repository, so the two folders sit side by side:
dev/
yuku-minimal-seam/ the Yuku branch from PR #164
yuku-tsrx/ this repositoryWhy a path dependency rather than a pinned URL
The owner ruling recorded in goal.md is "Local link first, PR last": build
against the local path the whole way, keep the Yuku-side diff under pressure to
shrink, and open the upstream pull request only once the whole system is green.
A path dependency is what makes that loop fast, and it is why the checkout is a
prerequisite rather than something the build fetches for you. When PR #164
merges, the path dependency becomes a normal versioned one. See
Upstreaming to Yuku.
Which route are you on#
Three things people come here to do, and they need different commands. Pick yours; the other two answers are not on your path.
Consume it from Node
zig build writes a complete npm package layout into zig-out/npm/yuku-tsrx/. A consuming project points at that directory with "yuku-tsrx": "link:../yuku-tsrx/zig-out/npm/yuku-tsrx" and then does import { parseModule } from "yuku-tsrx". Use the built package from another project has the whole sequence.
Run it in a browser
pnpm run docs:wasm is zig build wasm -Doptimize=ReleaseSmall, and it writes zig-out/wasm/yuku-tsrx.wasm. node tools/wasm-smoke.mjs instantiates that module in Node and parses with it, so the build is proven before any page fetches it. docs/assets/yuku-wasm.js is the browser host for the same module, and the playground is that host running in your tab.
Hack on the dialect
The dialect is src/dialect/: parser_extension.zig declares the hooks Yuku calls, schema.zig the TSRX node records, and transfer.zig the buffer that crosses into JavaScript. Run zig build test for the Zig suite and pnpm test for the JavaScript one. The Yuku-side seam is yuku-toolchain/yuku#164 (opens in new tab); see Zig/Yuku Dialect Core and Upstreaming to Yuku.
The browser route is the shortest one to a working build, because it needs nothing from npm:
# the WebAssembly build the docs site and the playground load zig build wasm -Doptimize=ReleaseSmall # exit 0 # prove the module in Node before a page ever fetches it node tools/wasm-smoke.mjs wasm: zig-out/wasm/yuku-tsrx.wasm 1246 KiB imports: none hero: 92 nodes in 6.21 ms, 0 diagnostics semantic: 9 scopes, 4 symbols, 5 references generate: 338 bytes, 0 errors fixtures: 15 parsed ok # exit 0
Build#
zig build # builds the addon and writes the package to zig-out/npm/yuku-tsrx/
zig build test # the Zig test suite
pnpm test # the JavaScript test suite# build the addon and write the npm package layout zig build # exit 0 # zig build prints nothing on success, so look at what it wrote ls zig-out/npm/yuku-tsrx @yuku-tsrx binding.js decode-analyzer.js decode.js encode.js index.d.ts index.js package.json walk.js # exit 0 # the Zig test suite; --summary all only adds the tree at the end zig build test --summary all Build Summary: 7/7 steps succeeded; 2/2 tests passed test success +- run test 1 pass (1 total) 7ms MaxRSS:3M | +- compile test Debug native cached 51ms MaxRSS:31M | +- options cached | +- options cached +- run test 1 pass (1 total) 7ms MaxRSS:3M +- compile test Debug native cached 51ms MaxRSS:31M +- options (reused) +- options (reused) # exit 0
pnpm test is not in that recording. tools/capture-transcripts.mjs drops any
command that did not exit zero rather than editing its output, and on the day
above two checks in test/m1.test.ts, which assert things about the build
environment rather than about the parser, were failing. Run it yourself and read
what it says.
zig build is the one that produces something you can import. It writes a
complete npm package layout into zig-out/npm/yuku-tsrx/: index.js,
index.d.ts, package.json, the generated decoders (decode.js,
decode-analyzer.js, encode.js), walk.js, and a binding.js that loads the
native addon built for your machine.
Run the two test suites before you trust the result. zig build test covers the
dialect itself; pnpm test covers the JavaScript surface, including the fixtures
in test/parser/misc/tsrx/.
Use the built package from another project#
zig-out/npm/yuku-tsrx/ is a real package directory, so a consuming project
points at it with a link: dependency:
{
"dependencies": {
"yuku-tsrx": "link:../yuku-tsrx/zig-out/npm/yuku-tsrx"
}
}Then import it the way you would any ESM package:
import { parseModule, walk } from "yuku-tsrx";
const program = parseModule(source, "Cart.tsrx");
walk(program, {
JSXCodeBlock(node) {
// every TSRX code block in the file
},
});That is how Markless consumes it. Markless parses .tsrx today through
@tsrx/core, and parseModule(source, filename, options) is shaped as a
drop-in for @tsrx/core's parseModule, so the link is the only change at the
call site. On 2026-08-17, against the head of PR #164, Markless's node test
suite (229 files, 1832 tests) passed with yuku-tsrx swapped in for @tsrx/core
and no test edits, and its typescript-plugin completion matrix was 47/47.
Rebuild with zig build after any change to the dialect or to the sibling Yuku
checkout. A link: dependency reads the directory on disk, so the consuming
project picks the new build up without reinstalling.
Where to go next#
- TSRX Syntax Support for what the parser accepts and what it rejects.
- Parser for
parse,parseModule, options, and diagnostics. - API for every export with its signature.
- Limitations for what this library deliberately does not do.