reactive-route 0.0.1-alpha.0 → 0.0.1-alpha.1
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.
- package/dist/cjs/index.js +218 -41
- package/dist/esm/index.js +218 -41
- package/dist/types/core/index.d.ts +1 -0
- package/dist/types/core/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var core_exports = {};
|
|
32
32
|
__export(core_exports, {
|
|
33
33
|
createRouterConfig: () => createRouterConfig,
|
|
34
|
+
createRouterStore: () => createRouterStore,
|
|
34
35
|
findRouteByPathname: () => findRouteByPathname,
|
|
35
36
|
getInitialRoute: () => getInitialRoute,
|
|
36
37
|
history: () => history,
|
|
@@ -53,6 +54,9 @@ function createRouterConfig(config) {
|
|
|
53
54
|
return addNames(config);
|
|
54
55
|
}
|
|
55
56
|
|
|
57
|
+
// packages/core/createRouterStore.ts
|
|
58
|
+
var import_query_string2 = __toESM(require("query-string"));
|
|
59
|
+
|
|
56
60
|
// packages/core/utils/constants.ts
|
|
57
61
|
var constants = {
|
|
58
62
|
dynamicSeparator: ":",
|
|
@@ -73,37 +77,6 @@ function isDynamicRoute(route) {
|
|
|
73
77
|
return "params" in route;
|
|
74
78
|
}
|
|
75
79
|
|
|
76
|
-
// packages/core/utils/findRouteByPathname.ts
|
|
77
|
-
function completeStaticMatch(pathname, path) {
|
|
78
|
-
return !path.includes(constants.dynamicSeparator) && (pathname === path || pathname === `${path}${constants.pathPartSeparator}`);
|
|
79
|
-
}
|
|
80
|
-
function findRouteByPathname({
|
|
81
|
-
pathname,
|
|
82
|
-
routes
|
|
83
|
-
}) {
|
|
84
|
-
let dynamicRouteMatch;
|
|
85
|
-
const pathnameArray = pathname.replace(/\?.+$/, "").split(constants.pathPartSeparator).filter(Boolean);
|
|
86
|
-
for (const routeName in routes) {
|
|
87
|
-
if (!Object.hasOwn(routes, routeName)) continue;
|
|
88
|
-
const route = routes[routeName];
|
|
89
|
-
if (completeStaticMatch(pathname, route.path)) return route;
|
|
90
|
-
if (dynamicRouteMatch) continue;
|
|
91
|
-
const routePathnameArray = route.path.split(constants.pathPartSeparator).filter(Boolean);
|
|
92
|
-
if (routePathnameArray.length !== pathnameArray.length) continue;
|
|
93
|
-
const someParamInvalid = routePathnameArray.some((paramName, i) => {
|
|
94
|
-
const paramFromUrl = pathnameArray[i];
|
|
95
|
-
if (!isDynamic(paramName)) return paramName !== paramFromUrl;
|
|
96
|
-
const validator = route.params?.[clearDynamic(paramName)];
|
|
97
|
-
if (typeof validator !== "function") {
|
|
98
|
-
throw new Error(`findRoute: missing validator for param "${paramName}"`);
|
|
99
|
-
}
|
|
100
|
-
return !validator(paramFromUrl);
|
|
101
|
-
});
|
|
102
|
-
if (!someParamInvalid) dynamicRouteMatch = route;
|
|
103
|
-
}
|
|
104
|
-
return dynamicRouteMatch;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
80
|
// packages/core/utils/getDynamicValues.ts
|
|
108
81
|
function getDynamicValues(params) {
|
|
109
82
|
const { route, pathname } = params;
|
|
@@ -138,16 +111,6 @@ function getQueryValues(params) {
|
|
|
138
111
|
return query;
|
|
139
112
|
}
|
|
140
113
|
|
|
141
|
-
// packages/core/utils/getInitialRoute.ts
|
|
142
|
-
function getInitialRoute(params) {
|
|
143
|
-
const route = findRouteByPathname({ pathname: params.pathname, routes: params.routes }) || params.routes[params.fallback];
|
|
144
|
-
return {
|
|
145
|
-
route: route.name,
|
|
146
|
-
query: getQueryValues({ route, pathname: params.pathname }),
|
|
147
|
-
params: getDynamicValues({ route, pathname: params.pathname })
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
114
|
// packages/core/utils/history.ts
|
|
152
115
|
var import_history = require("history");
|
|
153
116
|
var history = constants.isClient ? (0, import_history.createBrowserHistory)() : null;
|
|
@@ -184,3 +147,217 @@ function replaceDynamicValues({
|
|
|
184
147
|
return encodeURIComponent(value);
|
|
185
148
|
});
|
|
186
149
|
}
|
|
150
|
+
|
|
151
|
+
// packages/core/createRouterStore.ts
|
|
152
|
+
function createRouterStore({
|
|
153
|
+
batch,
|
|
154
|
+
routes,
|
|
155
|
+
routeError500,
|
|
156
|
+
makeObservable,
|
|
157
|
+
lifecycleParams,
|
|
158
|
+
replaceObject
|
|
159
|
+
}) {
|
|
160
|
+
const routerStore = makeObservable({
|
|
161
|
+
routesHistory: [],
|
|
162
|
+
currentRoute: {},
|
|
163
|
+
isRedirecting: false,
|
|
164
|
+
redirectTo: void 0
|
|
165
|
+
});
|
|
166
|
+
routerStore.redirectTo = async function redirectTo(config) {
|
|
167
|
+
const { route: routeName, noHistoryPush, asClient } = config;
|
|
168
|
+
const isClient = typeof asClient === "boolean" ? asClient : constants.isClient;
|
|
169
|
+
let currentRoute;
|
|
170
|
+
let currentPathname;
|
|
171
|
+
let currentUrl;
|
|
172
|
+
let currentSearch;
|
|
173
|
+
let currentQuery;
|
|
174
|
+
if (routerStore.currentRoute?.name) {
|
|
175
|
+
currentRoute = routes[routerStore.currentRoute.name];
|
|
176
|
+
currentPathname = replaceDynamicValues({
|
|
177
|
+
route: currentRoute,
|
|
178
|
+
params: routerStore.currentRoute.params
|
|
179
|
+
});
|
|
180
|
+
currentUrl = import_query_string2.default.stringifyUrl({
|
|
181
|
+
url: currentPathname,
|
|
182
|
+
query: routerStore.currentRoute.query
|
|
183
|
+
});
|
|
184
|
+
currentQuery = routerStore.currentRoute.query;
|
|
185
|
+
currentSearch = import_query_string2.default.stringify(routerStore.currentRoute.query);
|
|
186
|
+
}
|
|
187
|
+
const nextRoute = routes[routeName];
|
|
188
|
+
const nextPathname = replaceDynamicValues({
|
|
189
|
+
route: nextRoute,
|
|
190
|
+
params: "params" in config ? config.params : void 0
|
|
191
|
+
});
|
|
192
|
+
let nextQuery;
|
|
193
|
+
let nextUrl = nextPathname;
|
|
194
|
+
let nextSearch;
|
|
195
|
+
if ("query" in config && config.query) {
|
|
196
|
+
const clearedQuery = getQueryValues({
|
|
197
|
+
route: nextRoute,
|
|
198
|
+
pathname: `${nextPathname}?${import_query_string2.default.stringify(config.query)}`
|
|
199
|
+
});
|
|
200
|
+
if (Object.keys(clearedQuery).length > 0) {
|
|
201
|
+
nextQuery = clearedQuery;
|
|
202
|
+
nextSearch = import_query_string2.default.stringify(clearedQuery);
|
|
203
|
+
nextUrl = import_query_string2.default.stringifyUrl({ url: nextPathname, query: clearedQuery });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (currentUrl === nextUrl) return Promise.resolve();
|
|
207
|
+
if (currentPathname === nextPathname) {
|
|
208
|
+
if (currentSearch !== nextSearch) {
|
|
209
|
+
batch(() => {
|
|
210
|
+
replaceObject(routerStore.currentRoute.query, nextQuery || {});
|
|
211
|
+
routerStore.routesHistory.push(nextUrl);
|
|
212
|
+
});
|
|
213
|
+
if (history && !noHistoryPush) {
|
|
214
|
+
history.push({
|
|
215
|
+
hash: history.location.hash,
|
|
216
|
+
search: nextSearch,
|
|
217
|
+
pathname: nextPathname
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return Promise.resolve();
|
|
222
|
+
}
|
|
223
|
+
batch(() => {
|
|
224
|
+
routerStore.isRedirecting = true;
|
|
225
|
+
});
|
|
226
|
+
try {
|
|
227
|
+
await currentRoute?.beforeLeave?.(
|
|
228
|
+
{
|
|
229
|
+
nextUrl,
|
|
230
|
+
nextRoute,
|
|
231
|
+
nextQuery,
|
|
232
|
+
nextSearch,
|
|
233
|
+
nextPathname,
|
|
234
|
+
currentUrl,
|
|
235
|
+
currentQuery,
|
|
236
|
+
currentRoute,
|
|
237
|
+
currentSearch,
|
|
238
|
+
currentPathname
|
|
239
|
+
},
|
|
240
|
+
...lifecycleParams || []
|
|
241
|
+
);
|
|
242
|
+
const redirectConfig = await nextRoute.beforeEnter?.(
|
|
243
|
+
{
|
|
244
|
+
nextUrl,
|
|
245
|
+
nextRoute,
|
|
246
|
+
nextQuery,
|
|
247
|
+
nextSearch,
|
|
248
|
+
nextPathname,
|
|
249
|
+
currentUrl,
|
|
250
|
+
currentQuery,
|
|
251
|
+
currentRoute,
|
|
252
|
+
currentSearch,
|
|
253
|
+
currentPathname
|
|
254
|
+
},
|
|
255
|
+
...lifecycleParams || []
|
|
256
|
+
);
|
|
257
|
+
if (typeof redirectConfig === "object") {
|
|
258
|
+
if (isClient) return redirectTo({ ...redirectConfig, asClient });
|
|
259
|
+
const redirectRoute = routes[redirectConfig.route];
|
|
260
|
+
const redirectParams = "params" in redirectConfig && redirectConfig.params ? redirectConfig.params : void 0;
|
|
261
|
+
let redirectUrl = replaceDynamicValues({
|
|
262
|
+
params: redirectParams,
|
|
263
|
+
route: redirectRoute
|
|
264
|
+
});
|
|
265
|
+
if ("query" in redirectConfig && redirectConfig.query) {
|
|
266
|
+
const clearedQuery = getQueryValues({
|
|
267
|
+
route: nextRoute,
|
|
268
|
+
pathname: `${nextPathname}?${import_query_string2.default.stringify(redirectConfig.query)}`
|
|
269
|
+
});
|
|
270
|
+
if (Object.keys(clearedQuery).length > 0) {
|
|
271
|
+
redirectUrl = import_query_string2.default.stringifyUrl({ url: redirectUrl, query: clearedQuery });
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
throw Object.assign(new Error(redirectUrl), { name: constants.errorRedirect });
|
|
275
|
+
}
|
|
276
|
+
await loadComponentToConfig({ route: routes[nextRoute.name] });
|
|
277
|
+
} catch (error) {
|
|
278
|
+
if (error?.name === constants.errorPrevent) return Promise.resolve();
|
|
279
|
+
if (error?.name === constants.errorRedirect) {
|
|
280
|
+
throw error;
|
|
281
|
+
}
|
|
282
|
+
console.error(error);
|
|
283
|
+
await loadComponentToConfig({ route: routeError500 });
|
|
284
|
+
batch(() => {
|
|
285
|
+
replaceObject(routerStore.currentRoute, {
|
|
286
|
+
name: routeError500.name,
|
|
287
|
+
path: routeError500.path,
|
|
288
|
+
props: routes[routeError500.name].props,
|
|
289
|
+
query: {},
|
|
290
|
+
params: {},
|
|
291
|
+
pageName: routes[routeError500.name].pageName
|
|
292
|
+
});
|
|
293
|
+
routerStore.isRedirecting = false;
|
|
294
|
+
});
|
|
295
|
+
return Promise.resolve();
|
|
296
|
+
}
|
|
297
|
+
batch(() => {
|
|
298
|
+
replaceObject(routerStore.currentRoute, {
|
|
299
|
+
name: nextRoute.name,
|
|
300
|
+
path: nextRoute.path,
|
|
301
|
+
props: routes[nextRoute.name].props,
|
|
302
|
+
query: getQueryValues({ route: nextRoute, pathname: nextUrl }),
|
|
303
|
+
params: getDynamicValues({ route: nextRoute, pathname: nextUrl }),
|
|
304
|
+
pageName: routes[nextRoute.name].pageName
|
|
305
|
+
});
|
|
306
|
+
const lastUrl = routerStore.routesHistory[routerStore.routesHistory.length - 1];
|
|
307
|
+
if (lastUrl !== nextUrl) {
|
|
308
|
+
routerStore.routesHistory.push(nextUrl);
|
|
309
|
+
}
|
|
310
|
+
if (history && !noHistoryPush) {
|
|
311
|
+
history.push({
|
|
312
|
+
hash: history.location.hash,
|
|
313
|
+
search: "query" in config ? `?${import_query_string2.default.stringify(config.query)}` : "",
|
|
314
|
+
pathname: nextPathname
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
routerStore.isRedirecting = false;
|
|
318
|
+
});
|
|
319
|
+
return Promise.resolve();
|
|
320
|
+
};
|
|
321
|
+
return routerStore;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// packages/core/utils/findRouteByPathname.ts
|
|
325
|
+
function completeStaticMatch(pathname, path) {
|
|
326
|
+
return !path.includes(constants.dynamicSeparator) && (pathname === path || pathname === `${path}${constants.pathPartSeparator}`);
|
|
327
|
+
}
|
|
328
|
+
function findRouteByPathname({
|
|
329
|
+
pathname,
|
|
330
|
+
routes
|
|
331
|
+
}) {
|
|
332
|
+
let dynamicRouteMatch;
|
|
333
|
+
const pathnameArray = pathname.replace(/\?.+$/, "").split(constants.pathPartSeparator).filter(Boolean);
|
|
334
|
+
for (const routeName in routes) {
|
|
335
|
+
if (!Object.hasOwn(routes, routeName)) continue;
|
|
336
|
+
const route = routes[routeName];
|
|
337
|
+
if (completeStaticMatch(pathname, route.path)) return route;
|
|
338
|
+
if (dynamicRouteMatch) continue;
|
|
339
|
+
const routePathnameArray = route.path.split(constants.pathPartSeparator).filter(Boolean);
|
|
340
|
+
if (routePathnameArray.length !== pathnameArray.length) continue;
|
|
341
|
+
const someParamInvalid = routePathnameArray.some((paramName, i) => {
|
|
342
|
+
const paramFromUrl = pathnameArray[i];
|
|
343
|
+
if (!isDynamic(paramName)) return paramName !== paramFromUrl;
|
|
344
|
+
const validator = route.params?.[clearDynamic(paramName)];
|
|
345
|
+
if (typeof validator !== "function") {
|
|
346
|
+
throw new Error(`findRoute: missing validator for param "${paramName}"`);
|
|
347
|
+
}
|
|
348
|
+
return !validator(paramFromUrl);
|
|
349
|
+
});
|
|
350
|
+
if (!someParamInvalid) dynamicRouteMatch = route;
|
|
351
|
+
}
|
|
352
|
+
return dynamicRouteMatch;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// packages/core/utils/getInitialRoute.ts
|
|
356
|
+
function getInitialRoute(params) {
|
|
357
|
+
const route = findRouteByPathname({ pathname: params.pathname, routes: params.routes }) || params.routes[params.fallback];
|
|
358
|
+
return {
|
|
359
|
+
route: route.name,
|
|
360
|
+
query: getQueryValues({ route, pathname: params.pathname }),
|
|
361
|
+
params: getDynamicValues({ route, pathname: params.pathname })
|
|
362
|
+
};
|
|
363
|
+
}
|
package/dist/esm/index.js
CHANGED
|
@@ -11,6 +11,9 @@ function createRouterConfig(config) {
|
|
|
11
11
|
return addNames(config);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
// packages/core/createRouterStore.ts
|
|
15
|
+
import queryString2 from "query-string";
|
|
16
|
+
|
|
14
17
|
// packages/core/utils/constants.ts
|
|
15
18
|
var constants = {
|
|
16
19
|
dynamicSeparator: ":",
|
|
@@ -31,37 +34,6 @@ function isDynamicRoute(route) {
|
|
|
31
34
|
return "params" in route;
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
// packages/core/utils/findRouteByPathname.ts
|
|
35
|
-
function completeStaticMatch(pathname, path) {
|
|
36
|
-
return !path.includes(constants.dynamicSeparator) && (pathname === path || pathname === `${path}${constants.pathPartSeparator}`);
|
|
37
|
-
}
|
|
38
|
-
function findRouteByPathname({
|
|
39
|
-
pathname,
|
|
40
|
-
routes
|
|
41
|
-
}) {
|
|
42
|
-
let dynamicRouteMatch;
|
|
43
|
-
const pathnameArray = pathname.replace(/\?.+$/, "").split(constants.pathPartSeparator).filter(Boolean);
|
|
44
|
-
for (const routeName in routes) {
|
|
45
|
-
if (!Object.hasOwn(routes, routeName)) continue;
|
|
46
|
-
const route = routes[routeName];
|
|
47
|
-
if (completeStaticMatch(pathname, route.path)) return route;
|
|
48
|
-
if (dynamicRouteMatch) continue;
|
|
49
|
-
const routePathnameArray = route.path.split(constants.pathPartSeparator).filter(Boolean);
|
|
50
|
-
if (routePathnameArray.length !== pathnameArray.length) continue;
|
|
51
|
-
const someParamInvalid = routePathnameArray.some((paramName, i) => {
|
|
52
|
-
const paramFromUrl = pathnameArray[i];
|
|
53
|
-
if (!isDynamic(paramName)) return paramName !== paramFromUrl;
|
|
54
|
-
const validator = route.params?.[clearDynamic(paramName)];
|
|
55
|
-
if (typeof validator !== "function") {
|
|
56
|
-
throw new Error(`findRoute: missing validator for param "${paramName}"`);
|
|
57
|
-
}
|
|
58
|
-
return !validator(paramFromUrl);
|
|
59
|
-
});
|
|
60
|
-
if (!someParamInvalid) dynamicRouteMatch = route;
|
|
61
|
-
}
|
|
62
|
-
return dynamicRouteMatch;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
37
|
// packages/core/utils/getDynamicValues.ts
|
|
66
38
|
function getDynamicValues(params) {
|
|
67
39
|
const { route, pathname } = params;
|
|
@@ -96,16 +68,6 @@ function getQueryValues(params) {
|
|
|
96
68
|
return query;
|
|
97
69
|
}
|
|
98
70
|
|
|
99
|
-
// packages/core/utils/getInitialRoute.ts
|
|
100
|
-
function getInitialRoute(params) {
|
|
101
|
-
const route = findRouteByPathname({ pathname: params.pathname, routes: params.routes }) || params.routes[params.fallback];
|
|
102
|
-
return {
|
|
103
|
-
route: route.name,
|
|
104
|
-
query: getQueryValues({ route, pathname: params.pathname }),
|
|
105
|
-
params: getDynamicValues({ route, pathname: params.pathname })
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
71
|
// packages/core/utils/history.ts
|
|
110
72
|
import { createBrowserHistory } from "history";
|
|
111
73
|
var history = constants.isClient ? createBrowserHistory() : null;
|
|
@@ -142,8 +104,223 @@ function replaceDynamicValues({
|
|
|
142
104
|
return encodeURIComponent(value);
|
|
143
105
|
});
|
|
144
106
|
}
|
|
107
|
+
|
|
108
|
+
// packages/core/createRouterStore.ts
|
|
109
|
+
function createRouterStore({
|
|
110
|
+
batch,
|
|
111
|
+
routes,
|
|
112
|
+
routeError500,
|
|
113
|
+
makeObservable,
|
|
114
|
+
lifecycleParams,
|
|
115
|
+
replaceObject
|
|
116
|
+
}) {
|
|
117
|
+
const routerStore = makeObservable({
|
|
118
|
+
routesHistory: [],
|
|
119
|
+
currentRoute: {},
|
|
120
|
+
isRedirecting: false,
|
|
121
|
+
redirectTo: void 0
|
|
122
|
+
});
|
|
123
|
+
routerStore.redirectTo = async function redirectTo(config) {
|
|
124
|
+
const { route: routeName, noHistoryPush, asClient } = config;
|
|
125
|
+
const isClient = typeof asClient === "boolean" ? asClient : constants.isClient;
|
|
126
|
+
let currentRoute;
|
|
127
|
+
let currentPathname;
|
|
128
|
+
let currentUrl;
|
|
129
|
+
let currentSearch;
|
|
130
|
+
let currentQuery;
|
|
131
|
+
if (routerStore.currentRoute?.name) {
|
|
132
|
+
currentRoute = routes[routerStore.currentRoute.name];
|
|
133
|
+
currentPathname = replaceDynamicValues({
|
|
134
|
+
route: currentRoute,
|
|
135
|
+
params: routerStore.currentRoute.params
|
|
136
|
+
});
|
|
137
|
+
currentUrl = queryString2.stringifyUrl({
|
|
138
|
+
url: currentPathname,
|
|
139
|
+
query: routerStore.currentRoute.query
|
|
140
|
+
});
|
|
141
|
+
currentQuery = routerStore.currentRoute.query;
|
|
142
|
+
currentSearch = queryString2.stringify(routerStore.currentRoute.query);
|
|
143
|
+
}
|
|
144
|
+
const nextRoute = routes[routeName];
|
|
145
|
+
const nextPathname = replaceDynamicValues({
|
|
146
|
+
route: nextRoute,
|
|
147
|
+
params: "params" in config ? config.params : void 0
|
|
148
|
+
});
|
|
149
|
+
let nextQuery;
|
|
150
|
+
let nextUrl = nextPathname;
|
|
151
|
+
let nextSearch;
|
|
152
|
+
if ("query" in config && config.query) {
|
|
153
|
+
const clearedQuery = getQueryValues({
|
|
154
|
+
route: nextRoute,
|
|
155
|
+
pathname: `${nextPathname}?${queryString2.stringify(config.query)}`
|
|
156
|
+
});
|
|
157
|
+
if (Object.keys(clearedQuery).length > 0) {
|
|
158
|
+
nextQuery = clearedQuery;
|
|
159
|
+
nextSearch = queryString2.stringify(clearedQuery);
|
|
160
|
+
nextUrl = queryString2.stringifyUrl({ url: nextPathname, query: clearedQuery });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (currentUrl === nextUrl) return Promise.resolve();
|
|
164
|
+
if (currentPathname === nextPathname) {
|
|
165
|
+
if (currentSearch !== nextSearch) {
|
|
166
|
+
batch(() => {
|
|
167
|
+
replaceObject(routerStore.currentRoute.query, nextQuery || {});
|
|
168
|
+
routerStore.routesHistory.push(nextUrl);
|
|
169
|
+
});
|
|
170
|
+
if (history && !noHistoryPush) {
|
|
171
|
+
history.push({
|
|
172
|
+
hash: history.location.hash,
|
|
173
|
+
search: nextSearch,
|
|
174
|
+
pathname: nextPathname
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return Promise.resolve();
|
|
179
|
+
}
|
|
180
|
+
batch(() => {
|
|
181
|
+
routerStore.isRedirecting = true;
|
|
182
|
+
});
|
|
183
|
+
try {
|
|
184
|
+
await currentRoute?.beforeLeave?.(
|
|
185
|
+
{
|
|
186
|
+
nextUrl,
|
|
187
|
+
nextRoute,
|
|
188
|
+
nextQuery,
|
|
189
|
+
nextSearch,
|
|
190
|
+
nextPathname,
|
|
191
|
+
currentUrl,
|
|
192
|
+
currentQuery,
|
|
193
|
+
currentRoute,
|
|
194
|
+
currentSearch,
|
|
195
|
+
currentPathname
|
|
196
|
+
},
|
|
197
|
+
...lifecycleParams || []
|
|
198
|
+
);
|
|
199
|
+
const redirectConfig = await nextRoute.beforeEnter?.(
|
|
200
|
+
{
|
|
201
|
+
nextUrl,
|
|
202
|
+
nextRoute,
|
|
203
|
+
nextQuery,
|
|
204
|
+
nextSearch,
|
|
205
|
+
nextPathname,
|
|
206
|
+
currentUrl,
|
|
207
|
+
currentQuery,
|
|
208
|
+
currentRoute,
|
|
209
|
+
currentSearch,
|
|
210
|
+
currentPathname
|
|
211
|
+
},
|
|
212
|
+
...lifecycleParams || []
|
|
213
|
+
);
|
|
214
|
+
if (typeof redirectConfig === "object") {
|
|
215
|
+
if (isClient) return redirectTo({ ...redirectConfig, asClient });
|
|
216
|
+
const redirectRoute = routes[redirectConfig.route];
|
|
217
|
+
const redirectParams = "params" in redirectConfig && redirectConfig.params ? redirectConfig.params : void 0;
|
|
218
|
+
let redirectUrl = replaceDynamicValues({
|
|
219
|
+
params: redirectParams,
|
|
220
|
+
route: redirectRoute
|
|
221
|
+
});
|
|
222
|
+
if ("query" in redirectConfig && redirectConfig.query) {
|
|
223
|
+
const clearedQuery = getQueryValues({
|
|
224
|
+
route: nextRoute,
|
|
225
|
+
pathname: `${nextPathname}?${queryString2.stringify(redirectConfig.query)}`
|
|
226
|
+
});
|
|
227
|
+
if (Object.keys(clearedQuery).length > 0) {
|
|
228
|
+
redirectUrl = queryString2.stringifyUrl({ url: redirectUrl, query: clearedQuery });
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
throw Object.assign(new Error(redirectUrl), { name: constants.errorRedirect });
|
|
232
|
+
}
|
|
233
|
+
await loadComponentToConfig({ route: routes[nextRoute.name] });
|
|
234
|
+
} catch (error) {
|
|
235
|
+
if (error?.name === constants.errorPrevent) return Promise.resolve();
|
|
236
|
+
if (error?.name === constants.errorRedirect) {
|
|
237
|
+
throw error;
|
|
238
|
+
}
|
|
239
|
+
console.error(error);
|
|
240
|
+
await loadComponentToConfig({ route: routeError500 });
|
|
241
|
+
batch(() => {
|
|
242
|
+
replaceObject(routerStore.currentRoute, {
|
|
243
|
+
name: routeError500.name,
|
|
244
|
+
path: routeError500.path,
|
|
245
|
+
props: routes[routeError500.name].props,
|
|
246
|
+
query: {},
|
|
247
|
+
params: {},
|
|
248
|
+
pageName: routes[routeError500.name].pageName
|
|
249
|
+
});
|
|
250
|
+
routerStore.isRedirecting = false;
|
|
251
|
+
});
|
|
252
|
+
return Promise.resolve();
|
|
253
|
+
}
|
|
254
|
+
batch(() => {
|
|
255
|
+
replaceObject(routerStore.currentRoute, {
|
|
256
|
+
name: nextRoute.name,
|
|
257
|
+
path: nextRoute.path,
|
|
258
|
+
props: routes[nextRoute.name].props,
|
|
259
|
+
query: getQueryValues({ route: nextRoute, pathname: nextUrl }),
|
|
260
|
+
params: getDynamicValues({ route: nextRoute, pathname: nextUrl }),
|
|
261
|
+
pageName: routes[nextRoute.name].pageName
|
|
262
|
+
});
|
|
263
|
+
const lastUrl = routerStore.routesHistory[routerStore.routesHistory.length - 1];
|
|
264
|
+
if (lastUrl !== nextUrl) {
|
|
265
|
+
routerStore.routesHistory.push(nextUrl);
|
|
266
|
+
}
|
|
267
|
+
if (history && !noHistoryPush) {
|
|
268
|
+
history.push({
|
|
269
|
+
hash: history.location.hash,
|
|
270
|
+
search: "query" in config ? `?${queryString2.stringify(config.query)}` : "",
|
|
271
|
+
pathname: nextPathname
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
routerStore.isRedirecting = false;
|
|
275
|
+
});
|
|
276
|
+
return Promise.resolve();
|
|
277
|
+
};
|
|
278
|
+
return routerStore;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// packages/core/utils/findRouteByPathname.ts
|
|
282
|
+
function completeStaticMatch(pathname, path) {
|
|
283
|
+
return !path.includes(constants.dynamicSeparator) && (pathname === path || pathname === `${path}${constants.pathPartSeparator}`);
|
|
284
|
+
}
|
|
285
|
+
function findRouteByPathname({
|
|
286
|
+
pathname,
|
|
287
|
+
routes
|
|
288
|
+
}) {
|
|
289
|
+
let dynamicRouteMatch;
|
|
290
|
+
const pathnameArray = pathname.replace(/\?.+$/, "").split(constants.pathPartSeparator).filter(Boolean);
|
|
291
|
+
for (const routeName in routes) {
|
|
292
|
+
if (!Object.hasOwn(routes, routeName)) continue;
|
|
293
|
+
const route = routes[routeName];
|
|
294
|
+
if (completeStaticMatch(pathname, route.path)) return route;
|
|
295
|
+
if (dynamicRouteMatch) continue;
|
|
296
|
+
const routePathnameArray = route.path.split(constants.pathPartSeparator).filter(Boolean);
|
|
297
|
+
if (routePathnameArray.length !== pathnameArray.length) continue;
|
|
298
|
+
const someParamInvalid = routePathnameArray.some((paramName, i) => {
|
|
299
|
+
const paramFromUrl = pathnameArray[i];
|
|
300
|
+
if (!isDynamic(paramName)) return paramName !== paramFromUrl;
|
|
301
|
+
const validator = route.params?.[clearDynamic(paramName)];
|
|
302
|
+
if (typeof validator !== "function") {
|
|
303
|
+
throw new Error(`findRoute: missing validator for param "${paramName}"`);
|
|
304
|
+
}
|
|
305
|
+
return !validator(paramFromUrl);
|
|
306
|
+
});
|
|
307
|
+
if (!someParamInvalid) dynamicRouteMatch = route;
|
|
308
|
+
}
|
|
309
|
+
return dynamicRouteMatch;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// packages/core/utils/getInitialRoute.ts
|
|
313
|
+
function getInitialRoute(params) {
|
|
314
|
+
const route = findRouteByPathname({ pathname: params.pathname, routes: params.routes }) || params.routes[params.fallback];
|
|
315
|
+
return {
|
|
316
|
+
route: route.name,
|
|
317
|
+
query: getQueryValues({ route, pathname: params.pathname }),
|
|
318
|
+
params: getDynamicValues({ route, pathname: params.pathname })
|
|
319
|
+
};
|
|
320
|
+
}
|
|
145
321
|
export {
|
|
146
322
|
createRouterConfig,
|
|
323
|
+
createRouterStore,
|
|
147
324
|
findRouteByPathname,
|
|
148
325
|
getInitialRoute,
|
|
149
326
|
history,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { createRouterConfig } from './createRouterConfig';
|
|
2
|
+
export { createRouterStore } from './createRouterStore';
|
|
2
3
|
export type { InterfaceRouterStore } from './types/InterfaceRouterStore';
|
|
3
4
|
export type { TypeCurrentRoute } from './types/TypeCurrentRoute';
|
|
4
5
|
export type { TypeRedirectToParams } from './types/TypeRedirectToParams';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../packages/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,YAAY,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,YAAY,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../packages/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,YAAY,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACzE,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC"}
|