chore: version packages#50
Merged
Merged
Conversation
d35c23b to
530dd10
Compare
530dd10 to
252c0a6
Compare
252c0a6 to
c1149b4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.
Releases
@zipbul/router@1.0.0
Major Changes
f938797: BREAKING: collapse two 2-state public enums into booleans on
RouterOptions.The
TrailingSlashandOptionalParamBehaviorenums each had only twomembers. They were boolean choices dressed up as enums — the internal
pipeline already converted both to booleans before consuming them
(
router.ts:95,build.ts:106). Replacing the enums with booleansremoves ceremony from every call site without changing runtime behavior.
Migration
{ trailingSlash: TrailingSlash.Strict }{ ignoreTrailingSlash: false }{ trailingSlash: TrailingSlash.Ignore }(default){ ignoreTrailingSlash: true }(or omit){ optionalParamBehavior: OptionalParamBehavior.Omit }(default){ omitMissingOptional: true }(or omit){ optionalParamBehavior: OptionalParamBehavior.SetUndefined }{ omitMissingOptional: false }Defaults are unchanged: trailing slash is ignored by default; missing
optional parameters are omitted from
paramsby default.Public export surface
The two enum names are removed from the public exports. Remaining
exports:
Router,RouterError,MatchSource,RouterErrorKind.MatchSource(3 members) andRouterErrorKind(21 members) remainenums — both have enough cardinality that the enum form carries
meaningful information.
Minor Changes
8f77a9f: Fix a broken published build and several match-time correctness defects.
Build
bun build --packages external+sideEffects: falsecombination triggered a Bun bundler bug (Bun build does not import values re-exported from another package whensideEffectsisfalseoven-sh/bun#18008) that emitted an 84-byte stub re-exporting undeclared identifiers — the produceddistcould not be imported. The build now usesbunup(Bun-native library bundler), emitting a working ESM bundle, a.d.ts, and a linked source map.sideEffects: falsewas removed (it provides no benefit for a server-side library and was the bug trigger).Match-time correctness
:paramimmediately followed by a*namestar wildcard now matches an empty tail./:p/*restagainst/xnow returns{ p: 'x', rest: '' }(previouslynull). The compiled match function diverged from the reference walkers on this shape.pathCaseSensitive: false) no longer mutates captured values. Case-folding now applies to route selection only; captured:paramand*wildcardvalues keep their original case (e.g./Users/:id+/USERS/AbC→{ id: 'AbC' }, previously'abc'). Folding is now ASCII-only (length-preserving) instead ofString.toLowerCase(): a captured value containing a length-changing non-ASCII char (e.g.İ, whosetoLowerCase()is two code units) no longer corrupts the capture offsets (/:id/x+/İ/x→{ id: 'İ' }, previously{ id: 'İ/' }). Since URL paths are ASCII (RFC 3986; non-ASCII arrives percent-encoded), ASCII folding is complete./u/AbC,/u/aBc) collapsed to one entry and the second returned the first's captured value. The cache is now keyed on the non-folded (but still trailing-slash-trimmed) path, so each case-variant keeps its own capture while same-path and trailing-slash-variant inputs still cache-hit.:id(\w+)(and\w{1,}) now correctly rejects hyphens, matching the actual\wsemantics.:id(\d+)?builds and matches (/x/42→{ id: '42' },/xabsent,/x/abcno match); previously rejected with a misleadingpath-queryerror.method-invalid-token(RFC 7230/9110 token grammar is ASCII-only); previously accepted.?in a non-param segment is now rejected (/a?→path-query); the?optional decorator is accepted only on param segments.Internal
OptionalParamDefaultsclass,MethodRegistry.get()/size, and the unreachable nullable-value path in the hit cache.maxParamsObserved.Patch Changes
49e9511: Bench audit, lint/format tooling setup, router lint compliance, circular-dep removal. No published API change —
dist/is unaffected; consumers see no behavioral difference.Part 1 — Bench audit & harness fixes (line-by-line + Codex/Explore second-opinion)
Measurement correctness (output was lying)
router.bench.ts: removed non-existentenableCache,ignoreTrailingSlash,caseSensitiveoptions (silently ignored byRouterOptions). The cache-hit vs no-cache and case-insensitive benches were measuring nothing of the kind; sections deleted.fullOptionsRouternow uses the real options (trailingSlash: 'ignore',pathCaseSensitive: false). Static-match 10/100/500/1000 collapsed to a single hash-bucket bench (all four are O(1) static-bucket lookups; the four-row scaling was misleading).100k-verification.ts:100k churnscenario removed — hit/miss paths were fixed strings, defeating the advertised "unique-path churn" intent. Real churn measurement already lives incacheTraversalFeasibility().100k-gate-runner.tsscenarios list updated.complex-shapes.bench.ts:regexshape now skips memoirist withregex: null(was registering a tester-less variant under the "regex (testers)" label — apples-to-oranges vs zipbul). Label corrected from "2 testers" to "3 testers".comparison.bench.ts:missscenario'swrongMethodaxis now hits a registered path; the previous unregistered path collapsed wrong-method into the plain miss axis.regression-snapshot.ts:p99NsPerOpJSON field renamed tomaxNsPerOp. With TRIALS=11 the nearest-rank p99 index lands on the max sample.Statistical honesty
helpers.tspercentile(): docstring warns small-N inputs collapse p75/p99 to max.100k-gate-runner.ts,100k-external-baselines.ts:buildP75/P99collapsed tobuildMax.100k-bun-serve-baseline.ts:warmedP99removed.first-call-latency.ts: replaced localMath.floor(n*0.99)with sharedpercentile().Methodology consistency
100k-external-baselines.ts:find-my-wayadapter uses{ ignoreTrailingSlash: true }matching100k-external-correctness.ts.settleScavenger()called beforemem()baseline.100k-verification.ts: removedcandidateMicrobench()andtryUrlPatternBaseline()(didn't measure zipbul Router).Cross-router fairness — full pair isolation
comparison.bench.ts: 7 adapters × 7 scenarios = 49 fresh-process pairs. Worker takesargv = [adapter, scenarioLabel]. Sanity-gate failures print structured reasons.complex-shapes.bench.ts: 3 routers × 11 shapes = 33 fresh-process pairs with per-shape build functions (no JIT pollution from sibling shapes). Unsupported pairs printskip=true reason=unsupported.Dead-code purge
bench/comparison-solo.bench.ts,bench/baseline/percent-gate.bench.txt.supportsfield,skipForparameter in100k-external-correctness.ts.@hattip/routeranditty-router(referenced only by since-deleted benches).Walker-fallback bench note
walker-fallbacks.bench.ts: header note that the three benches measure each walker on the workload that triggers its selection — route counts and match paths differ, so the timings are per-walker sanity numbers, not cross-walker comparisons.Part 2 — Lint/format/dead-code tooling (toolkit-wide)
Copied from
zipbul/sibling repo for consistency with the broader Zipbul ecosystem standards. All configs at toolkit root (.oxlintrc.jsonc,.oxfmtrc.jsonc,knip.json). Rootpackage.jsonscripts:typecheck,lint,format,format:check,knip,dpdm. devDependencies pinned to versions matching the sibling repo (oxlint@^1.41.0,oxlint-tsgolint@^0.11.1,oxfmt@^0.26.0,knip@^5.63.1,dpdm@^4.2.0).tsconfig stricter (
toolkit/tsconfig.json)noUnusedLocals,noUnusedParameters,noPropertyAccessFromIndexSignatureall enabled (wasfalse). Router passes cleanly.Sensible overrides (
.oxlintrc.jsonc)packages/router/bench/**/*.ts:no-explicit-any,no-loop-func,import/no-dynamic-require,default-caseoff. Adapter testing against 7 external routers with disparate return shapes requires loose typing; per-shapeShapeunion switches use exhaustive type-narrowing that TypeScript verifies.**/*.spec.ts/**/*.test.ts:no-explicit-anyoff (intentionalanyfor type-error coverage);jest/no-conditional-in-testoff (Result-type narrowingif (err.data.kind === 'X')is legitimate TypeScript narrowing, not a test antipattern).Router exports-last refactor (12 files)
All
export function/export interface/export classdeclarations moved to a single bottomexport { ... }/export type { ... }block per file. Files touched:pattern-tester.ts,path-policy.ts,wildcard-method-expand.ts,emitter.ts,prefix-factor.ts,factor-detect.ts,path-parser.ts,route-expand.ts,wildcard-prefix-index.ts,router.ts,pipeline/registration.ts,codegen/segment-compile.ts,tree/segment-tree.ts.Circular dependency removal
Extracted
SegmentNode+ParamSegmentinterfaces fromsrc/tree/segment-tree.tsinto a newsrc/tree/node-types.ts.segment-tree.tsnow imports the types from./node-typesand re-exports them;undo.tsalso imports from./node-types. Eliminates the type-onlysegment-tree → undo → segment-treecycle thatdpdmflagged.Test/spec import dedup
src/builder/path-parser.spec.ts,src/builder/route-expand.spec.ts,src/router.spec.ts: merged duplicate inline imports (one at top, one mid-file) into single top imports — fixesimport/no-duplicatesandimport/first.Format pass
oxfmtapplied to every.ts,.md,.jsonin the monorepo. 204 files reformatted (printWidth 130, trailingComma all, sorted package.json scripts, sorted imports per group).Verification
bunx tsc --noEmit -p packages/router/tsconfig.json— 0 errors.bun test(router-scoped) — 999 pass / 0 fail / 9533 expects.bunx oxlint packages/router— 0 warnings / 0 errors.bunx dpdm packages/router/src/**/*.ts packages/router/index.ts— no circular dependencies.comparison.bench.ts,complex-shapes.bench.ts,cache-cardinality.bench.ts,walker-fallbacks.bench.ts,first-call-latency.ts,regression-snapshot.ts,router.bench.ts,100k-verification.ts,100k-external-correctness.ts.100k-gate-runner.tsregex parser still matches100k-verification.tsoutput format.Known follow-ups (out of router scope)
cors,multipart,rate-limiter,result,query-parserstill have lint violations (53 errors total across those packages). Pre-existing; not addressed in this PR. Tracking separately.knipreports ~11 router exports + 9 router types as unused outside their own file. Most are internal helpers (flushStaticBuffer,emitParamBranch, etc.) — safe to delete or keep as internal-API surface. Decided not to remove now to avoid scope creep.dist/artifacts inpackages/resultandpackages/sharedcause 26 cross-package test failures when runningbun testfrom monorepo root. Unrelated; tracked separately.