Skip to content

Commit e140da3

Browse files
committed
feat(RouterEngine)!: Rename noMatches to fallback and make resolvedHash public
BREAKING CHANGE
1 parent ebb5f0d commit e140da3

File tree

6 files changed

+32
-32
lines changed

6 files changed

+32
-32
lines changed

AGENTS.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ Where `RouteInfo` contains:
5252

5353
#### Reactive Properties
5454
- `routeStatus`: Per-route match status and extracted parameters
55-
- `noMatches`: Boolean indicating NO routes matched (excluding `ignoreForFallback` routes)
55+
- `fallback`: Boolean indicating NO routes matched (excluding `ignoreForFallback` routes)
5656

5757
### Component Architecture
5858

@@ -72,12 +72,12 @@ universe they belong to.
7272
#### Fallback Component
7373
- Shows content when no routes match
7474
- Props:
75-
- `when?: WhenPredicate`: Override default `noMatches` behavior
75+
- `when?: WhenPredicate`: Override default `fallback` behavior
7676
- `children`: Content snippet
7777

7878
Render logic:
7979
```svelte
80-
{#if (router && when?.(router.routeStatus, router.noMatches)) || (!when && router?.noMatches)}
80+
{#if (router && when?.(router.routeStatus, router.fallback)) || (!when && router?.fallback)}
8181
{@render children?.(router.state, router.routeStatus)}
8282
{/if}
8383
```
@@ -224,8 +224,8 @@ test("Should hide content when routes match.", () => {
224224
});
225225

226226
// ❌ Bad - Test internal implementation
227-
test("Should call router.noMatches.", () => {
228-
const spy = vi.spyOn(router, 'noMatches');
227+
test("Should call router.fallback.", () => {
228+
const spy = vi.spyOn(router, 'fallback');
229229
render(Component, { props, context });
230230
expect(spy).toHaveBeenCalled(); // Testing implementation detail
231231
});
@@ -240,7 +240,7 @@ test("Component renders when condition is met.", () => {
240240
});
241241

242242
// ✅ Router tests focus on router logic (separate file)
243-
test("Router calculates noMatches correctly.", () => {
243+
test("Router calculates fallback correctly.", () => {
244244
// Test router's internal logic
245245
});
246246
```
@@ -691,7 +691,7 @@ test("Should react to state changes.", () => {
691691
**Purpose**: Render content when no routes match, with override capability
692692

693693
**Key behaviors to test**:
694-
1. Shows when `router.noMatches` is true
694+
1. Shows when `router.fallback` is true
695695
2. Hides when routes are matching
696696
3. Respects `when` predicate override
697697
4. Works across all routing universes

src/lib/Fallback/Fallback.svelte

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@
5353
/**
5454
* Renders the children of the component.
5555
*
56-
* This rendering is conditioned to the parent router engine's `noMatches` property being `true`. This means
57-
* that the children will only be rendered when no route matches the current location.
56+
* This rendering is conditioned to the parent router engine's `fallback` property being `true`. This means
57+
* that the children will only be rendered when no routes match the current location.
5858
* @param context The component's context available to children.
5959
*/
6060
children?: Snippet<[RouterChildrenContext]>;
@@ -68,6 +68,6 @@
6868
const router = getRouterContext(resolvedHash);
6969
</script>
7070

71-
{#if (router && when?.(router.routeStatus, router.noMatches)) || (!when && router?.noMatches)}
71+
{#if (router && when?.(router.routeStatus, router.fallback)) || (!when && router?.fallback)}
7272
{@render children?.({ state: router.state, rs: router.routeStatus })}
7373
{/if}

src/lib/Fallback/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
The `Fallback` component can be thought about as a `Route` component that only render its children if there are no
44
other routes in the parent router engine that match.
55

6-
Internally, it checks the parent router engine's `noMatches` value, which is a reactive value calculated when all other
6+
Internally, it checks the parent router engine's `fallback` value, which is a reactive value calculated when all other
77
route status data is calculated.
88

99
## Props

src/lib/kernel/RouterEngine.svelte.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -666,13 +666,13 @@ ROUTING_UNIVERSES.forEach(universe => {
666666
});
667667
});
668668

669-
describe('noMatches', () => {
669+
describe('fallback', () => {
670670
test("Should be true whenever there are no routes registered.", () => {
671671
// Act.
672672
const router = new RouterEngine({ hash: universe.hash });
673673

674674
// Assert.
675-
expect(router.noMatches).toBe(true);
675+
expect(router.fallback).toBe(true);
676676
});
677677

678678
test("Should be true whenever there are no matching routes.", () => {
@@ -686,7 +686,7 @@ ROUTING_UNIVERSES.forEach(universe => {
686686
};
687687

688688
// Assert.
689-
expect(router.noMatches).toBe(true);
689+
expect(router.fallback).toBe(true);
690690
});
691691

692692
test.each([
@@ -714,7 +714,7 @@ ROUTING_UNIVERSES.forEach(universe => {
714714
addRoutes(router, { matching: routeCount, nonMatching: nonMatchingCount });
715715

716716
// Assert.
717-
expect(router.noMatches).toBe(false);
717+
expect(router.fallback).toBe(false);
718718
});
719719

720720
test.each([
@@ -732,7 +732,7 @@ ROUTING_UNIVERSES.forEach(universe => {
732732
});
733733

734734
// Assert.
735-
expect(router.noMatches).toBe(true);
735+
expect(router.fallback).toBe(true);
736736
});
737737
});
738738
});

src/lib/kernel/RouterEngine.svelte.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export class RouterEngine {
4747
#routeHelper;
4848
#cleanup = false;
4949
#parent: RouterEngine | undefined;
50-
#resolvedHash: Hash;
50+
resolvedHash: Hash;
5151
/**
5252
* Gets or sets the router's identifier. This is displayed by the `RouterTracer` component.
5353
*/
@@ -86,17 +86,17 @@ export class RouterEngine {
8686

8787
#routeStatusData = $derived.by(() => {
8888
const routeStatus = {} as Record<string, RouteStatus>;
89-
let noMatches = true;
89+
let fallback = true;
9090
for (let routeKey of Object.keys(this.routes)) {
9191
const pattern = this.#routePatterns.get(routeKey)!;
9292
const [match, routeParams] = this.#routeHelper.testRoute(pattern);
93-
noMatches = noMatches && (pattern.ignoreForFallback ? true : !match);
93+
fallback = fallback && (pattern.ignoreForFallback ? true : !match);
9494
routeStatus[routeKey] = {
9595
match,
9696
routeParams,
9797
};
9898
}
99-
return [routeStatus, noMatches] as const;
99+
return [routeStatus, fallback] as const;
100100
});
101101
/**
102102
* Gets a a record of route statuses where the keys are the route keys, and the values are
@@ -105,9 +105,9 @@ export class RouterEngine {
105105
routeStatus = $derived(this.#routeStatusData[0]);
106106
/**
107107
* Gets a boolean value that indicates whether the current URL matches none of the route
108-
* patterns.
108+
* patterns, therefore enabling fallback behavior.
109109
*/
110-
noMatches = $derived(this.#routeStatusData[1]);
110+
fallback = $derived(this.#routeStatusData[1]);
111111
/**
112112
* Initializes a new instance of this class with the specified options.
113113
*/
@@ -121,24 +121,24 @@ export class RouterEngine {
121121
throw new Error("The routing library hasn't been initialized. Execute init() before creating routers.");
122122
}
123123
if (isRouterEngine(parentOrOpts)) {
124-
this.#resolvedHash = parentOrOpts.#resolvedHash;
124+
this.resolvedHash = parentOrOpts.resolvedHash;
125125
this.#parent = parentOrOpts;
126126
}
127127
else {
128128
this.#parent = parentOrOpts?.parent;
129-
this.#resolvedHash = this.#parent && parentOrOpts?.hash === undefined ? this.#parent.#resolvedHash : resolveHashValue(parentOrOpts?.hash);
130-
if (this.#parent && this.#resolvedHash !== this.#parent.#resolvedHash) {
129+
this.resolvedHash = this.#parent && parentOrOpts?.hash === undefined ? this.#parent.resolvedHash : resolveHashValue(parentOrOpts?.hash);
130+
if (this.#parent && this.resolvedHash !== this.#parent.resolvedHash) {
131131
throw new Error("The parent router's hash mode must match the child router's hash mode.");
132132
}
133-
if (routingOptions.hashMode === 'multi' && this.#resolvedHash && typeof this.#resolvedHash !== 'string') {
133+
if (routingOptions.hashMode === 'multi' && this.resolvedHash && typeof this.resolvedHash !== 'string') {
134134
throw new Error("The specified hash value is not valid for the 'multi' hash mode. Either don't specify a hash for path routing, or correct the hash value.");
135135
}
136-
if (routingOptions.hashMode !== 'multi' && typeof this.#resolvedHash === 'string') {
136+
if (routingOptions.hashMode !== 'multi' && typeof this.resolvedHash === 'string') {
137137
throw new Error("A hash path ID was given, but is only allowed when the library's hash mode has been set to 'multi'.");
138138
}
139139
}
140-
assertAllowedRoutingMode(this.#resolvedHash);
141-
this.#routeHelper = new RouteHelper(this.#resolvedHash);
140+
assertAllowedRoutingMode(this.resolvedHash);
141+
this.#routeHelper = new RouteHelper(this.resolvedHash);
142142
if (traceOptions.routerHierarchy) {
143143
registerRouter(this);
144144
this.#cleanup = true;
@@ -158,7 +158,7 @@ export class RouterEngine {
158158
* This is a shortcut for `location.state`.
159159
*/
160160
get state() {
161-
return location.getState(this.#resolvedHash);
161+
return location.getState(this.resolvedHash);
162162
}
163163
/**
164164
* Gets or sets the router's base path.

src/lib/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -428,10 +428,10 @@ export type ActiveState = {
428428
* Defines the type of function accepted by the `Fallback` component via its `when` property.
429429
*
430430
* @param routeStatus The current route status data from the parent router.
431-
* @param noMatches The value that the parent router has calculated as per standard fallback logic.
431+
* @param fallback The value that the parent router has calculated as per standard fallback logic.
432432
* @returns `true` if the fallback content should be shown; `false` to prevent content from being shown.
433433
*/
434-
export type WhenPredicate = (routeStatus: Record<string, RouteStatus>, noMatches: boolean) => boolean;
434+
export type WhenPredicate = (routeStatus: Record<string, RouteStatus>, fallback: boolean) => boolean;
435435

436436
/**
437437
* Defines the shape of logger objects that can be given to this library during initialization.

0 commit comments

Comments
 (0)