Plugin Development
For plugin authors β people writing new ttsc plugins. If you just want to use existing plugins like @ttsc/lint or typia, you donβt need this section β wire the plugin into compilerOptions.plugins per its own README and skip ahead.
Reading order for first-time authors: (1) Concepts overview β the two-halves model, vocabulary, stages, auto-discovery (5 min). (2) Walkthroughs β
@ttsc/bannerβ line-by-line walkthrough of the simplest shipped plugin. The friendliest first read for Go newcomers. (3) Authoring β Getting started β the Hello plugin: bootstrap, printer round-trip, no mutation. Write your first plugin from scratch. (4) Reference β Pitfalls β skim before you build so the common first-hour failures are recognizable. (5) Authoring β End-to-end transform β the same shape with a real AST mutation. Then read@ttsc/strip, then@ttsc/pathsfor production-quality versions of the same shape. (6) Authoring β Testing and Publishing β after your first plugin runs. Skip Reference β Architecture on the first pass; come back when you need to debug a build. The@ttsc/lintdeep dive is the last stop after you finish the paths walkthrough, when you are ready to ship a multi-file engine.
This chapter is organized in four tiers:
Concepts
Background you need before authoring.
β Concepts overview β two-halves model, stage/subcommand matrix, auto-discovery rule, AST-vs-Checker decision tree, glossary.
- Plugin protocol β the npm package contract, binary subcommands,
--plugins-jsonshape,composes/contributors, exit codes. - AST & Checker β how TypeScript-Go exposes the AST and Checker to Go plugins.
driver.LoadProgram, printer round-trip, the leaf-text synthesize-flag invariant.
Walkthroughs
The main learning path. Friendly, line-by-line source-code tours of every plugin that ships with ttsc, ordered by difficulty. Each page annotates the Go language as it appears so a Go newcomer can read along and pick the pattern up by following the real production code. Start here β the Authoring chapter writes the same shapes from scratch and assumes the vocabulary these pages establish.
@ttsc/bannerβ smallest transform plugin. Introducespackage main, themain β run β switchdispatcher, exit codes, the JS descriptor, and theshim/boundary.@ttsc/stripβ your first real AST mutation. Statement-list filtering, recursion into block-bodied statements, the empty-statement substitution trick, dotted-name matching.@ttsc/pathsβ tsconfig parsing, Program-backed alias resolution, the visitor that finds every module-specifier shape, and the synthesize-flag invariant for leaf-text mutations.@ttsc/lintβ advanced deep dive. Multi-file engine, rule registry, severity ladder, fix/format cascade, ESLint runtime delegation, build-time contributor merging.
Authoring
The build-and-publish path. Pair with Walkthroughs: read banner before Getting started; read strip / paths before End-to-end.
- Getting started β the Hello plugin: bootstrap, printer round-trip, no AST mutation.
- End-to-end transform β the same shape with a real AST mutation (
debuggerremoval). - Editor setup β
go.work,gopls, pnpm notes. Set up before you import a shim. - Recipes β copyable patterns (auto-discovery, lint diagnostics, leaf-text mutation, toolchain re-spawn).
- Testing β Go unit + e2e fixtures, AGENTS.md Β§2.2 shape,
tests/projects/exemplar. - Publishing β npm package shape,
peerDependencies, Pre-Publish Check CI recipe.
Reference
Deeper material β read as needed.
- Architecture β source-plugin build cache, cache-key inputs, build environment, Go toolchain resolution.
- Driver API β the Go faΓ§ade plugin authors should call (
LoadProgram,Program,NewLintDiagnostic,EmitAllRaw,RewriteSet,ApplySourcePreamble). - Pitfalls β common first-hour failures with exact host error strings.
How a plugin works, in one paragraph
A ttsc plugin is an npm package with two halves: a JS descriptor that lives in the consumerβs node_modules and tells ttsc what the plugin does, and a Go sidecar that holds the actual logic. The Go sidecar reads the TypeScript-Go AST, queries the Checker, then either reports diagnostics or rewrites emit. It compiles once into a binary the first time it is used, and the binary is cached by ttsc version, tsgo version, platform, plugin source hash, overlay hash, contributor hashes, and the Go build environment. Plugins run everywhere ttsc runs β CLI, ttsx, ttscserver, every @ttsc/unplugin bundler adapter. One contract, one config (tsconfig.jsonβs compilerOptions.plugins); a package.json#ttsc.plugin field on a directly-listed dependency adds auto-discovery as a package-side fallback. See Concepts for the canonical vocabulary.
Test Fixtures
When you want a Program/Checker bootstrap your plugin can copy verbatim, look at these fixtures:
tests/projects/go-source-plugin-checkerβ minimal Program/Checker setup.tests/projects/go-source-plugin-propertiesβ AST traversal fixture.
Status
v1 protocol, still moving. Donβt publish ttsc as a peer dependency yet β treat it as a build-time-only dependency. The driver surface (packages/ttsc/driver/) is the closest thing to a stable plugin SDK; symbols documented in Reference β Driver API survive a normal release cycle.
Requirements
- Node.js 18+ β install from nodejs.org/downloadβ if you donβt have it.
- Go 1.22+ for direct
go test/go vetagainst your plugin β install from go.dev/dlβ.ttscβs bundled toolchain (shipped in the platform package) is what actually builds plugins on consumer machines; a system Go is only needed for local-dev workflows. The shipped plugins (and thego.modexamples in this chapter) targetgo 1.26because that is the bundled SDK; the bundled toolchain satisfies thegodirective regardless of your system Go version. - A consumer test fixture with
ttscand@typescript/native-previewinstalled.