📝 Reconcile project-specs.md and cspell.json with the feature/setup branch
This commit is contained in:
1 parent
1fe3dbe28b
commit
1a749b13d6
2 files changed
+77
-44
No files matched your search
@@ -2,8 +2,6 @@
|
||||
"version": "0.2",
|
||||
"language": "en",
|
||||
"words": [
|
||||
"tslib",
|
||||
"typefest",
|
||||
"lefthook",
|
||||
"oxlint",
|
||||
"oxfmt",
|
||||
|
||||
+77
-42
@@ -8,13 +8,28 @@ typescript-lib-starter-tiny => https://github.com/tmueller/typescript-lib-starte
|
||||
|
||||
## 1. Development Environment
|
||||
|
||||
- **TypeScript**: Use strictest practical rules. Inline in `tsconfig.json` (not
|
||||
via `@tsconfig/strictest`). The rule set is: `strict`, `noImplicitAny`,
|
||||
`noImplicitThis`, `alwaysStrict`, `strictNullChecks`, `strictFunctionTypes`,
|
||||
`strictBindCallApply`, `strictPropertyInitialization`, `noImplicitReturns`,
|
||||
`noFallthroughCasesInSwitch`, `noUncheckedIndexedAccess`, `noImplicitOverride`,
|
||||
`noUnusedLocals`, `noUnusedParameters`, `forceConsistentCasingInFileNames`,
|
||||
`isolatedModules`, `verbatimModuleSyntax`.
|
||||
- **TypeScript**: Use strictest practical rules via `@tsconfig/strictest`
|
||||
(extended from `tsconfig.json`). The project also extends
|
||||
`@tsconfig/node26` for Node 26's `target`/`module`/`lib` defaults;
|
||||
`tsconfig.json` is the type-check base (`noEmit: true`, includes
|
||||
`src/`), and `tsconfig.build.json` extends it to add the emit-only
|
||||
options (`declaration`, `sourceMap`, `outDir`, `target: es2024`,
|
||||
`rewriteRelativeImportExtensions: true`) and to exclude test files
|
||||
from emission. The `verbatimModuleSyntax: true` and
|
||||
`allowImportingTsExtensions: true` overrides live in
|
||||
`tsconfig.json` (the latter only works because the base has
|
||||
`noEmit: true`). The strictest flags the project relies on (inherited
|
||||
from `@tsconfig/strictest`) are: `strict`, `noImplicitAny`,
|
||||
`noImplicitThis`, `alwaysStrict`, `strictNullChecks`,
|
||||
`strictFunctionTypes`, `strictBindCallApply`,
|
||||
`strictPropertyInitialization`, `noImplicitReturns`,
|
||||
`noFallthroughCasesInSwitch`, `noUncheckedIndexedAccess`,
|
||||
`noImplicitOverride`, `noUnusedLocals`, `noUnusedParameters`,
|
||||
`forceConsistentCasingInFileNames`, `isolatedModules`,
|
||||
`verbatimModuleSyntax`, plus the additional strictest flags
|
||||
(`exactOptionalPropertyTypes`, `noPropertyAccessFromIndexSignature`,
|
||||
`noUncheckedIndexedAccess` etc.) that `@tsconfig/strictest` enables
|
||||
beyond a plain `strict: true`.
|
||||
- **EditorConfig**: Use `.editorconfig` from typescript-lib-starter-tiny.
|
||||
- **oxfmt**: Rust-based formatter, Prettier-compatible. Replaces Prettier.
|
||||
Config in `.oxfmtrc.json` (same shape as `.prettierrc`).
|
||||
@@ -34,6 +49,8 @@ typescript-lib-starter-tiny => https://github.com/tmueller/typescript-lib-starte
|
||||
- `eslint/sort-keys` — handler/case order is semantic, not alphabetical.
|
||||
- `eslint/id-length` — `T`, `R`, `U`, `V` are standard TS generics.
|
||||
- `import/no-named-export` — false positive on library entry re-exports.
|
||||
- `typescript/method-signature-style` — method signatures in
|
||||
`interface` declarations are conventional TS ergonomics.
|
||||
- Stylistic rules superseded by oxfmt (oxfmt is the canonical
|
||||
formatter; these rules either conflict with its output or
|
||||
duplicate features oxfmt already provides):
|
||||
@@ -48,8 +65,6 @@ typescript-lib-starter-tiny => https://github.com/tmueller/typescript-lib-starte
|
||||
`import { type X, Y }` is intentional for grouping.
|
||||
- `unicorn/prefer-export-from` — conflicts with how the
|
||||
barrel `src/index.ts` re-exports through `src/match.ts`.
|
||||
- `typescript/method-signature-style` — method signatures
|
||||
in `interface` are conventional TS ergonomics.
|
||||
For `*.test.ts` files additionally: `no-unused-expressions` (for
|
||||
`expectTypeOf(...)` calls), `no-empty-file` (we have a single import
|
||||
per test file in some cases), `import/no-nodejs-modules` (we use
|
||||
@@ -58,9 +73,9 @@ typescript-lib-starter-tiny => https://github.com/tmueller/typescript-lib-starte
|
||||
- **Import sorting**: built into oxfmt (no separate plugin).
|
||||
- **cspell**: Basic spelling configuration. Words dictionary in `cspell.json`
|
||||
covers tooling names (`oxlint`, `oxfmt`, `oxc`, `nodenext`,
|
||||
`oxfmtrc`, `oxlintrc`, `EDITMSG`, `typescriptteam`,
|
||||
`gitmoji`, `dbaeumer`, `msvc`) and a few library names (`tslib`,
|
||||
`typefest`, `lefthook`).
|
||||
`oxfmtrc`, `oxlintrc`, `tsgolint`, `EDITMSG`, `typescriptteam`,
|
||||
`gitmoji`, `dbaeumer`, `msvc`, `publint`, `attw`, `arethetypeswrong`,
|
||||
`knip`) and a few library names (`lefthook`).
|
||||
- **Lefthook**: Pre-commit checks (run in parallel, lefthook v2 schema).
|
||||
Single source of truth for the underlying commands is in
|
||||
`package.json#scripts`; the lefthook config only describes _what to
|
||||
@@ -82,16 +97,27 @@ typescript-lib-starter-tiny => https://github.com/tmueller/typescript-lib-starte
|
||||
CI and via the explicit `lefthook run outdated` command.
|
||||
|
||||
- **Additional Dev Dependencies**:
|
||||
- lefthook
|
||||
- check-outdated
|
||||
- lefthook (git hook manager)
|
||||
- check-outdated (outdated dependency warnings)
|
||||
- knip (unused dependency / export / file detection)
|
||||
- publint (publish-time `package.json` validation)
|
||||
- @arethetypeswrong/cli (attw, publish-time `.d.ts` validation)
|
||||
- @tsconfig/strictest, @tsconfig/node26 (extended from in
|
||||
`tsconfig.json`)
|
||||
- c8 (coverage for `node --test`)
|
||||
- expect-type (type-level assertions in tests)
|
||||
- oxfmt, oxlint (with their native bindings as `optionalDependencies`
|
||||
so the correct binding is selected per platform automatically)
|
||||
- oxlint-tsgolint (type-aware linter backend, also with native
|
||||
bindings as `optionalDependencies`)
|
||||
- cspell (spell checking)
|
||||
- typescript (TS 7)
|
||||
- @types/node
|
||||
- tslib (available for future runtime helper imports)
|
||||
- type-fest (utility types)
|
||||
|
||||
`tslib` and `type-fest` were removed (commit `ec98223`): knip
|
||||
flagged them as unused, and they were not appropriate for an
|
||||
ES2024-targeting ESM-only library (`tslib` is a runtime helper for
|
||||
old ES3/ES5 targets; `type-fest` was never imported).
|
||||
|
||||
## 2. Build & Test
|
||||
|
||||
@@ -121,10 +147,6 @@ typescript-lib-starter-tiny => https://github.com/tmueller/typescript-lib-starte
|
||||
- `target: es2024`, `lib: ["es2024"]` (Node 26 supports all ES2024
|
||||
features natively).
|
||||
- **Additional Dev Dependencies** (for types and tests):
|
||||
- `tslib` — available for runtime helper imports; not currently
|
||||
used by source (kept for future use per the original spec).
|
||||
- `type-fest` — utility types; not currently used by source
|
||||
(kept for future use per the original spec).
|
||||
- `@types/node` — types for `node:test`, `node:assert`, `node:fs`.
|
||||
- **Node Version**: `>=26` (engines field). Pinned via `.node-version`
|
||||
for fnm/nvm/volta/mise auto-switching and CI
|
||||
@@ -207,7 +229,10 @@ script does not belong in the standard pipeline.
|
||||
- `test:unit`: Run unit tests with `node --test --strip-types "src/**/*.test.ts"`
|
||||
(no preceding typecheck).
|
||||
- `test:ci`: Run tests in CI mode with c8 coverage (text + lcov + html
|
||||
reporters), uploading `coverage/` as an artifact.
|
||||
reporters), uploading `coverage/` as an artifact. The command is
|
||||
`c8 --reporter=text --reporter=lcov --reporter=html node --test
|
||||
--strip-types "src/**/*.test.ts"` (the glob is required on Node 26
|
||||
for the same reason `test` uses one — see below).
|
||||
|
||||
### BUILD
|
||||
|
||||
@@ -223,8 +248,11 @@ script does not belong in the standard pipeline.
|
||||
|
||||
### CHECK
|
||||
|
||||
- `check`: Run all checks in order — `check:oxlint`, `check:oxfmt`,
|
||||
`check:tsc`, `check:cspell`, `check:knip`, `check:outdated`.
|
||||
- `check`: Run all checks in order — `check:tsc`, `check:oxlint`,
|
||||
`check:oxfmt`, `check:cspell`, `check:knip`, `check:outdated`.
|
||||
`check:tsc` is first so a type error short-circuits the rest
|
||||
(faster feedback than letting oxlint/oxfmt run and then failing on
|
||||
tsc at the end).
|
||||
- `check:oxlint`: `oxlint ${LEFTHOOK_FILES:-src}` — lints `src/` by
|
||||
default; when invoked from the lefthook pre-commit hook with
|
||||
`LEFTHOOK_FILES` set to the staged-files list, lints only those
|
||||
@@ -256,7 +284,8 @@ script does not belong in the standard pipeline.
|
||||
- `check:tsc`: `tsc` (noEmit is set in `tsconfig.json`).
|
||||
- `check:cspell`: `cspell lint ${LEFTHOOK_FILES:-.}` — walks the
|
||||
project root by default; from lefthook, only the staged files.
|
||||
- `check:outdated`: `check-outdated --ignore-pre-releases --ignore-packages @oxfmt/binding-*,@oxlint/binding-*`. The oxc native bindings are declared as `optionalDependencies` so the correct one is selected per platform automatically; the `*`-platform bindings show as "not installed" on the current platform and are explicitly ignored here.
|
||||
- `check:outdated`: `check-outdated --ignore-pre-releases
|
||||
--ignore-packages @oxfmt/binding-darwin-arm64,@oxfmt/binding-darwin-x64,@oxfmt/binding-linux-arm64-gnu,@oxfmt/binding-linux-arm64-musl,@oxfmt/binding-linux-x64-gnu,@oxfmt/binding-linux-x64-musl,@oxfmt/binding-win32-x64-msvc,@oxlint/binding-darwin-arm64,@oxlint/binding-darwin-x64,@oxlint/binding-linux-arm64-gnu,@oxlint/binding-linux-arm64-musl,@oxlint/binding-linux-x64-gnu,@oxlint/binding-linux-x64-musl,@oxlint/binding-win32-x64-msvc,@oxlint-tsgolint/darwin-arm64,@oxlint-tsgolint/darwin-x64,@oxlint-tsgolint/linux-arm64,@oxlint-tsgolint/linux-x64,@oxlint-tsgolint/win32-arm64,@oxlint-tsgolint/win32-x64`. The oxfmt, oxlint, and oxlint-tsgolint native bindings are declared as `optionalDependencies` so the correct one is selected per platform automatically; bindings for non-current platforms show as "not installed" and are explicitly ignored here.
|
||||
- `check:knip`: `knip --include dependencies,exports,files` — finds
|
||||
unused dependencies, value exports, and source files. The
|
||||
scoped `--include` list intentionally omits the `types`
|
||||
@@ -311,7 +340,7 @@ deliberate design choice; the rule of thumb is:
|
||||
- **pre-commit hook**: fast, file-scoped, offline, deterministic.
|
||||
Catches what _you just changed_ in under a second or two.
|
||||
- **pre-push hook**: runs the unit test suite (`npm test`,
|
||||
including a full `tsc` over the project). ~500ms. Catches
|
||||
including a full `tsc` over the project). ~3.5s. Catches
|
||||
runtime/logic bugs across the whole codebase before the push
|
||||
leaves your machine. The `tsc` step is technically redundant
|
||||
with pre-commit but validates against unstaged changes too.
|
||||
@@ -321,17 +350,22 @@ deliberate design choice; the rule of thumb is:
|
||||
`npm run test:ci` on every push and PR. The ground truth —
|
||||
if CI passes, the codebase is clean.
|
||||
|
||||
| Script | pre-commit | pre-push | `npm run check` | CI build | CI publish |
|
||||
| ----------------- | :--------: | :------: | :-------------: | :------: | :--------: |
|
||||
| `check:tsc` | ✅ | ✅ | ✅ | ✅ | — |
|
||||
| `check:oxlint` | ✅ | — | ✅ | ✅ | — |
|
||||
| `check:oxfmt` | ✅ | — | ✅ | ✅ | — |
|
||||
| `check:cspell` | ✅ | — | ✅ | ✅ | — |
|
||||
| `test` | — | ✅ | — | ✅ | — |
|
||||
| `check:knip` | — | — | ✅ | ✅ | — |
|
||||
| `check:outdated` | — | — | ✅ | ✅ | — |
|
||||
| `publish:publint` | — | — | — | — | ✅ |
|
||||
| `publish:attw` | — | — | — | — | ✅ |
|
||||
| Script | pre-commit | pre-push | `npm run check` | `npm run fix` | CI build | CI publish |
|
||||
| ----------------- | :--------: | :------: | :-------------: | :-----------: | :------: | :--------: |
|
||||
| `check:tsc` | ✅ | ✅ | ✅ | — | ✅ | — |
|
||||
| `check:oxlint` | ✅ | — | ✅ | — | ✅ | — |
|
||||
| `check:oxfmt` | ✅ | — | ✅ | — | ✅ | — |
|
||||
| `check:cspell` | ✅ | — | ✅ | — | ✅ | — |
|
||||
| `test` | — | ✅ | — | — | ✅ | — |
|
||||
| `check:knip` | — | — | ✅ | — | ✅ | — |
|
||||
| `check:outdated` | — | — | ✅ | — | ✅ | — |
|
||||
| `fix:oxlint` | — | — | — | ✅ | — | — |
|
||||
| `fix:oxfmt` | — | — | — | ✅ | — | — |
|
||||
| `publish:publint` | — | — | — | — | — | ✅ |
|
||||
| `publish:attw` | — | — | — | — | — | ✅ |
|
||||
|
||||
(Each `test` row also runs `check:tsc` internally, so pre-push gets a
|
||||
full `tsc` for free.)
|
||||
|
||||
#### Why these splits?
|
||||
|
||||
@@ -342,12 +376,13 @@ deliberate design choice; the rule of thumb is:
|
||||
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 (~500ms
|
||||
for the current 6 tests). The pre-commit `LEFTHOOK_FILES`
|
||||
convention doesn't apply to the test runner, so pre-commit
|
||||
isn't the right home. Pre-push is the natural place: it runs
|
||||
after all commits are made but before the push leaves the
|
||||
machine, catching regressions that span multiple commits.
|
||||
runs the whole test suite across the whole project (~3.5s
|
||||
for the current 6 tests, including a full `tsc`). The pre-commit
|
||||
`LEFTHOOK_FILES` convention doesn't apply to the test runner,
|
||||
so pre-commit isn't the right home. Pre-push is the natural
|
||||
place: it runs after all commits are made but before the push
|
||||
leaves the machine, catching regressions that span multiple
|
||||
commits.
|
||||
|
||||
- **`check:knip` is NOT in pre-commit or pre-push** because it
|
||||
scans the whole project (not staged files) and takes ~4s.
|
||||
|
||||
Reference in new issue
Block a user