Repository navigation
feat(attest): choose the type checker, with tsrs support - #1706
Conversation
tsrs, the Rust port of TypeScript 7, serves the same native API as tsgo, so the `tsrs` option (`--tsrs` or `ATTEST_tsrs=true`) only changes which package attest loads its API client, AST and compiler binary from. It's an optional peer dependency resolved relative to attest, like typescript. The TS 7.1 version guard is skipped for tsrs, whose version names the upstream commit it ports. Instantiation counts still come from the compiler's --extendedDiagnostics, which tsrs prints in the same format. Measured against tsgo 7.1.0-dev.20261006.1 with tsrs 0.18.0-ts7.1.0-dev.20260929 (upstream b85298b6a81f), Linux x64: - ark/attest: 63/63 passing on both, 28s vs 62s wall - ark/type: 890/890 passing on both, 61s vs 95s wall - whole repo --extendedDiagnostics: 5,142,738 vs 5,172,042 instantiations (0.6% lower), 8.3s vs 30.8s check time Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Replaces the tsrs boolean with one setting naming the checker, so future backends don't each add a flag. Left unset, attest uses tsrs when it resolves alongside TypeScript 7, else tsgo for TypeScript 7, else tsjs. An explicit checker that doesn't match the installed TypeScript major, or an unknown name, throws rather than silently falling back. Since tsrs is now an attest devDependency, this repo's own suites default to tsrs; ATTEST_checker='"tsgo"' runs them on tsgo (63/63 on both). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
tsrs ships its binary in per-platform optional dependencies, so the package installs without one on platforms it doesn't support, like the Windows CI runner. Auto-detection now requires a platform package (or TSRS_BINARY) to resolve. Since this repo's typed tests now default to tsrs, the attest@tsgo CI task reruns them on tsgo, which most consumers check with. The repo typecheck stays on tsc. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Important
The new checker option is silently ignored when set through setup() — only --checker/ATTEST_checker take effect. Details inline.
Reviewed changes
Adds a checker: "tsjs" | "tsgo" | "tsrs" attest option selecting which TypeScript-compatible API and compiler binary attest analyzes with, defaulting to tsrs where its binary is installed, then tsgo on TypeScript 7, then tsjs.
checkerconfig (ark/attest/config.ts) — newCheckertype andchecker: undefineddefault.- Checker selection (
ark/attest/ts7/server.ts) —getChecker/hasTsrsBinarychoose thecompilerpackage thatast,API,createFileSystemLayerandtscPathload from, throwing on an unknown or version-mismatched checker. - Packaging (
ark/attest/package.json,pnpm-lock.yaml) —tsrsdevDependency plus an optional peer, with per-platform optional binaries. - CI (
ark/repo/testTsVersions.ts) — typed tests default to tsrs, with a newattest@tsgotask rerunning them on tsgo.
ℹ️ New checker option isn't on the options page
ark/docs/content/docs/attest/options.mdx states it lists "the current defaults for all available options" and mirrors getDefaultAttestConfig, but the new checker: undefined default isn't included, so the --checker/ATTEST_checker surface ships undocumented.
Technical details
# checker missing from options.mdx
## Affected sites
- ark/docs/content/docs/attest/options.mdx:25-41 — defaults snippet omits `checker`
- ark/attest/config.ts:48-65 — `getDefaultAttestConfig` now includes `checker: undefined`
## Required outcome
- The options page reflects the new option. A short subsection like the existing `skipTypes`/`typeToStringFormat` ones would fit, since the default-selection behavior (tsrs → tsgo → tsjs) is not obvious from the name alone.deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
| return checker | ||
| } | ||
|
|
||
| const checker = getChecker() |
There was a problem hiding this comment.
checker is resolved eagerly at module load, so setup({ checker: "tsgo" }) is silently ignored: @ark/attest's entry graph (index.ts → fixtures.ts → ts7/analyze.ts → here) evaluates before setup() writes ATTEST_CONFIG, and the derived ast/API/tscPath constants can't change afterward. Only --checker/ATTEST_checker work.
Technical details
# setup({ checker }) has no effect
## Affected sites
- ark/attest/ts7/server.ts:59 — `const checker = getChecker()` runs during module evaluation
- ark/attest/ts7/server.ts:62-80 — `compiler`, `ast`, `API`, `createFileSystemLayer`, `tscPath` are all module-level consts derived from `checker`
- ark/attest/fixtures.ts:9-12 — `setup()` only writes `process.env.ATTEST_CONFIG` when it is called
- ark/attest/config.ts:111-117 — `addEnvConfig` is what reads that env var
- ark/repo/mocha.globalSetup.ts:1-10 — the repo's own global setup imports `@ark/attest` (line 1) before calling `setup()` (line 6), so it can't set `checker` either
## Required outcome
- `setup({ checker })` must select the checker, or `checker` must not be offered on the setup-facing `AttestConfig` (with CLI/env-only usage made explicit). As written, the type advertises the option but the runtime ignores it, and a user following the docs gets the default checker with no warning.
## Suggested approach (optional)
- Resolve the checker lazily on first `TsgoServer.instance` access (turn `ast`/`API`/`createFileSystemLayer`/`tscPath` into getters), since `ATTEST_CONFIG` cannot exist before the module graph is evaluated.| // recorded with the workspace's TS 7, whose type strings and counts differ | ||
| // type assertions default to tsrs where it's installed, but tsgo is what | ||
| // most consumers check with | ||
| "attest@tsgo": `ATTEST_checker='"tsgo"' pnpm testTypedLoose && cd ark/attest && ATTEST_checker='"tsgo"' pnpm test`, |
There was a problem hiding this comment.
Nit: the two-line comment just above (type snapshots ... differ) originally explained the attest@6.0.3 task below it; inserting the new comment between them now leaves it reading as if it describes attest@tsgo. Move the new comment/task below it so each comment stays attached to the task it explains.
The checker was read while @ark/attest's entry graph evaluated, before
setup() writes ATTEST_CONFIG, so setup({ checker }) was silently ignored.
The compiler is now loaded on first use: ast is populated in place, and
noTruncation and tscPath become getNoTruncation() and getTscPath().
writeAssertionData dispatches on getChecker(), so a tsjs/TS 7 mismatch
throws there too.
Also documents checker on the options page and keeps each
testTsVersions comment beside the task it explains.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
# Conflicts: # ark/attest/config.ts # ark/attest/ts7/server.ts
Its --tsconfig null dropped the repo's ark-ts customConditions, so workspace packages resolved to their built out/ declarations. CI builds first, but locally a stale build made the loose run fail on changes like #1691's that hadn't been rebuilt. It now resolves source like every other typed run. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds tsrs support and the checker option (#1706). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
main contributes attest 0.58.0: a `checker` option ("tsjs", "tsgo" or
"tsrs") and support for tsrs, a Rust port of TypeScript 7 serving tsgo's
API, which attest picks by default when its binary is installed alongside
TypeScript 7. server.ts now loads the compiler lazily, after setup() has
written attest's config, so `ast`, the no-truncation flag and the tsc path
are read on first use (getNoTruncation, getTscPath). testTsVersions gains
an attest@tsgo task, since the repo itself now checks with tsrs on the
platforms it ships for.
Conflicts:
- ark/attest/CHANGELOG.md: featherduster's Unreleased section stays on
top, with main's 0.58.0 section below it.
- ark/attest/ts7/instantiations.ts: featherduster's countVariants, which
returns the parsed counts directly, now passes getTscPath() in place of
the removed tscPath.
- ark/docs/content/docs/attest/options.mdx: featherduster's options table
replaces the getDefaultAttestConfig listing main added `checker` to, so
`checker` gets a table row pointing at main's new section instead.
- package.json: featherduster's testTsCompat and bench (with
benchJsonSchema), and main's testTypedLoose, which resolves workspace
packages through the ark-ts condition.
- ark/docs/app/layout.tsx: featherduster's. main removed the ArkRegex
release banner from its fumadocs layout, and featherduster's own layout
never rendered one.
- pnpm-lock.yaml: featherduster's, reinstalled against the merged
manifests, so the only change is tsrs and its platform binaries.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Adds a
checker: "tsjs" | "tsgo" | "tsrs"setting (--checker tsrs,ATTEST_checker='"tsrs"'). tsrs, the Rust port of TypeScript 7, serves the same native API as tsgo, so it only changes which package attest loads its API client, AST and compiler binary from.Unset, attest uses tsrs when its binary resolves alongside TypeScript 7, else tsgo on TypeScript 7, else tsjs. An unknown checker, or one that doesn't match the installed TypeScript major, throws. tsrs is an optional peer dependency.
CI: this repo's typed tests now default to tsrs. A new
attest@tsgotask intestTsVersionsreruns them on tsgo, and the repo typecheck stays ontsc.Measured locally (Linux x64, tsrs 0.18.0 vs tsgo 7.1.0-dev.20261006.1):
ark/attest(63 passing)ark/type(890 passing)Locally,
prCheckspassed everything exceptbuildDocs: docs pages exceeded Next.js's 60s render timeout on WSL, and docs pages don't import attest.🤖 Generated with Claude Code