Cleaner separation of concerns:
- options.typeAware: true in .oxlintrc.json activates type-aware
rules declaratively (equivalent to --type-aware CLI flag, but
the script command stays clean: just 'oxlint ...')
- Remove the 3 type-aware rule disables from .oxlintrc.json
- Add source-level oxlint-disable directives instead:
- 4x typescript/no-unsafe-type-assertion (pattern.ts: keysMatch
Object.keys() cast, candidate[] cast; structuralMatcher value
as S cast; match.ts: handler as ... cast in nextCases)
- 1x typescript/no-unnecessary-type-parameters (pattern.ts:
keysMatch <S extends object>)
- 1x file-level typescript/no-floating-promises in index.test.ts
(expectTypeOf() is a sync type-assertion library that the
type-aware linter misidentifies)
Disabling rules at the source (next to the line that needs the
exemption) documents intent more clearly than a global config
override, and makes the trade-off visible to anyone reading the
code. Re-enabling a rule in the future only requires removing the
inline comment, not editing a central config.
Activates type-aware rules via oxlint --type-aware, backed by
oxlint-tsgolint (TypeScript-Go). Catches unsafe type assertions,
unnecessary type parameters, and other issues regular oxlint
cannot see.
- Add oxlint-tsgolint devDep + 6 platform-specific native bindings
as optionalDependencies (same pattern as oxlint)
- Add --type-aware flag to check:oxlint
- Add 6 @oxlint-tsgolint/* platforms to check:outdated ignore list
- Disable 3 type-aware rules in .oxlintrc.json with rationale:
- typescript/no-unsafe-type-assertion, typescript/no-unnecessary-type-parameters:
fire on legitimate generic type machinery in keysMatch/MatchBuilder
that needs type-system restructuring (deferred to a follow-up)
- typescript/no-floating-promises in test files: expectTypeOf() is
a sync type-assertion library that oxlint-tsgolint misidentifies
Code simplifications enabled by the new strict checks:
- src/match.ts: drop value as unknown casts (T is already assignable
to unknown) and the redundant run(value) as R cast
- src/index.test.ts: drop unnecessary 'X' as 'X | Y' assertions in
match<...>(...) calls (literals are already assignable to the union)
Documentation updates in project-specs.md and README.md. Add
'tsgolint' to cspell word list.
Node's --strip-types does not rewrite import specifiers the way bundlers
and Deno do, so 'import ... from "./match.js"' literally looks for
match.js (not match.ts) and fails with ERR_MODULE_NOT_FOUND at test
time. Fix by switching source imports to .ts extensions and letting
TypeScript's rewriteRelativeImportExtensions do the rewrite at build
emit time.
Changes:
- tsconfig.json: enable allowImportingTsExtensions (works because the
root config has noEmit: true)
- tsconfig.build.json: enable rewriteRelativeImportExtensions so the
emitted dist/*.js files keep './match.js' style imports (correct for
consumers), not './match.ts'
- src/index.ts: import './match.ts' and './pattern.ts'
- src/match.ts: import './pattern.ts'
- src/index.test.ts: import './index.ts'
Verified: npm run test runs tsc --noEmit (passes) and node --test
--strip-types src/ — all 6 tests pass. tsc -p tsconfig.build.json
emits dist/*.js with './match.js' imports as before; consumers see no
change.
- Install expect-type@1.4.0 (devDependency)
- New src/index.test.ts exercises the public API with both runtime
assertions (node:assert/strict inside node:test) and type-level
assertions (expectTypeOf().toEqualTypeOf, toMatchTypeOf, toHaveProperty)
- Tests are excluded from tsc -p tsconfig.build.json (no .d.ts pollution
in dist/)
- Type-level checks happen during tsc --noEmit (run by 'npm run check' and
the test script); expectTypeOf assertions have no runtime side effect,
so they pair naturally with node --test in the same test() blocks
- cspell: add EDITMSG to dictionary (used in commit-message-template path)
- oxlint test-file overrides: silence no-nodejs-modules (we use node:
builtins) and no-magic-numbers (literals in tests are fine)
Coverage:
- match() returns a builder with with/exhaustive/otherwise
- P.literal narrows to its literal type, P.type to its typeof target
- exhaustive() returns the union of handler return types
- otherwise() falls back when no case matches
- exhaustive() throws when no case matches