Drop the `pretest:ci` lifecycle hook and call `create:doc-tests` from the `build` job before `test:ci`. The hook hid the step from the job log and made `test:ci` behave differently under npm than when run directly.
3.1 KiB
3.1 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. - 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:coveragetherefore runs c8 over the tracked tests only (git ls-files 'src/*.test.ts'— the generated files are untracked), andtest:docruns the examples in a separate process without c8.test:cichains the two, so correctness and coverage stay independent. - The CI
buildjob runsnpm run create:doc-testsas an explicit step beforenpm run test:ci, not apretest:cilifecycle hook: the hook hides the step from the job log and makestest:cibehave differently under npm than when run directly.