@onrails/twoslash
v0.1.3
Published
Extract #region snippet blocks from real, tested source modules into display + twoslash forms for type-checked documentation.
Maintainers
Readme
@onrails/twoslash
Extract #region snippet blocks from real, tested source modules into two forms
for documentation: a clean display snippet and a self-contained
twoslash module with hover types.
The idea: keep example code in actual .ts modules that your test/typecheck
gate compiles, mark the part you want to show with #region snippet, and
generate doc snippets from it — so rendered docs can never drift from compiling
reality.
Runs on Node (≥18) and Bun. No runtime dependencies.
Install
bun add -d @onrails/twoslash
# or: npm i -D @onrails/twoslashUsage
Mark a region in an example module. Anything imported from your fixtures file is hidden in the rendered output but kept for type-checking:
// examples/checkout.ts
import { cart, charge } from "./fixtures.js"; // hidden in docs, kept for type-checking
// #region snippet
import { ok } from "@scope/result";
const receipt = charge(cart);
export const result = ok(receipt);
// #endregionGenerate the snippets module:
import { extractSnippets } from "@onrails/twoslash";
await extractSnippets({
srcDir: "examples",
outFile: "docs/snippets.generated.ts",
// optional: rewrite relative source imports to published specifiers
rewriteImport: (line) =>
line.replace(/from "(?:\.\.\/)+([\w-]+)\/src\/index\.js"/, 'from "@scope/$1"'),
});Each entry in the generated module has two forms:
code— display form: region only,exportstripped, fixture imports dropped, imports optionally rewritten.twoslash— a self-contained module: shown imports on top, fixtures hidden inside// ---cut-start---/// ---cut-end---, body below — so twoslash type-checks everything but renders only the snippet, with live hover types.
// docs/snippets.generated.ts (generated)
export const snippets = {
checkout: { code: "…", twoslash: "…" },
} as const;
export type SnippetId = keyof typeof snippets;API
extractSnippets(options)
Scans srcDir, writes the generated module to outFile. Returns
{ count, outFile, skipped }.
| Option | Default | Purpose |
| --- | --- | --- |
| srcDir | — | directory scanned for *.ts / *.tsx snippet modules |
| outFile | — | path of the generated module to write |
| fixtureName | "fixtures" | basename of the shared fixtures module in srcDir |
| rewriteImport | identity | rewrites a single import line (e.g. relative → package specifier) |
| sourceLabel | srcDir | label in the generated-file header comment |
| generatedBy | "extract-snippets" | attribution in the // Generated by … header |
buildSnippetsModule(modules, fixturesSource, options?)
The pure core behind extractSnippets — no disk access, unit-testable. Takes
{ name, source }[] plus the fixtures source, returns { module, ids, skipped }.
Use it when you source modules from somewhere other than the filesystem.
How it pairs with twoslash
Feed the twoslash form to fumadocs-twoslash or any
twoslash renderer. The fixtures live below the
cut markers, so they type-check the snippet without appearing in the output.
