Every `ts`-tagged fence in README.md / CONTRIBUTING.md now becomes an executed `node:test` case in a gitignored generated file, so a documented example cannot drift from the API. The generator hoists and merges the leading imports, rewrites the library specifier to the `#test-tiny-pattern-ts` alias, and rejects a fence with no describing paragraph or one that re-imports a prelude module. CI regenerates via `pretest:ci`; `create:doc-tests` runs the generator, formats, then typechecks the output against a scoped tsconfig that relaxes `noUnusedLocals`. c8's default excludes already omit the generated `*.test.ts`, so `test:ci` is unchanged.
2.5 KiB
2.5 KiB
Docs
Why the prose documentation is maintained the way it is. The actionable rules are in CONTRIBUTING.md; this file records the rationale.
Validating Markdown code fences
Decision (2026-11)
Compile every ts / typescript fence in the prose docs into a real
node:test case under src/doc-test/__generated__/, typechecked by a scoped
tsc project and executed by node --test.
Why
- A documented example is a promise about the API. Left unchecked it drifts the moment a signature changes, and a reader copies broken code.
- The repo runs TypeScript 7, the native/Go compiler. It exposes no legacy JS
compiler API (
ts.createProgram,ts.transpileModule,ts.createSourceFileare allundefined;Object.keys(require("typescript"))is["version", "versionMajorMinor"]). So@typescript/vfs, the type-awareeslint-plugin-markdownanddocs-ts/@effect/docgencannot run here. node --checkparses as JS and rejects valid TS type annotations, so it is not a gate. The only faithful validator is thetscCLI, which means emitting real.tsfiles and letting the existingcheck:tsc/node --testpipeline judge them.
Rejected
- A packaged doc-test tool (see above) — no usable compiler API on TS 7.
- Embedding a typecheck in the generator — duplicates the gate, and would not exercise the repo's own resolution.
node --check— wrong language level.
Known issue
- Scanned sources are hard-coded to
README.mdandCONTRIBUTING.md. Adocs/+examples/list is the natural extension;development/must never be scanned (its fences are illustrative, not compilable). - The generator hoists and merges leading imports, rewrites
tiny-pattern-tsto the#test-tiny-pattern-tssource alias, and rejects an example that importsnode:assert/node:test(the prelude already binds both). Titles are the immediately preceding paragraph; a fence with no such paragraph is a fatal error, which keeps every example described. oxlint src/doc-testreports "No files found" because the generated*.test.tsare gitignored. That is cosmetic: the files are still typechecked and run.- The generated tests are
*.test.ts, which c8's default excludes already keep out of the--100gate. Do not add an--excludefor them: passing any--excludereplaces the defaults, so every hand-written test file and__tests__/helper re-enters coverage and the gate fails.