Commit Graph
38 Commits
Author SHA1 Message Date
tmu 013bfa883b 📝 Prune the backlog; document the LSP shutdown fix
Remove every done/cancelled backlog item; the reasons they recorded are
already in development/ (library.md, testing.md, tooling.md, workflow.md)
and git history is the archive.

The one exception was the TS 7 LSP shutdown workaround, which lived only in
a code comment. Record it under development/testing.md § Autocomplete
(Known issue) before dropping the bug item.
2026-09-23 15:12:54 +00:00
tmu cbaed8fabc 🐛 Stop knip reporting the source entry
Listing scripts/*.ts in knip's `entry` replaced its default entry
detection, which derives the public entry from package.json `exports`.
Adding the CLI scripts therefore dropped the library entry, so knip
resolved the package through dist/index.js and flagged the unreferenced
src/index.ts as unused. Name the source entry alongside the scripts.

Record the rationale in development/tooling.md.
2026-09-23 14:55:27 +00:00
tmu aaeeef1e11 📝 Document the finite-only universe decision
Record why open universes and value/stringification collisions are
rejected, the `Member<T, K>` inversion, and the findings from the
rejected open-universe attempt so they are not re-run.
2026-09-23 13:42:12 +00:00
tmu 6228b4922d ♻️ Share the Matchable universe between both matchers 2026-09-22 10:54:27 +00:00
tmu e96ca12149 ✨ Allow boolean and nullish tags in tagged unions
A `boolean` / `null` / `undefined` discriminant cannot key a handler
map, so the tagged-union matcher now routes it through the
`PatternKey` / `PatternParam` projection the primitive-union matcher
already used. Both matchers share the projection from
`matcher-shared.ts`; `MapTaggedUnion`, `Handlers`, `HandledMembers`
and `MustBePartial` key off the projected form and invert it to
recover the real member.

Covers exhaustive and fallback dispatch, the redundant-fallback
guard, and the LSP popup offering the tags by name.
2026-09-22 10:22:59 +00:00
tmu 02f736507c ♻️ Rename primitive to primitive-union
`getMatcher` / `getMatcherW` become `getPrimitiveUnionMatcher` /
`getPrimitiveUnionMatcherW`; `src/primitive.ts` and its test move to
`src/primitive-union.*`. The `Union` suffix mirrors `getTaggedUnionMatcher`.
2026-09-22 09:46:59 +00:00
tmu 937d84ea48 ♻️ Share matcher internals 2026-09-21 23:15:09 +00:00
tmu 8ab3c6dbc6 📝 Document the tagged-union matcher 2026-09-21 22:14:22 +00:00
tmu 9e03c52473 ✅ Assert the shape each handler receives
A handler's `expectTypeOf(shape)` only proved the type the compiler inferred;
nothing observed the argument `dispatch` passed. Passing `String(shape)` at the
call site therefore kept the whole suite green while breaking every key whose
property name differs from its value (`true`, `null`, `1`).

Pair each handler expectation with a runtime assertion: `assert.equal` where a
handler runs for one shape, the disjunction over the set a `_` fallback accepts
where it runs for several. Where the exact value matters the fallback returns
its shape verbatim and the call site asserts it; a widening pattern absorbs the
remainder type into the return union, so the claim stays strict-free. The
mutation above now fails 10 of the 33 tests.

Rule: CONTRIBUTING.md, rationale: development/testing.md § Handler arguments.
2026-09-21 12:52:58 +00:00
tmu 80d498e4f4 ⚡ Index dispatch with the raw shape key
String(shape) defeats V8's numeric-key fast path (measured ~2x on
number-keyed dispatch). JS already coerces boolean/null/undefined to the
same property key, so assert shape to string | number and index directly.
The assertion is TS2538-only; the facade keeps it sound. Needs a source
no-unsafe-type-assertion disable, next to the existing one.
2026-09-21 11:23:14 +00:00
tmu 1ad19ba308 📝 Document matcher caveats in the README
State the end-user limits once, in README § Caveats: a member colliding
with its stringification, the unsupported symbol/bigint, and NaN/-0. Drop
the duplicated known-issue prose from development/library.md and the
source comment; link to the README instead.
2026-09-21 10:33:36 +00:00
tmu 16904440cf 📝 Place test-wide suppressions in the config
Drop the fixed no-floating-promises header exception from CONTRIBUTING.md
and AGENTS.md; agents must not add a source disable or edit .oxlintrc.json.
Record the split in tooling.md and testing.md: a one-site false positive is a
source disable, a file-class one lives in the test override.
2026-09-21 10:01:30 +00:00
tmu 45495fe2a8 ✨ Match boolean, null and undefined
Extend the matcher universe beyond string | number so a union can carry
boolean, null and undefined members. true|false, null and undefined are
not property keys, so handler keys are their stringification while the
callback still receives the real member. Symbols are rejected (a brand
is compile-time only) and bigint is not a property key.
2026-09-21 09:44:44 +00:00
tmu f27966e803 ✨ Reject a fallback for an exhaustive map
A fallback paired with a handler map that already covers `T` was still
accepted, even though its remainder is empty. Fold the guard into
`Handled`'s own (F-bounded) constraint so it is checked after inference;
a conditional in the fallback parameter is evaluated while `Handled` is
still its constraint and rejects every partial map whose handler callbacks
need contextual typing.
2026-09-20 22:05:40 +00:00
tmu ae7ffb6fa2 📝 Document the two-argument fallback
Rewrite development/library.md around the new shape: the fallback is a second
argument (so it can receive the remainder), `R` needs an inference site in the
handler map, `Exact` restores the excess-property check, and the overload order
is load-bearing. Record this branch's rejected alternatives (single-object `_`,
currying, `this`/HKT, variance/`const`/`NoInfer`/brands) and the redundant-
fallback known issue. Add the changelog note and check off the backlog task.
2026-09-18 23:52:47 +00:00
tmu 947eac8089 ⏪ Revert the LSP notes in testing.md
The protocol cross-link and the TS-internal shutdown-race explanation were
too detailed for the category doc. The helper comment keeps a short,
self-contained note on the stdin-EOF workaround.
2026-09-18 07:43:36 +00:00
tmu 8b73143740 🐛 Stop the LSP shutdown context-canceled log
The TS 7 Go server races Session.updateWatches against the exit
notification; handleExit returns io.EOF, the background context is
cancelled, and the bare error is flushed to stderr once the outgoing
queue closes (server.go / logger.go). Send shutdown and close stdin
instead: EOF makes the server exit cleanly (code 0, no output), with the
kill kept as a fallback. testing.md records the cause.
2026-09-18 07:31:04 +00:00
tmu 998c4bfd80 📝 Document the protocol-backed LSP helper
Note that the autocomplete helper drives the server through
vscode-languageserver-protocol, cross-link the tooling decision, and replace
the obsolete string-id known issue with the benign context-canceled stderr
the Go server emits on shutdown.
2026-09-18 07:16:45 +00:00
tmu 94ccc16963 ➕ Add the LSP protocol dependency
The autocomplete helper drives tsc --lsp --stdio; vscode-languageserver-protocol
supplies the transport (re-exported vscode-jsonrpc/node) and the typed LSP
requests, replacing the hand-rolled JSON-RPC client. Record the choice and
the rejected alternatives in tooling.md.
2026-09-18 07:14:45 +00:00
tmu 88159296d4 📝 Drop the stale scripts test glob from testing.md
No tests live under scripts/, and every test script (test, test:unit, test:ci,
watch:test) globs only src/**/*.test.ts, so state that. The scripts/**
oxlint scope it was confused with still exists and carries the same
import/no-nodejs-modules exception as the test-helper scope.
2026-09-17 21:55:41 +00:00
tmu 800c11139d ♻️ Name the matcher factories getMatcher / getMatcherW
Drop the strict/widened aliases from src/index.ts so the factories are
exported under their own names, and align the type tests, the autocomplete
probe (which now imports the public surface from ./index.ts) and library.md
with them.

Also correct the widened-overload comment: the excess-property check does not
apply to a generic P, so MatcherWidening's keyof guard — not the closed
constraint — is what rejects keys outside T/_, as library.md already
documented.
2026-09-17 21:48:54 +00:00
tmu 05fad0fcd6 📝 Record the autocomplete and matcher-design decisions
The matcher is now two three-overload factories; library.md documents why
the union merge, inferred universe, conditional RequireKeys and cases-first
paths were rejected, and lists the two open issues (the fallback sees all of
T; a redundant _ is still accepted). testing.md records the language server
as the autocomplete oracle, and CONTRIBUTING points the exception at the
matcher's own test file.

The backlog marks the design-doc and autocomplete groundwork done alongside
the adoption.
2026-09-17 20:59:28 +00:00
tmu c51e32d6a6 📝 Record the test-helper home decision
development/testing.md § Test helpers: why name beats path under
import/no-relative-parent-imports, why the key needs `#`, why the
`__tests__` folder name, and what was rejected (flat placement, tsconfig
paths, rule exemptions).
2026-09-17 13:23:29 +00:00
tmu a3eb6183af 🔥 Remove the match and pattern example modules
They were the template's demo API, not the library's real surface. Drop
them, their README walkthrough, and the tooling note that cited their
disable directives, and point index.ts at the primitive matchers that
remain.
2026-09-16 21:57:55 +00:00
tmu ce3d618757 🔥 Remove the example index spec
The spec only exercised the template's match/P example API. Removing it
first lets the modules and exports it imports go next without leaving a
dangling reference.
2026-09-16 21:57:42 +00:00
tmu fa0b7f2e84 🔧 Allow ternaries and lowercase comments
Turn off `eslint/no-ternary` and `eslint/capitalized-comments` in the
project config: both encode a style the project rejects, so they belong in
the config's rule map rather than a per-site disable.

Scope the adjacent `oxlint-disable` decision to false positives and
record why a rejected stylistic rule is turned off project-wide.
2026-09-16 21:45:54 +00:00
tmu 62a5599ab3 📝 Require labeled AAA blocks in tests
Rule in CONTRIBUTING.md; decision, why and rejected unlabeled
ordering in development/testing.md.
2026-09-16 16:00:43 +00:00
tmu a25ac6d1e2 ✅ Spec primitive union matchers
Type-driven tests: every expectTypeOf pairs an assert, covering the
header matrix (exhaustive vs partial patterns, strict R vs widened
returns, string and numeric keys, _ fallback wiring).

Negative cases use Parameters<typeof factory>[0] assignability because
expect-type's .not.toBeCallableWith collapses to never on these generic
Simplify<>-wrapped signatures.

Same documented expectTypeOf floating-promise false positive as
index.test.ts, so the same file-level disable applies; testing.md
known-issue updated to list both files.
2026-09-16 14:52:30 +00:00
tmu c15bc0153e 📝 Require concise prose in development/
Actionable sentence in CONTRIBUTING.md § Rules the tools don't enforce;
the why — humans skim, agents imitate the dominant style, so verbosity
compounds — in development/README.md § Decision blocks. Both sides in
one commit per the write-each-fact-once rule.
2026-09-16 08:00:36 +00:00
tmu ae319f6547 🔧 Ignore @types/node in maintain:outdated
DefinitelyTyped keeps the @types/node latest dist-tag on the LTS line,
so check-outdated compared the current-line types against a lower
version: a permanent "reverted" flag, scan exit 1, zero signal. Ignored
by package name; --types filtering and a version-scoped pin rejected
(rationale in development/tooling.md).
2026-09-16 07:55:25 +00:00
tmu d646fd1ec4 ♻️ Let create:branch start from an ahead main
`create:finish` leaves the merge local until `create:release` pushes it, so
`main` is routinely ahead of its upstream between a merge and a release. The
branch front door demanded an exact match and refused until it was pushed,
forcing a manual `git push` that the model deliberately keeps out of it.

Reject only a `main` that is behind its upstream — matching `create:finish`,
which already tolerates being ahead — and record why pushing from `finish` was
rejected instead. The push stays with `create:release`, so the merge remains
reviewable locally, and the known issue about the deadlock is gone.

Resolves: backlog task "Resolve the finish/push tension".
2026-09-15 22:14:51 +00:00
tmu f6f820a648 📝 Require a changelog note before finishing a branch
A merged branch must carry a final commit adding a short summary of the
work under [Unreleased] in CHANGELOG.md. create:release derives the bump
heuristic from that body, so notes have to exist before release day;
rationale in development/workflow.md.
2026-09-15 22:08:08 +00:00
tmu 5e7d40b013 📝 Improve docs after split 2026-09-15 21:46:41 +00:00
tmu 74c39e1346 ♻️ Tighten the development/ prose
Same decisions, rationale, rejected alternatives and known issues, said with
less padding: ~5,530 -> ~4,730 words (-15%). Every fact from the first draft is
kept; only the wording, duplicated lead-ins and restated context are cut.
2026-09-15 13:56:49 +00:00
tmu 7ea84b66fa ♻️ Drop the last duplicated prose from development/
The GitHub Flow description and the type-first enforcement sentence still
appeared in both CONTRIBUTING.md and development/. development/ now carries only
the context and rationale that is not in CONTRIBUTING.md.
2026-09-15 13:47:01 +00:00
tmu 95d73d11b6 ♻️ Single-home the actionable rules and the rationale
development/ had restated the actionables that CONTRIBUTING.md owns: the
branching step list, the script prefix list, the feedback-tier rule of thumb,
the commit convention and the type-driven test loop. Those now live only in
CONTRIBUTING.md; development/ keeps the decision blocks and links to the rule.
development/README.md, CONTRIBUTING.md and AGENTS.md state the 'write each fact
once' principle explicitly.
2026-09-15 13:46:31 +00:00
tmu 84d48c6e67 📝 Make the rule/rationale split explicit
AGENTS.md and CONTRIBUTING.md now state that a decision, its rejected
alternatives and its known issues belong in development/<category>.md, that the
actionable rule stays in CONTRIBUTING.md, and that both change in the same
commit. development/README.md names library.md in the category list and spells
out that the sync runs in both directions.
2026-09-15 13:39:58 +00:00
tmu dc7ce22fc5 📝 Add development/ docs for decisions and known issues
Category files under development/ replace the decision prose that was
scattered through README.md and CONTRIBUTING.md. Each decision is a block with
Decision (YYYY-MM) / Why / Rejected / Known issue; the new library.md records
the public API contract and its limitations. AGENTS.md and backlog.tasks now
point at the new home.
2026-09-15 13:26:59 +00:00