Files
tiny-pattern-ts/CONTRIBUTING.md
T
tmu 538272c222 📝 Restore unique maintainer content as CONTRIBUTING.md
After dropping project-specs.md last commit, three categories of
content were lost that have no other home in the repo:

1. The script prefix convention with its 'pick the right prefix,
   don't invent one' rule
2. The feedback-tier system (table + 'why these splits?')
3. The publishing workflow (tagged-release flow)

These are maintainer/contributor-facing material, not user-facing.
The standard OSS location for this kind of doc is CONTRIBUTING.md,
which keeps it separate from README.md (user docs) so the two
don't drift. README.md gains a pointer at the bottom.

The content is condensed: no config dumps, no restatements of
package.json, no historical commit-message examples. Only the
rationale that isn't already in the actual config files.
2026-09-05 00:35:00 +02:00

4.6 KiB
Raw Blame History

Contributing

This document is for maintainers and contributors working on the project itself. End-user documentation is in README.md.

Script prefix convention

Script names in package.json use a prefix that signals when the script is intended to run. A <prefix>:<name> script is implicitly aggregated by a <prefix> script (if one exists) and run by the corresponding lefthook hook or CI step. Picking the right prefix documents the script's intended lifecycle:

  • check:* — read-only verification. Aggregated by npm run check. Used in pre-commit hooks (on staged files) and CI's build job (on the whole project). Read-only; never modifies files.
  • fix:* — mutating counterpart of a check:* script. Aggregated by npm run fix. Use after npm run check to auto-resolve issues; the diff is the review surface.
  • test:* — test scripts. npm run test is the canonical entry point (check:tsc + unit tests); test:unit skips the typecheck for fast local iteration; test:ci adds c8 coverage and is the CI variant.
  • publish:* — runs only at publish time, in the CI publish job (immediately before npm publish). There is no local npm run publish script — publishing is CI-only by policy. The publish: prefix still documents intent: this script validates the publishable artifact (e.g., dist/) rather than the source.

A new script should pick the prefix that matches its lifecycle, not invent a new one. If no existing prefix fits, that's a signal the script doesn't belong in the standard pipeline.

Feedback tiers

The tools are organized into a feedback ladder. Each tier catches different things at different costs; the rule of thumb is "earlier tiers fire more often, faster tiers catch less, slower tiers are more thorough":

Tier When What it runs Time
Pre-commit (auto) on stage tsc + oxlint + oxfmt + cspell (staged files only) ~1.3s
Pre-push (auto) on push npm test (full tsc + unit tests) ~3.5s
npm run check manual Full project audit: all check:* scripts + knip + outdated ~10s
npm run fix manual Auto-resolve fixable issues (lint, format) ~3s
CI build (auto) on push/PR npm run check + npm run test:ci ~30s+
CI publish (auto) on tag publish:publint + publish:attw, then npm publish ~10s

Why these splits?

  • check:tsc, check:oxlint, check:oxfmt, check:cspell are in pre-commit because they are fast (~0.2–0.5s each), fully offline, and naturally scope to staged files via the LEFTHOOK_FILES env var convention. They give instant feedback on what you typed.
  • test (and the tsc it includes) is in pre-push because it runs the whole test suite across the whole project. The pre-commit LEFTHOOK_FILES convention doesn't apply to the test runner, so pre-commit isn't the right home. Pre-push runs after all commits are made but before the push leaves the machine, catching regressions that span multiple commits.
  • check:knip and check:outdated are NOT in pre-commit — knip scans the whole project (~4s, would noticeably slow the hook), and check-outdated queries the npm registry (~6.5s, network-dependent, advisory not correctness). Both run in npm run check and CI; pre-commit stays fast and offline.
  • publish:publint and publish:attw are NOT in check — they belong to the publish: prefix because they validate the publishable artifact (dist/) and require a fresh build. Running them on every commit would be wasteful. They run in the CI publish job immediately before npm publish.

Before pushing

Run npm run check locally. If you only trust pre-commit + CI, know that anything check:knip or check:outdated would catch will be caught by CI on the PR before merge.

Publishing workflow

Publishing is CI-only by policy. Local npm publish is not supported.

  1. Develop and merge PRs to main.
  2. CI runs npm run check + npm run test:ci on every push and PR — this is the authoritative gate.
  3. After all intended changes are on main, bump the version locally:
    npm version <patch|minor|major>
    
  4. Push the tag to GitHub:
    git push --follow-tags origin main
    
  5. The publish CI job runs on the tag: build → publish:publint → publish:attw → npm publish --access public. The publish-tier checks must pass before the artifact is published.