📝 Document the TypeScript 5.0 type floor
Consumers need TypeScript >= 5.0: the emitted declarations use const type parameters and keep relative .ts specifiers, both of which resolve only on TS >= 5.0. That also makes the emitted .ts specifiers a non-issue, so the backlog item is closed without a .d.ts post-step: TS <= 4.9 cannot parse the declarations anyway. The README/CONTRIBUTING wording now says the rewrite applies to the JavaScript output, not to the declarations.
This commit is contained in:
1 parent
e7a058d608
commit
a0dd187042
3 files changed
+8
-6
No files matched your search
+1
-1
@@ -6,7 +6,7 @@ This document is for maintainers and contributors working on the project itself.
|
|||||||
|
|
||||||
CI and review will bounce these even though `npm run check` and the linters don't catch them. They're the high-frequency things a contributor (or an agent) reaches for by default:
|
CI and review will bounce these even though `npm run check` and the linters don't catch them. They're the high-frequency things a contributor (or an agent) reaches for by default:
|
||||||
|
|
||||||
- **Source imports use `.ts` extensions, never `.js`.** `node --strip-types` resolves the `.ts` form at test time; `rewriteRelativeImportExtensions` emits `.js` in `dist/`. "Pre-fixing" an import to `.js` breaks the inner loop. (rationale: README § Tooling decisions)
|
- **Source imports use `.ts` extensions, never `.js`.** `node --strip-types` only resolves the `.ts` form at test time; "Pre-fixing" an import to `.js` breaks the inner loop. (rationale: README § Tooling decisions)
|
||||||
- **A new `npm run` script must reuse an existing prefix** (`create:` / `check:` / `fix:` / `test:` / `watch:` / `maintain:` / `publish:` / `setup:`). If none fits, that's a signal the script doesn't belong in the pipeline — not a reason to invent a new prefix. If it genuinely does belong, add the prefix to both lists here in the same commit; an undocumented prefix becomes invisible and quietly accrues members. (see [Script prefix convention](#script-prefix-convention))
|
- **A new `npm run` script must reuse an existing prefix** (`create:` / `check:` / `fix:` / `test:` / `watch:` / `maintain:` / `publish:` / `setup:`). If none fits, that's a signal the script doesn't belong in the pipeline — not a reason to invent a new prefix. If it genuinely does belong, add the prefix to both lists here in the same commit; an undocumented prefix becomes invisible and quietly accrues members. (see [Script prefix convention](#script-prefix-convention))
|
||||||
- **`oxlint-disable` directives live in source, not `.oxlintrc.json`.** The trade-off must sit next to the code it silences. This is a _human_ last-resort convention; agents must not add these — see [AGENTS.md § Never do](./AGENTS.md#never-do). (rationale: README § Tooling decisions)
|
- **`oxlint-disable` directives live in source, not `.oxlintrc.json`.** The trade-off must sit next to the code it silences. This is a _human_ last-resort convention; agents must not add these — see [AGENTS.md § Never do](./AGENTS.md#never-do). (rationale: README § Tooling decisions)
|
||||||
- **Don't put slow / network / whole-project scans in `check` or pre-commit.** Advisory scans are not correctness gates; they belong under `maintain:`. (see [Feedback tiers](#feedback-tiers) and [Script prefix convention](#script-prefix-convention))
|
- **Don't put slow / network / whole-project scans in `check` or pre-commit.** Advisory scans are not correctness gates; they belong under `maintain:`. (see [Feedback tiers](#feedback-tiers) and [Script prefix convention](#script-prefix-convention))
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ Each tool's configuration trade-off is recorded in [Tooling decisions](#tooling-
|
|||||||
The choice and configuration of each tool above is the result of deliberate trade-offs, not defaults. The non-obvious ones:
|
The choice and configuration of each tool above is the result of deliberate trade-offs, not defaults. The non-obvious ones:
|
||||||
|
|
||||||
- **`tsconfig.json` extends `@tsconfig/strictest` + `@tsconfig/node26`**; `tsconfig.build.json` extends it to add the emit-only options (`declaration`, `sourceMap`, `inlineSources`, `outDir`, `target: es2024`, `rewriteRelativeImportExtensions: true`) and to exclude test files. `inlineSources` embeds the original TypeScript in `dist/*.js.map`, so debuggers can map into `src/` without it being shipped; `declarationMap` is intentionally off because a `.d.ts.map` cannot embed source and would dangle. This separation lets the editor and CI type-check from one config while the build emits from the other.
|
- **`tsconfig.json` extends `@tsconfig/strictest` + `@tsconfig/node26`**; `tsconfig.build.json` extends it to add the emit-only options (`declaration`, `sourceMap`, `inlineSources`, `outDir`, `target: es2024`, `rewriteRelativeImportExtensions: true`) and to exclude test files. `inlineSources` embeds the original TypeScript in `dist/*.js.map`, so debuggers can map into `src/` without it being shipped; `declarationMap` is intentionally off because a `.d.ts.map` cannot embed source and would dangle. This separation lets the editor and CI type-check from one config while the build emits from the other.
|
||||||
- **Source imports use `.ts` extensions** so `node --strip-types` resolves them at test time. `rewriteRelativeImportExtensions: true` in `tsconfig.build.json` rewrites them to `.js` in the emitted `dist/*` output, so consumers see conventional ESM imports.
|
- **Source imports use `.ts` extensions** so `node --strip-types` resolves them at test time. `rewriteRelativeImportExtensions: true` in `tsconfig.build.json` rewrites them to `.js` in the emitted JavaScript; the emitted `.d.ts` keep the `.ts` specifier, which TypeScript >= 5.0 resolves (see [Requirements](#requirements)), so no post-processing step is needed.
|
||||||
- **Type-aware oxlint is enabled declaratively** via `options.typeAware: true` in `.oxlintrc.json` (powered by `oxlint-tsgolint`). The script commands stay clean — no CLI flag — and type-aware mode is a property of the config, not the invocation.
|
- **Type-aware oxlint is enabled declaratively** via `options.typeAware: true` in `.oxlintrc.json` (powered by `oxlint-tsgolint`). The script commands stay clean — no CLI flag — and type-aware mode is a property of the config, not the invocation.
|
||||||
- **Source-level `oxlint-disable` directives** are used for known type-aware false positives (see `src/pattern.ts`, `src/match.ts`, `src/index.test.ts`). The disable lives next to the code it silences, not in `.oxlintrc.json`, so the trade-off is visible to anyone reading the source.
|
- **Source-level `oxlint-disable` directives** are used for known type-aware false positives (see `src/pattern.ts`, `src/match.ts`, `src/index.test.ts`). The disable lives next to the code it silences, not in `.oxlintrc.json`, so the trade-off is visible to anyone reading the source.
|
||||||
- **`knip --include dependencies,exports,files`** intentionally omits the `types` category, which produces systematic false positives for libraries whose exported types are part of the public API. The targeted scope keeps the signal high without config-file boilerplate.
|
- **`knip --include dependencies,exports,files`** intentionally omits the `types` category, which produces systematic false positives for libraries whose exported types are part of the public API. The targeted scope keeps the signal high without config-file boilerplate.
|
||||||
@@ -52,6 +52,7 @@ The choice and configuration of each tool above is the result of deliberate trad
|
|||||||
### Requirements
|
### Requirements
|
||||||
|
|
||||||
- Node.js >= 26 (engines field; pinned via `.node-version`).
|
- Node.js >= 26 (engines field; pinned via `.node-version`).
|
||||||
|
- TypeScript >= 5.0 to consume the published declarations. The emitted `.d.ts` use `const` type parameters (TS 5.0) and keep their relative `.ts` specifiers; both resolve on TS >= 5.0 in `node10`/`node16`/`nodenext`/`bundler`.
|
||||||
|
|
||||||
## VSCode integration
|
## VSCode integration
|
||||||
|
|
||||||
|
|||||||
+5
-4
@@ -16,7 +16,7 @@ Setup:
|
|||||||
- `verify = check + test:unit`; `check:tsc` uses the root config (`noEmit: true`), so `tsconfig.build.json` is only exercised by `build`
|
- `verify = check + test:unit`; `check:tsc` uses the root config (`noEmit: true`), so `tsconfig.build.json` is only exercised by `build`
|
||||||
- a broken build config (bad `rootDir`, emit-option typo) passes `verify` and only fails in CI
|
- a broken build config (bad `rootDir`, emit-option typo) passes `verify` and only fails in CI
|
||||||
✔ Confirmed no change: `verify` is the local quick source-correctness check; the emit path is gated by CI's `build` job (`npm run build`), so adding `build` locally only adds inner-loop friction @done
|
✔ Confirmed no change: `verify` is the local quick source-correctness check; the emit path is gated by CI's `build` job (`npm run build`), so adding `build` locally only adds inner-loop friction @done
|
||||||
☐ Fix `.ts` extensions in emitted `.d.ts`
|
✔ Fix `.ts` extensions in emitted `.d.ts` @done
|
||||||
- emitted JS rewrites `./pattern.ts` → `./pattern.js`, but `dist/*.d.ts` still imports `"./pattern.ts"` / `"./match.ts"`
|
- emitted JS rewrites `./pattern.ts` → `./pattern.js`, but `dist/*.d.ts` still imports `"./pattern.ts"` / `"./match.ts"`
|
||||||
- resolves under TS7, but a portability risk for older resolvers/bundlers; `attw` does not catch it
|
- resolves under TS7, but a portability risk for older resolvers/bundlers; `attw` does not catch it
|
||||||
- HANDOVER (setup-phase review, unfixed — emit work deferred out of that session):
|
- HANDOVER (setup-phase review, unfixed — emit work deferred out of that session):
|
||||||
@@ -24,9 +24,10 @@ Setup:
|
|||||||
- `npm run build` + `publish:publint` + `publish:attw` + a packed-consumer `tsc -p` all pass today, so this is a portability/robustness fix, not a broken-build fix — don't expect a red gate to confirm it works
|
- `npm run build` + `publish:publint` + `publish:attw` + a packed-consumer `tsc -p` all pass today, so this is a portability/robustness fix, not a broken-build fix — don't expect a red gate to confirm it works
|
||||||
- the durable proof is a consumer-resolution typecheck that asserts types still flow (a deliberately-wrong assignment must error), not just exit 0 — TS7 resolution silently tolerates the `.ts` form, so a green run alone proves nothing
|
- the durable proof is a consumer-resolution typecheck that asserts types still flow (a deliberately-wrong assignment must error), not just exit 0 — TS7 resolution silently tolerates the `.ts` form, so a green run alone proves nothing
|
||||||
- two directions: (a) post-process the `.d.ts` imports to `.js` in the build, or (b) stop emitting relative `.ts` on the declaration surface (e.g. build-only source or an internal barrel). Either way reconcile the README/CONTRIBUTING sentence claiming the option yields "conventional ESM imports" for consumers
|
- two directions: (a) post-process the `.d.ts` imports to `.js` in the build, or (b) stop emitting relative `.ts` on the declaration surface (e.g. build-only source or an internal barrel). Either way reconcile the README/CONTRIBUTING sentence claiming the option yields "conventional ESM imports" for consumers
|
||||||
☐ Fix the declaration emit (`.d.ts` post-step) or stop using relative `.ts` in the declaration surface
|
- resolution: no code change. TypeScript >= 5.0 resolves the `.ts` specifier in shipped declarations in `node10`/`node16`/`nodenext`/`bundler` (verified across TS 4.7–7.0 with a consumer `@ts-expect-error` type guard). TS <= 4.9 rejects it, but also cannot parse the `<const L extends …>` already emitted in `dist/pattern.d.ts` (const type parameters, a TS 5.0 feature), so no consumer that can use the package is affected; the effective floor is now documented in README § Requirements
|
||||||
☐ Reconcile the README/CONTRIBUTING claim that `rewriteRelativeImportExtensions` yields "conventional ESM imports"
|
✘ Post-process the declaration emit to `.js`, or restructure to avoid relative `.ts` on the declaration surface @cancelled
|
||||||
☐ Add a consumer-resolution test to the suite (durable guard; `attw` currently misses it)
|
✔ Reconcile the README/CONTRIBUTING claim that `rewriteRelativeImportExtensions` yields "conventional ESM imports"; document the TS >= 5.0 floor @done
|
||||||
|
✘ Add a consumer-resolution test (moot without a fix; `attw` still misses this class of issue) @cancelled
|
||||||
✔ Resolve sourcemap sources for consumers @done
|
✔ Resolve sourcemap sources for consumers @done
|
||||||
- `dist/*.map` `sources` are `../src/*.ts`, but `src` is not in `files`, so debuggers get missing sources
|
- `dist/*.map` `sources` are `../src/*.ts`, but `src` is not in `files`, so debuggers get missing sources
|
||||||
- HANDOVER (setup-phase review, unfixed — emit work deferred out of that session):
|
- HANDOVER (setup-phase review, unfixed — emit work deferred out of that session):
|
||||||
|
|||||||
Reference in new issue
Block a user