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.
62 lines
3.1 KiB
Markdown
62 lines
3.1 KiB
Markdown
# Docs
|
|
|
|
Why the prose documentation is maintained the way it is. The actionable rules
|
|
are in [CONTRIBUTING.md](../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.
|
|
- The CI `build` job runs `npm run create:doc-tests` as an explicit step before
|
|
`npm run test:ci`, not a `pretest:ci` lifecycle hook: the hook hides the step
|
|
from the job log and makes `test:ci` behave differently under npm than when
|
|
run directly.
|