
# 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.zon` sets `.minimum_zig_version = "0.16.0"`.
- **pnpm**, for the JavaScript side.
- **A Yuku checkout of the branch in [yuku-toolchain/yuku#164](https://github.com/yuku-toolchain/yuku/pull/164)**,
  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:

```zig
.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 repository
```

**Why 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](/architecture/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.

On the site this table is a chooser: you pick your route and only that answer stays on screen.

| What do you want to do with yuku-tsrx? | What that route looks like |
| --- | --- |
| 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](#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](/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](https://github.com/yuku-toolchain/yuku/pull/164); see [Zig/Yuku Dialect Core](/architecture/yuku-dialect) and [Upstreaming to Yuku](/architecture/upstreaming-to-yuku). |

The browser route is the shortest one to a working build, because it needs
nothing from npm:

Captured on 2026-08-17 by tools/capture-transcripts.mjs on Darwin 25.5.0 arm64 (Apple M5 Pro), Node v24.15.0, Zig 0.16.0. Every line is what the command printed; long output is trimmed where marked.

```text
# 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

```sh
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
```

Captured on 2026-08-17 by tools/capture-transcripts.mjs on Darwin 25.5.0 arm64 (Apple M5 Pro), Node v24.15.0, Zig 0.16.0. Every line is what the command printed; long output is trimmed where marked.

```text
# 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:

```json
{
  "dependencies": {
    "yuku-tsrx": "link:../yuku-tsrx/zig-out/npm/yuku-tsrx"
  }
}
```

Then import it the way you would any ESM package:

```js
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](/guide/tsrx-syntax) for what the parser accepts and what
  it rejects.
- [Parser](/guide/parser) for `parse`, `parseModule`, options, and diagnostics.
- [API](/reference/api) for every export with its signature.
- [Limitations](/reference/limitations) for what this library deliberately does
  not do.
