Files
tiny-pattern-ts/development/docs.md
T
tmu 4dc58395c0 ♻️ Run doc tests outside the coverage gate
An example that exercises a line no hand-written test reaches would let
the `--100` gate pass on documentation alone. Node has no file-level
exclusion, and c8's `--exclude` only filters the report, so run the two
in separate processes: `test:coverage` runs c8 over the tracked tests
only (`git ls-files`, which skips the untracked generated files), and
`test:doc` runs the generated examples without c8. `test:ci` chains
them.
2026-09-24 12:52:42 +00:00

2.9 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.createSourceFile are all undefined; Object.keys(require("typescript")) is ["version", "versionMajorMinor"]). So @typescript/vfs, the type-aware eslint-plugin-markdown and docs-ts / @effect/docgen cannot run here.
  • node --check parses as JS and rejects valid TS type annotations, so it is not a gate. The only faithful validator is the tsc CLI, which means emitting real .ts files and letting the existing check:tsc / node --test pipeline 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.md and CONTRIBUTING.md. A docs/ + 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-ts to the #test-tiny-pattern-ts source alias, and rejects an example that imports node: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-test reports "No files found" because the generated *.test.ts are 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 --100 gate. Do not add an --exclude for them: passing any --exclude replaces the defaults, so every hand-written test file and __tests__/ helper re-enters coverage and the gate fails.
  • Generated examples must not run under c8: an example could cover a line no hand-written test reaches, so the coverage gate would pass on documentation alone. test:coverage therefore runs c8 over the tracked tests only (git ls-files 'src/*.test.ts' — the generated files are untracked), and test:doc runs the examples in a separate process without c8. test:ci chains the two, so correctness and coverage stay independent.