74e453809417e93fd5726bb9b780d577b3f7ca21
Adds a 'CHECK TIERS' subsection under the existing HOOKS section in project-specs.md that explicitly documents: - Where each check runs (pre-commit, npm run check, CI build, CI publish) - A summary table mapping scripts to execution contexts - The rationale for each split (speed, scope, side effects) - Why check:knip is not in pre-commit (~4s, whole project) - Why check:outdated is not in pre-commit (network dep, advisory) - Why publish:* is not in check (validates dist/, needs build) - Cross-reference from the CI/CD section back to the tiers table The split is a deliberate design choice: pre-commit is the fast safety net for what you just changed, npm run check is the full local audit, CI is authoritative. Documenting it makes the rationale explicit and stops anyone from re-adding the slower checks to the hook.
tiny-pattern-ts
Pattern matching for TypeScript/ESM environments (F#-style, not regex).
Development
- Build:
npm run build - Test:
npm run test,npm run test:ci - Checks:
npm run check,npm run fix - Format/Fix:
npm run fix:oxfmt,npm run fix:oxlint
Tooling
- TypeScript 7 — type checker and build (
tsc). - node --test +
--experimental-strip-types— test runner (Node 22.6+, flag dropped on Node 24). - c8 — code coverage for
test:ci. - oxlint — Rust-based linter. Type-aware rules are enabled via
options.typeAware: truein.oxlintrc.json(powered byoxlint-tsgolint). - oxlint-tsgolint — type-aware linting via typescript-go (declarative via
.oxlintrc.json, no CLI flag). Catches unsafe type assertions, unnecessary type parameters, and other type-system issues that regular oxlint can't see. Source-leveloxlint-disabledirectives are used to silence known false positives (e.g.,expectTypeOf()in test files). - oxfmt — Rust-based formatter (Prettier-compatible). Formats JS/TS, JSON/JSONC, YAML, Markdown, MDX, and more; built-in
package.jsonkey sorting replacessort-package-json. - cspell — spell checking.
- knip — finds unused dependencies, exports, and files. Scoped via
--include dependencies,exports,filesto skip the noisytypescategory (which produces false positives for libraries whose exported types are part of the public API). - publint — validates
package.jsonfor ESM publishing correctness. Runs on publish only (in CI), not as part ofnpm run check. - @arethetypeswrong/cli (
attw) — validates.d.tsdeclarations against multiple module-resolution scenarios. Runs on publish only with--profile esm-only(the package is intentionally ESM-only). - lefthook — git pre-commit hooks.
Requirements
- Node.js >= 26 (engines field; pinned via
.node-version).
VSCode integration
- Recommended extensions: see
.vscode/extensions.json(oxc, cspell). - TypeScript 7 is used via the
typescriptteam.native-previewextension. - oxc extension provides oxlint squiggles and oxfmt format-on-save.
Workflows
- Version updates via
npm version. - Publishing via GitHub Actions on tagged commits (see
.github/workflows/ci.yml); thepublishjob runspublish:publintandpublish:attwbeforenpm publish.
Script prefix convention
Script names follow a prefix convention that signals when they run:
check:*— read-only verification. Aggregated bynpm run check. Used in pre-commit hooks and CI's build job.fix:*— mutating counterpart ofcheck:*. Run individually (nonpm run fixaggregator by design — fixes should be intentional, not batched).test:*— test scripts.npm run testruns the full suite;test:unit/test:ciare scope-specific variants.publish:*— runs only at publish time, in the CIpublishjob (immediately beforenpm publish). There is no localnpm run publishscript — publishing is CI-only by policy.
Contribution guidelines
- Commit signing (GPG).
- Set up commit message template:
npm run use:git-commit-message. - See
commit-message-template. - Type-only tests use
expect-type'sexpectTypeOf(...)insidenode --testcases.