@solidjs/router 0.16.0 → 0.17.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +85 -79
  2. package/dist/components.jsx +22 -16
  3. package/dist/data/action.d.ts +12 -10
  4. package/dist/data/action.js +98 -78
  5. package/dist/data/events.d.ts +8 -1
  6. package/dist/data/events.js +3 -3
  7. package/dist/data/index.d.ts +2 -3
  8. package/dist/data/index.js +2 -3
  9. package/dist/data/query.d.ts +1 -3
  10. package/dist/data/query.js +10 -16
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.js +212 -261
  13. package/dist/index.jsx +1 -1
  14. package/dist/lifecycle.js +1 -1
  15. package/dist/routers/HashRouter.js +1 -1
  16. package/dist/routers/MemoryRouter.js +1 -1
  17. package/dist/routers/Router.js +2 -2
  18. package/dist/routers/StaticRouter.js +1 -1
  19. package/dist/routers/components.d.ts +0 -4
  20. package/dist/routers/components.jsx +30 -19
  21. package/dist/routing.d.ts +4 -3
  22. package/dist/routing.js +71 -49
  23. package/dist/types.d.ts +3 -18
  24. package/dist/utils.d.ts +1 -0
  25. package/dist/utils.js +8 -0
  26. package/package.json +8 -6
  27. package/dist/data/createAsync.d.ts +0 -32
  28. package/dist/data/createAsync.js +0 -93
  29. package/dist/src/components.d.ts +0 -31
  30. package/dist/src/components.jsx +0 -39
  31. package/dist/src/data/action.d.ts +0 -17
  32. package/dist/src/data/action.js +0 -163
  33. package/dist/src/data/action.spec.d.ts +0 -1
  34. package/dist/src/data/action.spec.js +0 -297
  35. package/dist/src/data/createAsync.d.ts +0 -32
  36. package/dist/src/data/createAsync.js +0 -96
  37. package/dist/src/data/createAsync.spec.d.ts +0 -1
  38. package/dist/src/data/createAsync.spec.js +0 -196
  39. package/dist/src/data/events.d.ts +0 -9
  40. package/dist/src/data/events.js +0 -123
  41. package/dist/src/data/events.spec.d.ts +0 -1
  42. package/dist/src/data/events.spec.js +0 -567
  43. package/dist/src/data/index.d.ts +0 -4
  44. package/dist/src/data/index.js +0 -4
  45. package/dist/src/data/query.d.ts +0 -23
  46. package/dist/src/data/query.js +0 -232
  47. package/dist/src/data/query.spec.d.ts +0 -1
  48. package/dist/src/data/query.spec.js +0 -354
  49. package/dist/src/data/response.d.ts +0 -4
  50. package/dist/src/data/response.js +0 -42
  51. package/dist/src/data/response.spec.d.ts +0 -1
  52. package/dist/src/data/response.spec.js +0 -165
  53. package/dist/src/index.d.ts +0 -7
  54. package/dist/src/index.jsx +0 -6
  55. package/dist/src/lifecycle.d.ts +0 -5
  56. package/dist/src/lifecycle.js +0 -69
  57. package/dist/src/routers/HashRouter.d.ts +0 -9
  58. package/dist/src/routers/HashRouter.js +0 -41
  59. package/dist/src/routers/MemoryRouter.d.ts +0 -24
  60. package/dist/src/routers/MemoryRouter.js +0 -57
  61. package/dist/src/routers/Router.d.ts +0 -9
  62. package/dist/src/routers/Router.js +0 -45
  63. package/dist/src/routers/StaticRouter.d.ts +0 -6
  64. package/dist/src/routers/StaticRouter.js +0 -15
  65. package/dist/src/routers/components.d.ts +0 -27
  66. package/dist/src/routers/components.jsx +0 -118
  67. package/dist/src/routers/createRouter.d.ts +0 -10
  68. package/dist/src/routers/createRouter.js +0 -41
  69. package/dist/src/routers/index.d.ts +0 -11
  70. package/dist/src/routers/index.js +0 -6
  71. package/dist/src/routing.d.ts +0 -175
  72. package/dist/src/routing.js +0 -560
  73. package/dist/src/types.d.ts +0 -200
  74. package/dist/src/types.js +0 -1
  75. package/dist/src/utils.d.ts +0 -13
  76. package/dist/src/utils.js +0 -185
  77. package/dist/test/helpers.d.ts +0 -6
  78. package/dist/test/helpers.js +0 -50
@@ -1,200 +0,0 @@
1
- import type { Component, JSX, Signal } from "solid-js";
2
- declare module "solid-js/web" {
3
- interface RequestEvent {
4
- response: {
5
- status?: number;
6
- statusText?: string;
7
- headers: Headers;
8
- };
9
- router?: {
10
- matches?: OutputMatch[];
11
- cache?: Map<string, CacheEntry>;
12
- submission?: {
13
- input: any;
14
- result: any;
15
- url: string;
16
- };
17
- dataOnly?: boolean | string[];
18
- data?: Record<string, any>;
19
- previousUrl?: string;
20
- };
21
- serverOnly?: boolean;
22
- }
23
- }
24
- export type Params = Record<string, string | undefined>;
25
- export type SearchParams = Record<string, string | string[] | undefined>;
26
- export type SetParams = Record<string, string | number | boolean | null | undefined>;
27
- export type SetSearchParams = Record<string, string | string[] | number | number[] | boolean | boolean[] | null | undefined>;
28
- export interface Path {
29
- pathname: string;
30
- search: string;
31
- hash: string;
32
- }
33
- export interface Location<S = unknown> extends Path {
34
- query: SearchParams;
35
- state: Readonly<Partial<S>> | null;
36
- key: string;
37
- }
38
- export interface NavigateOptions<S = unknown> {
39
- resolve: boolean;
40
- replace: boolean;
41
- scroll: boolean;
42
- state: S;
43
- }
44
- export interface Navigator {
45
- (to: string | number, options?: Partial<NavigateOptions>): void;
46
- (delta: number): void;
47
- }
48
- export type NavigatorFactory = (route?: RouteContext) => Navigator;
49
- export interface LocationChange<S = unknown> {
50
- value: string;
51
- replace?: boolean;
52
- scroll?: boolean;
53
- state?: S;
54
- rawPath?: string;
55
- }
56
- export interface RouterIntegration {
57
- signal: Signal<LocationChange>;
58
- create?: (router: RouterContext) => void;
59
- utils?: Partial<RouterUtils>;
60
- }
61
- export type Intent = "initial" | "native" | "navigate" | "preload";
62
- export interface RoutePreloadFuncArgs {
63
- params: Params;
64
- location: Location;
65
- intent: Intent;
66
- }
67
- export type RoutePreloadFunc<T = unknown> = (args: RoutePreloadFuncArgs) => T;
68
- export interface RouteSectionProps<T = unknown> {
69
- params: Params;
70
- location: Location;
71
- data: T;
72
- children?: JSX.Element;
73
- }
74
- export type RouteDefinition<S extends string | string[] = any, T = unknown> = {
75
- path?: S;
76
- matchFilters?: MatchFilters<S>;
77
- preload?: RoutePreloadFunc<T>;
78
- children?: RouteDefinition | RouteDefinition[];
79
- component?: Component<RouteSectionProps<T>>;
80
- info?: Record<string, any>;
81
- /** @deprecated use preload */
82
- load?: RoutePreloadFunc;
83
- };
84
- export type MatchFilter = readonly string[] | RegExp | ((s: string) => boolean);
85
- export type PathParams<P extends string | readonly string[]> = P extends `${infer Head}/${infer Tail}` ? [...PathParams<Head>, ...PathParams<Tail>] : P extends `:${infer S}?` ? [S] : P extends `:${infer S}` ? [S] : P extends `*${infer S}` ? [S] : [];
86
- export type MatchFilters<P extends string | readonly string[] = any> = P extends string ? {
87
- [K in PathParams<P>[number]]?: MatchFilter;
88
- } : Record<string, MatchFilter>;
89
- export interface PathMatch {
90
- params: Params;
91
- path: string;
92
- }
93
- export interface RouteMatch extends PathMatch {
94
- route: RouteDescription;
95
- }
96
- export interface OutputMatch {
97
- path: string;
98
- pattern: string;
99
- match: string;
100
- params: Params;
101
- info?: Record<string, any>;
102
- }
103
- export interface RouteDescription {
104
- key: unknown;
105
- originalPath: string;
106
- pattern: string;
107
- component?: Component<RouteSectionProps>;
108
- preload?: RoutePreloadFunc;
109
- matcher: (location: string) => PathMatch | null;
110
- matchFilters?: MatchFilters;
111
- info?: Record<string, any>;
112
- }
113
- export interface Branch {
114
- routes: RouteDescription[];
115
- score: number;
116
- matcher: (location: string) => RouteMatch[] | null;
117
- }
118
- export interface RouteContext {
119
- parent?: RouteContext;
120
- child?: RouteContext;
121
- pattern: string;
122
- path: () => string;
123
- outlet: () => JSX.Element;
124
- resolvePath(to: string): string | undefined;
125
- }
126
- export interface RouterUtils {
127
- renderPath(path: string): string;
128
- parsePath(str: string): string;
129
- go(delta: number): void;
130
- beforeLeave: BeforeLeaveLifecycle;
131
- paramsWrapper: (getParams: () => Params, branches: () => Branch[]) => Params;
132
- queryWrapper: (getQuery: () => SearchParams) => SearchParams;
133
- }
134
- export interface RouterContext {
135
- base: RouteContext;
136
- location: Location;
137
- params: Params;
138
- navigatorFactory: NavigatorFactory;
139
- isRouting: () => boolean;
140
- matches: () => RouteMatch[];
141
- renderPath(path: string): string;
142
- parsePath(str: string): string;
143
- beforeLeave: BeforeLeaveLifecycle;
144
- preloadRoute: (url: URL, preloadData?: boolean) => void;
145
- singleFlight: boolean;
146
- submissions: Signal<Submission<any, any>[]>;
147
- }
148
- export interface BeforeLeaveEventArgs {
149
- from: Location;
150
- to: string | number;
151
- options?: Partial<NavigateOptions>;
152
- readonly defaultPrevented: boolean;
153
- preventDefault(): void;
154
- retry(force?: boolean): void;
155
- }
156
- export interface BeforeLeaveListener {
157
- listener(e: BeforeLeaveEventArgs): void;
158
- location: Location;
159
- navigate: Navigator;
160
- }
161
- export interface BeforeLeaveLifecycle {
162
- subscribe(listener: BeforeLeaveListener): () => void;
163
- confirm(to: string | number, options?: Partial<NavigateOptions>): boolean;
164
- }
165
- export type Submission<T, U> = {
166
- readonly input: T;
167
- readonly result?: U;
168
- readonly error: any;
169
- readonly pending: boolean;
170
- readonly url: string;
171
- clear: () => void;
172
- retry: () => void;
173
- };
174
- export type SubmissionStub = {
175
- readonly input: undefined;
176
- readonly result: undefined;
177
- readonly error: undefined;
178
- readonly pending: undefined;
179
- readonly url: undefined;
180
- clear: () => void;
181
- retry: () => void;
182
- };
183
- export interface MaybePreloadableComponent extends Component {
184
- preload?: () => void;
185
- }
186
- export type CacheEntry = [number, Promise<any>, any, Intent | undefined, Signal<number> & {
187
- count: number;
188
- }];
189
- export type NarrowResponse<T> = T extends CustomResponse<infer U> ? U : Exclude<T, Response>;
190
- export type RouterResponseInit = Omit<ResponseInit, "body"> & {
191
- revalidate?: string | string[];
192
- };
193
- export type CustomResponse<T> = Omit<Response, "clone"> & {
194
- customBody: () => T;
195
- clone(...args: readonly unknown[]): CustomResponse<T>;
196
- };
197
- /** @deprecated */
198
- export type RouteLoadFunc = RoutePreloadFunc;
199
- /** @deprecated */
200
- export type RouteLoadFuncArgs = RoutePreloadFuncArgs;
package/dist/src/types.js DELETED
@@ -1 +0,0 @@
1
- export {};
@@ -1,13 +0,0 @@
1
- import type { MatchFilters, PathMatch, RouteDescription, SearchParams, SetSearchParams } from "./types.js";
2
- export declare const mockBase = "http://sr";
3
- export declare function normalizePath(path: string, omitSlash?: boolean): string;
4
- export declare function resolvePath(base: string, path: string, from?: string): string | undefined;
5
- export declare function invariant<T>(value: T | null | undefined, message: string): T;
6
- export declare function joinPaths(from: string, to: string): string;
7
- export declare function extractSearchParams(url: URL): SearchParams;
8
- export declare function createMatcher<S extends string>(path: S, partial?: boolean, matchFilters?: MatchFilters<S>): (location: string) => PathMatch | null;
9
- export declare function scoreRoute(route: RouteDescription): number;
10
- export declare function createMemoObject<T extends Record<string | symbol, unknown>>(fn: () => T): T;
11
- export declare function mergeSearchString(search: string, params: SetSearchParams): string;
12
- export declare function expandOptionals(pattern: string): string[];
13
- export declare function setFunctionName<T>(obj: T, value: string): T;
package/dist/src/utils.js DELETED
@@ -1,185 +0,0 @@
1
- import { createMemo, getOwner, runWithOwner } from "solid-js";
2
- const hasSchemeRegex = /^(?:[a-z0-9]+:)?\/\//i;
3
- const trimPathRegex = /^\/+|(\/)\/+$/g;
4
- export const mockBase = "http://sr";
5
- export function normalizePath(path, omitSlash = false) {
6
- const s = path.replace(trimPathRegex, "$1");
7
- return s ? (omitSlash || /^[?#]/.test(s) ? s : "/" + s) : "";
8
- }
9
- export function resolvePath(base, path, from) {
10
- if (hasSchemeRegex.test(path)) {
11
- return undefined;
12
- }
13
- const basePath = normalizePath(base);
14
- const fromPath = from && normalizePath(from);
15
- let result = "";
16
- if (!fromPath || path.startsWith("/")) {
17
- result = basePath;
18
- }
19
- else if (fromPath.toLowerCase().indexOf(basePath.toLowerCase()) !== 0) {
20
- result = basePath + fromPath;
21
- }
22
- else {
23
- result = fromPath;
24
- }
25
- return (result || "/") + normalizePath(path, !result);
26
- }
27
- export function invariant(value, message) {
28
- if (value == null) {
29
- throw new Error(message);
30
- }
31
- return value;
32
- }
33
- export function joinPaths(from, to) {
34
- return normalizePath(from).replace(/\/*(\*.*)?$/g, "") + normalizePath(to);
35
- }
36
- export function extractSearchParams(url) {
37
- const params = {};
38
- url.searchParams.forEach((value, key) => {
39
- if (key in params) {
40
- if (Array.isArray(params[key]))
41
- params[key].push(value);
42
- else
43
- params[key] = [params[key], value];
44
- }
45
- else
46
- params[key] = value;
47
- });
48
- return params;
49
- }
50
- export function createMatcher(path, partial, matchFilters) {
51
- const [pattern, splat] = path.split("/*", 2);
52
- const segments = pattern.split("/").filter(Boolean);
53
- const len = segments.length;
54
- return (location) => {
55
- const locSegments = location.split("/").filter(Boolean);
56
- const lenDiff = locSegments.length - len;
57
- if (lenDiff < 0 || (lenDiff > 0 && splat === undefined && !partial)) {
58
- return null;
59
- }
60
- const match = {
61
- path: len ? "" : "/",
62
- params: {}
63
- };
64
- const matchFilter = (s) => matchFilters === undefined ? undefined : matchFilters[s];
65
- for (let i = 0; i < len; i++) {
66
- const segment = segments[i];
67
- const dynamic = segment[0] === ":";
68
- const locSegment = dynamic ? locSegments[i] : locSegments[i].toLowerCase();
69
- const key = dynamic ? segment.slice(1) : segment.toLowerCase();
70
- if (dynamic && matchSegment(locSegment, matchFilter(key))) {
71
- match.params[key] = locSegment;
72
- }
73
- else if (dynamic || !matchSegment(locSegment, key)) {
74
- return null;
75
- }
76
- match.path += `/${locSegment}`;
77
- }
78
- if (splat) {
79
- const remainder = lenDiff ? locSegments.slice(-lenDiff).join("/") : "";
80
- if (matchSegment(remainder, matchFilter(splat))) {
81
- match.params[splat] = remainder;
82
- }
83
- else {
84
- return null;
85
- }
86
- }
87
- return match;
88
- };
89
- }
90
- function matchSegment(input, filter) {
91
- const isEqual = (s) => s === input;
92
- if (filter === undefined) {
93
- return true;
94
- }
95
- else if (typeof filter === "string") {
96
- return isEqual(filter);
97
- }
98
- else if (typeof filter === "function") {
99
- return filter(input);
100
- }
101
- else if (Array.isArray(filter)) {
102
- return filter.some(isEqual);
103
- }
104
- else if (filter instanceof RegExp) {
105
- return filter.test(input);
106
- }
107
- return false;
108
- }
109
- export function scoreRoute(route) {
110
- const [pattern, splat] = route.pattern.split("/*", 2);
111
- const segments = pattern.split("/").filter(Boolean);
112
- return segments.reduce((score, segment) => score + (segment.startsWith(":") ? 2 : 3), segments.length - (splat === undefined ? 0 : 1));
113
- }
114
- export function createMemoObject(fn) {
115
- const map = new Map();
116
- const owner = getOwner();
117
- return new Proxy({}, {
118
- get(_, property) {
119
- if (!map.has(property)) {
120
- runWithOwner(owner, () => map.set(property, createMemo(() => fn()[property])));
121
- }
122
- return map.get(property)();
123
- },
124
- getOwnPropertyDescriptor() {
125
- return {
126
- enumerable: true,
127
- configurable: true
128
- };
129
- },
130
- ownKeys() {
131
- return Reflect.ownKeys(fn());
132
- },
133
- has(_, property) {
134
- return property in fn();
135
- }
136
- });
137
- }
138
- export function mergeSearchString(search, params) {
139
- const merged = new URLSearchParams(search);
140
- Object.entries(params).forEach(([key, value]) => {
141
- if (value == null || value === "" || (value instanceof Array && !value.length)) {
142
- merged.delete(key);
143
- }
144
- else {
145
- if (value instanceof Array) {
146
- // Delete all instances of the key before appending
147
- merged.delete(key);
148
- value.forEach(v => {
149
- merged.append(key, String(v));
150
- });
151
- }
152
- else {
153
- merged.set(key, String(value));
154
- }
155
- }
156
- });
157
- const s = merged.toString();
158
- return s ? `?${s}` : "";
159
- }
160
- export function expandOptionals(pattern) {
161
- let match = /(\/?\:[^\/]+)\?/.exec(pattern);
162
- if (!match)
163
- return [pattern];
164
- let prefix = pattern.slice(0, match.index);
165
- let suffix = pattern.slice(match.index + match[0].length);
166
- const prefixes = [prefix, (prefix += match[1])];
167
- // This section handles adjacent optional params. We don't actually want all permuations since
168
- // that will lead to equivalent routes which have the same number of params. For example
169
- // `/:a?/:b?/:c`? only has the unique expansion: `/`, `/:a`, `/:a/:b`, `/:a/:b/:c` and we can
170
- // discard `/:b`, `/:c`, `/:b/:c` by building them up in order and not recursing. This also helps
171
- // ensure predictability where earlier params have precidence.
172
- while ((match = /^(\/\:[^\/]+)\?/.exec(suffix))) {
173
- prefixes.push((prefix += match[1]));
174
- suffix = suffix.slice(match[0].length);
175
- }
176
- return expandOptionals(suffix).reduce((results, expansion) => [...results, ...prefixes.map(p => p + expansion)], []);
177
- }
178
- export function setFunctionName(obj, value) {
179
- Object.defineProperty(obj, "name", {
180
- value,
181
- writable: false,
182
- configurable: false
183
- });
184
- return obj;
185
- }
@@ -1,6 +0,0 @@
1
- import { RouterContext } from "../src/types.js";
2
- export declare function createCounter(fn: () => void, start?: number): import("solid-js").Accessor<number>;
3
- export declare function waitFor(fn: () => boolean): Promise<number>;
4
- export declare function createAsyncRoot(fn: (resolve: () => void, disposer: () => void) => void): Promise<void>;
5
- export declare function createMockRouter(): RouterContext;
6
- export declare function awaitPromise(): Promise<unknown>;
@@ -1,50 +0,0 @@
1
- import { createEffect, createMemo, createRoot, createSignal } from "solid-js";
2
- import { vi } from "vitest";
3
- export function createCounter(fn, start = -1) {
4
- return createMemo((n) => {
5
- fn();
6
- return n + 1;
7
- }, start);
8
- }
9
- export function waitFor(fn) {
10
- return new Promise(resolve => {
11
- createEffect((n = 0) => {
12
- if (fn()) {
13
- resolve(n);
14
- }
15
- return n + 1;
16
- });
17
- });
18
- }
19
- export function createAsyncRoot(fn) {
20
- return new Promise(resolve => {
21
- createRoot(disposer => fn(resolve, disposer));
22
- });
23
- }
24
- export function createMockRouter() {
25
- const [submissions, setSubmissions] = createSignal([]);
26
- const [singleFlight] = createSignal(false);
27
- return {
28
- submissions: [submissions, setSubmissions],
29
- singleFlight: singleFlight(),
30
- navigatorFactory: () => vi.fn(),
31
- base: { path: () => "/" },
32
- location: { pathname: "/", search: "", hash: "", query: {}, state: null, key: "" },
33
- isRouting: () => false,
34
- matches: () => [],
35
- navigate: vi.fn(),
36
- navigateFromRoute: vi.fn(),
37
- parsePath: (path) => path,
38
- preloadRoute: vi.fn(),
39
- renderPath: (path) => path,
40
- utils: {
41
- go: vi.fn(),
42
- renderPath: vi.fn(),
43
- parsePath: vi.fn(),
44
- beforeLeave: { listeners: new Set() }
45
- }
46
- };
47
- }
48
- export async function awaitPromise() {
49
- return new Promise(resolve => setTimeout(resolve, 100));
50
- }