@rxdi/router 0.7.220 → 0.7.221
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/README.md +101 -0
- package/dist/decorators.d.ts +1 -2
- package/dist/decorators.js +1 -1
- package/dist/helpers.d.ts +1 -1
- package/dist/helpers.js +11 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/injection.tokens.d.ts +23 -16
- package/dist/injection.tokens.js +3 -1
- package/dist/lib/constants.d.ts +3 -0
- package/dist/lib/constants.js +6 -0
- package/dist/lib/index.d.ts +4 -0
- package/dist/{slot → lib}/index.js +6 -4
- package/dist/lib/path-to-regexp.d.ts +6 -0
- package/dist/lib/path-to-regexp.js +228 -0
- package/dist/lib/resolver.d.ts +70 -0
- package/dist/lib/resolver.js +426 -0
- package/dist/{vaadin/vaadin-router.d.ts → lib/router.d.ts} +98 -201
- package/dist/lib/router.js +833 -0
- package/dist/lib/triggers.d.ts +6 -0
- package/dist/lib/triggers.js +98 -0
- package/dist/lib/types.d.ts +134 -0
- package/dist/lib/types.js +6 -0
- package/dist/lib/utils.d.ts +20 -0
- package/dist/lib/utils.js +155 -0
- package/dist/not-found.component.js +3 -3
- package/dist/outlet.d.ts +7 -62
- package/dist/outlet.js +15 -84
- package/dist/router.component.d.ts +3 -3
- package/dist/router.component.js +4 -4
- package/package.json +3 -3
- package/dist/slot/index.d.ts +0 -8
- package/dist/slot/slot.d.ts +0 -11
- package/dist/slot/slot.js +0 -44
- package/dist/vaadin/vaadin-router.js +0 -2065
- package/slot/index.d.ts +0 -8
- package/slot/index.js +0 -8
- package/slot/slot.d.ts +0 -11
- package/slot/slot.js +0 -45
package/README.md
CHANGED
|
@@ -236,4 +236,105 @@ export class AboutComponent extends LitElement implements OnBeforeEnter, OnAfter
|
|
|
236
236
|
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
#### Snapshot changes
|
|
242
|
+
|
|
243
|
+
You can subscribe to route changes using `onSnapshotChange`. This is useful for reactive updates based on the current route state.
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
import { Component, html, LitElement, OnUpdateFirst } from '@rxdi/lit-html';
|
|
247
|
+
import { OnDestroy } from '@rxdi/lit-html';
|
|
248
|
+
import { Router } from '@rxdi/router';
|
|
249
|
+
import { Subject, takeUntil } from 'rxjs';
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* @customElement app-component
|
|
253
|
+
*/
|
|
254
|
+
@Component({
|
|
255
|
+
selector: 'app-component',
|
|
256
|
+
template(this: AboutComponent) {
|
|
257
|
+
return html``;
|
|
258
|
+
},
|
|
259
|
+
})
|
|
260
|
+
export class AboutComponent extends LitElement implements OnUpdateFirst, OnDestroy {
|
|
261
|
+
@Router()
|
|
262
|
+
private router: Router;
|
|
263
|
+
|
|
264
|
+
destroy$ = new Subject();
|
|
265
|
+
|
|
266
|
+
OnUpdateFirst() {
|
|
267
|
+
this.router
|
|
268
|
+
.onSnapshotChange()
|
|
269
|
+
.pipe(takeUntil(this.destroy$))
|
|
270
|
+
.subscribe((e) => {
|
|
271
|
+
console.log(e);
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
OnDestroy() {
|
|
276
|
+
this.destroy$.next(true);
|
|
277
|
+
this.destroy$.complete();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
#### Child Routing with Slots
|
|
283
|
+
|
|
284
|
+
The router supports advanced child routing where the parent component acts as a layout container. By using the standard Web Component `<slot></slot>` mechanism, the parent component can wrap child routes with common UI elements (headers, sidebars, etc.).
|
|
285
|
+
|
|
286
|
+
**Define the Module with Child Routes:**
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
import { Module } from '@rxdi/core';
|
|
290
|
+
import { RouterModule } from '@rxdi/router';
|
|
291
|
+
import { ProjectContainerComponent } from './project-container.component';
|
|
292
|
+
import { DetailsComponent } from './details.component';
|
|
293
|
+
import { SettingsComponent } from './settings.component';
|
|
294
|
+
|
|
295
|
+
@Module({
|
|
296
|
+
imports: [
|
|
297
|
+
RouterModule.forChild([
|
|
298
|
+
{
|
|
299
|
+
path: '/:projectId',
|
|
300
|
+
component: ProjectContainerComponent, // This component contains the <slot>
|
|
301
|
+
children: [
|
|
302
|
+
{
|
|
303
|
+
path: '/',
|
|
304
|
+
component: DetailsComponent, // Rendered inside ProjectContainerComponent's slot
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
path: '/settings',
|
|
308
|
+
component: SettingsComponent, // Rendered inside ProjectContainerComponent's slot
|
|
309
|
+
}
|
|
310
|
+
],
|
|
311
|
+
},
|
|
312
|
+
]),
|
|
313
|
+
],
|
|
314
|
+
})
|
|
315
|
+
export class ProjectsModule {}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
**Parent Component Implementation (`ProjectContainerComponent`):**
|
|
319
|
+
|
|
320
|
+
The parent component simply includes a `<slot>` elements in its template. The router will automatically inject the matched child component into this slot.
|
|
321
|
+
|
|
322
|
+
```typescript
|
|
323
|
+
import { Component } from '@rhtml/component';
|
|
324
|
+
import { html, LitElement } from '@rxdi/lit-html';
|
|
325
|
+
|
|
326
|
+
@Component({
|
|
327
|
+
selector: 'project-container-component',
|
|
328
|
+
template: () => html`
|
|
329
|
+
<div style="height: 100%; display: flex; flex-direction: column;">
|
|
330
|
+
<header>Project Header (Visible on all child routes)</header>
|
|
331
|
+
|
|
332
|
+
<!-- The active child route component will be rendered here -->
|
|
333
|
+
<slot></slot>
|
|
334
|
+
|
|
335
|
+
<footer>Project Footer</footer>
|
|
336
|
+
</div>
|
|
337
|
+
`,
|
|
338
|
+
})
|
|
339
|
+
export class ProjectContainerComponent extends LitElement {}
|
|
239
340
|
```
|
package/dist/decorators.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Define getter to `this.location.params` from component `this` and assign params to decorated property
|
|
3
3
|
*
|
|
4
|
-
* Info can be found at @vaadin-router https://vaadin.github.io/vaadin-router/vaadin-router/demo/#vaadin-router-route-parameters-demos
|
|
5
4
|
* @param target: LitElement | HTMLElement
|
|
6
5
|
* @returns this.location.params as getter (lazy evaluated)
|
|
7
6
|
* Usage:
|
|
@@ -24,4 +23,4 @@ export class UserProfile extends LitElement {
|
|
|
24
23
|
}
|
|
25
24
|
```
|
|
26
25
|
*/
|
|
27
|
-
export declare function RouteParams(): (target:
|
|
26
|
+
export declare function RouteParams(): (target: HTMLElement, propertyKey: string) => void;
|
package/dist/decorators.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
4
|
exports.RouteParams = RouteParams;
|
|
4
5
|
/**
|
|
5
6
|
* Define getter to `this.location.params` from component `this` and assign params to decorated property
|
|
6
7
|
*
|
|
7
|
-
* Info can be found at @vaadin-router https://vaadin.github.io/vaadin-router/vaadin-router/demo/#vaadin-router-route-parameters-demos
|
|
8
8
|
* @param target: LitElement | HTMLElement
|
|
9
9
|
* @returns this.location.params as getter (lazy evaluated)
|
|
10
10
|
* Usage:
|
package/dist/helpers.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BehaviorSubject } from 'rxjs';
|
|
2
2
|
import { Route } from './injection.tokens';
|
|
3
|
-
export declare const ChildRoutesObservable: BehaviorSubject<Route
|
|
3
|
+
export declare const ChildRoutesObservable: BehaviorSubject<Route[]>;
|
|
4
4
|
export declare function loadRoutes(routes: Route[]): Route<any>[];
|
|
5
5
|
export declare function getQueryParams<T>(params: string[]): T;
|
package/dist/helpers.js
CHANGED
|
@@ -12,9 +12,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.ChildRoutesObservable = void 0;
|
|
13
13
|
exports.loadRoutes = loadRoutes;
|
|
14
14
|
exports.getQueryParams = getQueryParams;
|
|
15
|
+
const core_1 = require("@rxdi/core");
|
|
15
16
|
const rxjs_1 = require("rxjs");
|
|
16
17
|
const injection_tokens_1 = require("./injection.tokens");
|
|
17
|
-
const core_1 = require("@rxdi/core");
|
|
18
18
|
const RouteCache = new Map();
|
|
19
19
|
exports.ChildRoutesObservable = new rxjs_1.BehaviorSubject(null);
|
|
20
20
|
function assignChildren(route) {
|
|
@@ -22,8 +22,13 @@ function assignChildren(route) {
|
|
|
22
22
|
const lazyModule = route.children;
|
|
23
23
|
route.children = function (context, commands) {
|
|
24
24
|
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
console.log('Lazy loading route:', route.path);
|
|
26
|
+
const loadedModule = yield lazyModule(context, commands);
|
|
27
|
+
let routes = exports.ChildRoutesObservable.getValue();
|
|
28
|
+
if (loadedModule && Array.isArray(loadedModule.ROUTES)) {
|
|
29
|
+
routes = loadedModule.ROUTES;
|
|
30
|
+
}
|
|
31
|
+
const params = [...(routes || []).map((r) => Object.assign({}, r))];
|
|
27
32
|
if (!RouteCache.has(route.path)) {
|
|
28
33
|
RouteCache.set(route.path, params);
|
|
29
34
|
}
|
|
@@ -87,6 +92,9 @@ function assignStaticIs(route) {
|
|
|
87
92
|
if (typeof route.component === 'function') {
|
|
88
93
|
route.component = route.component.is();
|
|
89
94
|
}
|
|
95
|
+
if (Array.isArray(route.children)) {
|
|
96
|
+
route.children = route.children.map((child) => assignStaticIs(assignAction(assignChildren(child))));
|
|
97
|
+
}
|
|
90
98
|
return route;
|
|
91
99
|
}
|
|
92
100
|
function loadRoutes(routes) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ModuleWithServices } from '@rxdi/core';
|
|
2
|
-
import {
|
|
3
|
-
import { RouterOptions, Route } from './injection.tokens';
|
|
2
|
+
import { Route, RouterOptions } from './injection.tokens';
|
|
4
3
|
import { NotFoundComponent } from './not-found.component';
|
|
4
|
+
import { RouterComponent } from './router.component';
|
|
5
5
|
export declare class RouterModule {
|
|
6
6
|
static forRoot<C>(routes: Route<C>[], options?: RouterOptions): ModuleWithServices;
|
|
7
|
-
static forChild(routes: Route
|
|
7
|
+
static forChild(routes: Route[]): typeof RouterModule;
|
|
8
8
|
}
|
|
9
9
|
export * from './injection.tokens';
|
|
10
10
|
export * from './outlet';
|
package/dist/index.js
CHANGED
|
@@ -23,9 +23,9 @@ var RouterModule_1;
|
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
24
|
exports.RouterModule = void 0;
|
|
25
25
|
const core_1 = require("@rxdi/core");
|
|
26
|
-
const router_component_1 = require("./router.component");
|
|
27
|
-
const injection_tokens_1 = require("./injection.tokens");
|
|
28
26
|
const helpers_1 = require("./helpers");
|
|
27
|
+
const injection_tokens_1 = require("./injection.tokens");
|
|
28
|
+
const router_component_1 = require("./router.component");
|
|
29
29
|
let RouterModule = RouterModule_1 = class RouterModule {
|
|
30
30
|
static forRoot(routes, options) {
|
|
31
31
|
return {
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
+
import { InjectionToken } from '@rxdi/core';
|
|
1
2
|
import { Observable } from 'rxjs';
|
|
2
3
|
import { Outlet } from './outlet';
|
|
3
|
-
export interface NavigationTrigger {
|
|
4
|
-
}
|
|
5
4
|
export declare function Router(): (target: Object, propertyKey: string) => void;
|
|
6
5
|
export type LazyChildren = (context?: CanActivateContext, commands?: CanActivateCommands) => Promise<any>;
|
|
7
6
|
export type Router = Outlet;
|
|
8
7
|
export interface Route<C = any> {
|
|
9
|
-
path
|
|
8
|
+
path?: string | string[];
|
|
10
9
|
component?: C | Function | string;
|
|
11
|
-
animate?: boolean
|
|
10
|
+
animate?: boolean | {
|
|
11
|
+
leave?: string;
|
|
12
|
+
enter?: string;
|
|
13
|
+
};
|
|
12
14
|
children?: Route<C>[] | LazyChildren;
|
|
13
15
|
redirect?: string;
|
|
14
16
|
freeze?: boolean;
|
|
@@ -25,35 +27,40 @@ export interface CanActivateContextKeys {
|
|
|
25
27
|
repeat: boolean;
|
|
26
28
|
}
|
|
27
29
|
export interface RouteContext extends Route {
|
|
28
|
-
parent
|
|
29
|
-
parent
|
|
30
|
-
path
|
|
31
|
-
};
|
|
30
|
+
parent?: {
|
|
31
|
+
parent?: any;
|
|
32
|
+
path?: string | string[];
|
|
33
|
+
} | null;
|
|
32
34
|
}
|
|
33
35
|
export interface CanActivateResolver {
|
|
34
36
|
canActivate(context: CanActivateContext, commands: CanActivateCommands): CanActivateRedirectResult | Promise<CanActivateRedirectResult> | boolean | Promise<boolean> | Observable<boolean> | void;
|
|
35
37
|
}
|
|
36
38
|
export interface CanActivateRedirectResult {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
redirect: {
|
|
40
|
+
from: string;
|
|
41
|
+
params: any;
|
|
42
|
+
pathname: string;
|
|
43
|
+
};
|
|
40
44
|
}
|
|
41
45
|
export interface CanActivateContext {
|
|
42
|
-
|
|
46
|
+
pathname: string;
|
|
47
|
+
params: any;
|
|
48
|
+
route: RouteContext;
|
|
49
|
+
chain?: {
|
|
43
50
|
route: RouteContext;
|
|
44
51
|
path: string;
|
|
45
|
-
element
|
|
52
|
+
element?: HTMLElement;
|
|
46
53
|
}[];
|
|
47
54
|
keys: any[];
|
|
48
|
-
next
|
|
55
|
+
next?: (resume?: any, parent?: any, prevResult?: any) => any;
|
|
49
56
|
}
|
|
50
57
|
export interface CanActivateCommands {
|
|
51
|
-
component: () =>
|
|
58
|
+
component: (component: string) => HTMLElement;
|
|
52
59
|
redirect: (path: string) => CanActivateRedirectResult;
|
|
53
60
|
}
|
|
54
61
|
export declare const RouterRoutlet = "router-outlet";
|
|
55
62
|
export declare const Routes = "router-routes";
|
|
56
|
-
export declare const RouterOptions
|
|
63
|
+
export declare const RouterOptions: InjectionToken<RouterOptions>;
|
|
57
64
|
export interface RouterOptions {
|
|
58
65
|
baseUrl?: string;
|
|
59
66
|
log?: boolean;
|
package/dist/injection.tokens.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RouterOptions = exports.Routes = exports.RouterRoutlet = void 0;
|
|
4
4
|
exports.Router = Router;
|
|
5
|
+
/* eslint-disable @typescript-eslint/ban-types */
|
|
6
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
5
7
|
const core_1 = require("@rxdi/core");
|
|
6
8
|
function Router() {
|
|
7
9
|
return (target, propertyKey) => {
|
|
@@ -12,4 +14,4 @@ function Router() {
|
|
|
12
14
|
}
|
|
13
15
|
exports.RouterRoutlet = 'router-outlet';
|
|
14
16
|
exports.Routes = 'router-routes';
|
|
15
|
-
exports.RouterOptions = 'router-options';
|
|
17
|
+
exports.RouterOptions = new core_1.InjectionToken('router-options');
|
|
@@ -14,7 +14,9 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.
|
|
18
|
-
|
|
19
|
-
Object.defineProperty(exports, "
|
|
20
|
-
|
|
17
|
+
exports.Router = exports.Resolver = void 0;
|
|
18
|
+
const resolver_1 = require("./resolver");
|
|
19
|
+
Object.defineProperty(exports, "Resolver", { enumerable: true, get: function () { return resolver_1.Resolver; } });
|
|
20
|
+
const router_1 = require("./router");
|
|
21
|
+
Object.defineProperty(exports, "Router", { enumerable: true, get: function () { return router_1.Router; } });
|
|
22
|
+
__exportStar(require("./types"), exports);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { CompileOptions, PathToken, PathToRegexpOptions, RouteParams } from './types';
|
|
2
|
+
export declare function parse(str: string, options?: PathToRegexpOptions): (string | PathToken)[];
|
|
3
|
+
export declare function compile(str: string, options?: PathToRegexpOptions): (data?: RouteParams, options?: CompileOptions) => string;
|
|
4
|
+
export declare function tokensToFunction(tokens: (string | PathToken)[]): (data?: RouteParams, options?: CompileOptions) => string;
|
|
5
|
+
export declare function tokensToRegExp(tokens: (string | PathToken)[], keys?: PathToken[], options?: PathToRegexpOptions): RegExp;
|
|
6
|
+
export declare function pathToRegexp(path: string | RegExp | (string | RegExp)[], keys?: PathToken[], options?: PathToRegexpOptions): RegExp;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parse = parse;
|
|
4
|
+
exports.compile = compile;
|
|
5
|
+
exports.tokensToFunction = tokensToFunction;
|
|
6
|
+
exports.tokensToRegExp = tokensToRegExp;
|
|
7
|
+
exports.pathToRegexp = pathToRegexp;
|
|
8
|
+
const DEFAULT_DELIMITER = '/';
|
|
9
|
+
const DEFAULT_DELIMITERS = './';
|
|
10
|
+
const PATH_REGEXP = new RegExp(['(\\\\.)', '(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?'].join('|'), 'g');
|
|
11
|
+
function parse(str, options) {
|
|
12
|
+
const tokens = [];
|
|
13
|
+
let key = 0;
|
|
14
|
+
let index = 0;
|
|
15
|
+
let path = '';
|
|
16
|
+
const defaultDelimiter = (options && options.delimiter) || DEFAULT_DELIMITER;
|
|
17
|
+
const delimiters = (options && options.delimiters) || DEFAULT_DELIMITERS;
|
|
18
|
+
let pathEscaped = false;
|
|
19
|
+
let res;
|
|
20
|
+
while ((res = PATH_REGEXP.exec(str)) !== null) {
|
|
21
|
+
const m = res[0];
|
|
22
|
+
const escaped = res[1];
|
|
23
|
+
const offset = res.index;
|
|
24
|
+
path += str.slice(index, offset);
|
|
25
|
+
index = offset + m.length;
|
|
26
|
+
if (escaped) {
|
|
27
|
+
path += escaped[1];
|
|
28
|
+
pathEscaped = true;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
let prev = '';
|
|
32
|
+
const next = str[index];
|
|
33
|
+
const name = res[2];
|
|
34
|
+
const capture = res[3];
|
|
35
|
+
const group = res[4];
|
|
36
|
+
const modifier = res[5];
|
|
37
|
+
if (!pathEscaped && path.length) {
|
|
38
|
+
const k = path.length - 1;
|
|
39
|
+
if (delimiters.indexOf(path[k]) > -1) {
|
|
40
|
+
prev = path[k];
|
|
41
|
+
path = path.slice(0, k);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (path) {
|
|
45
|
+
tokens.push(path);
|
|
46
|
+
path = '';
|
|
47
|
+
pathEscaped = false;
|
|
48
|
+
}
|
|
49
|
+
const partial = prev !== '' && next !== undefined && next !== prev;
|
|
50
|
+
const repeat = modifier === '+' || modifier === '*';
|
|
51
|
+
const optional = modifier === '?' || modifier === '*';
|
|
52
|
+
const delimiter = prev || defaultDelimiter;
|
|
53
|
+
const pattern = capture || group;
|
|
54
|
+
tokens.push({
|
|
55
|
+
name: name || key++,
|
|
56
|
+
prefix: prev,
|
|
57
|
+
delimiter: delimiter,
|
|
58
|
+
optional: optional,
|
|
59
|
+
repeat: repeat,
|
|
60
|
+
partial: partial,
|
|
61
|
+
pattern: pattern ? escapeGroup(pattern) : '[^' + escapeString(delimiter) + ']+?',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
if (path || index < str.length) {
|
|
65
|
+
tokens.push(path + str.substr(index));
|
|
66
|
+
}
|
|
67
|
+
return tokens;
|
|
68
|
+
}
|
|
69
|
+
function compile(str, options) {
|
|
70
|
+
return tokensToFunction(parse(str, options));
|
|
71
|
+
}
|
|
72
|
+
function tokensToFunction(tokens) {
|
|
73
|
+
const matches = new Array(tokens.length);
|
|
74
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
75
|
+
if (typeof tokens[i] === 'object') {
|
|
76
|
+
matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return function (data, options) {
|
|
80
|
+
let path = '';
|
|
81
|
+
const encode = (options && options.encode) || encodeURIComponent;
|
|
82
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
83
|
+
const token = tokens[i];
|
|
84
|
+
if (typeof token === 'string') {
|
|
85
|
+
path += token;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const value = data ? data[token.name] : undefined;
|
|
89
|
+
let segment;
|
|
90
|
+
if (Array.isArray(value)) {
|
|
91
|
+
if (!token.repeat) {
|
|
92
|
+
throw new TypeError('Expected "' + token.name + '" to not repeat, but got array');
|
|
93
|
+
}
|
|
94
|
+
if (value.length === 0) {
|
|
95
|
+
if (token.optional)
|
|
96
|
+
continue;
|
|
97
|
+
throw new TypeError('Expected "' + token.name + '" to not be empty');
|
|
98
|
+
}
|
|
99
|
+
for (let j = 0; j < value.length; j++) {
|
|
100
|
+
segment = encode(value[j], token);
|
|
101
|
+
if (!matches[i].test(segment)) {
|
|
102
|
+
throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '"');
|
|
103
|
+
}
|
|
104
|
+
path += (j === 0 ? token.prefix : token.delimiter) + segment;
|
|
105
|
+
}
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
|
109
|
+
segment = encode(String(value), token);
|
|
110
|
+
if (!matches[i].test(segment)) {
|
|
111
|
+
throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but got "' + segment + '"');
|
|
112
|
+
}
|
|
113
|
+
path += token.prefix + segment;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (token.optional) {
|
|
117
|
+
if (token.partial)
|
|
118
|
+
path += token.prefix;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
throw new TypeError('Expected "' + token.name + '" to be ' + (token.repeat ? 'an array' : 'a string'));
|
|
122
|
+
}
|
|
123
|
+
return path;
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function escapeString(str) {
|
|
127
|
+
return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, '\\$1');
|
|
128
|
+
}
|
|
129
|
+
function escapeGroup(group) {
|
|
130
|
+
return group.replace(/([=!:$/()])/g, '\\$1');
|
|
131
|
+
}
|
|
132
|
+
function flags(options) {
|
|
133
|
+
return options && options.sensitive ? '' : 'i';
|
|
134
|
+
}
|
|
135
|
+
function regexpToRegexp(path, keys) {
|
|
136
|
+
if (!keys)
|
|
137
|
+
return path;
|
|
138
|
+
const groups = path.source.match(/\((?!\?)/g);
|
|
139
|
+
if (groups) {
|
|
140
|
+
for (let i = 0; i < groups.length; i++) {
|
|
141
|
+
keys.push({
|
|
142
|
+
name: i,
|
|
143
|
+
prefix: '',
|
|
144
|
+
delimiter: '',
|
|
145
|
+
optional: false,
|
|
146
|
+
repeat: false,
|
|
147
|
+
partial: false,
|
|
148
|
+
pattern: '',
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return path;
|
|
153
|
+
}
|
|
154
|
+
function arrayToRegexp(path, keys, options) {
|
|
155
|
+
const parts = [];
|
|
156
|
+
for (let i = 0; i < path.length; i++) {
|
|
157
|
+
parts.push(pathToRegexp(path[i], keys, options).source);
|
|
158
|
+
}
|
|
159
|
+
return new RegExp('(?:' + parts.join('|') + ')', flags(options));
|
|
160
|
+
}
|
|
161
|
+
function stringToRegexp(path, keys, options) {
|
|
162
|
+
return tokensToRegExp(parse(path, options), keys, options);
|
|
163
|
+
}
|
|
164
|
+
function tokensToRegExp(tokens, keys, options) {
|
|
165
|
+
options = options || {};
|
|
166
|
+
const strict = options.strict;
|
|
167
|
+
const start = options.start !== false;
|
|
168
|
+
const end = options.end !== false;
|
|
169
|
+
const delimiter = escapeString(options.delimiter || DEFAULT_DELIMITER);
|
|
170
|
+
const delimiters = options.delimiters || DEFAULT_DELIMITERS;
|
|
171
|
+
const endsWith = []
|
|
172
|
+
.concat(options.endsWith || [])
|
|
173
|
+
.map(escapeString)
|
|
174
|
+
.concat('$')
|
|
175
|
+
.join('|');
|
|
176
|
+
let route = start ? '^' : '';
|
|
177
|
+
let isEndDelimited = tokens.length === 0;
|
|
178
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
179
|
+
const token = tokens[i];
|
|
180
|
+
if (typeof token === 'string') {
|
|
181
|
+
route += escapeString(token);
|
|
182
|
+
isEndDelimited = i === tokens.length - 1 && delimiters.indexOf(token[token.length - 1]) > -1;
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
const capture = token.repeat
|
|
186
|
+
? '(?:' + token.pattern + ')(?:' + escapeString(token.delimiter) + '(?:' + token.pattern + '))*'
|
|
187
|
+
: token.pattern;
|
|
188
|
+
if (keys)
|
|
189
|
+
keys.push(token);
|
|
190
|
+
if (token.optional) {
|
|
191
|
+
if (token.partial) {
|
|
192
|
+
route += escapeString(token.prefix) + '(' + capture + ')?';
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
route += '(?:' + escapeString(token.prefix) + '(' + capture + '))?';
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
route += escapeString(token.prefix) + '(' + capture + ')';
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (end) {
|
|
204
|
+
if (!strict)
|
|
205
|
+
route += '(?:' + delimiter + ')?';
|
|
206
|
+
route += endsWith === '$' ? '$' : '(?=' + endsWith + ')';
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
if (!strict)
|
|
210
|
+
route += '(?:' + delimiter + '(?=' + endsWith + '))?';
|
|
211
|
+
if (!isEndDelimited)
|
|
212
|
+
route += '(?=' + delimiter + '|' + endsWith + ')';
|
|
213
|
+
}
|
|
214
|
+
return new RegExp(route, flags(options));
|
|
215
|
+
}
|
|
216
|
+
function pathToRegexp(path, keys, options) {
|
|
217
|
+
if (path instanceof RegExp) {
|
|
218
|
+
return regexpToRegexp(path, keys);
|
|
219
|
+
}
|
|
220
|
+
if (Array.isArray(path)) {
|
|
221
|
+
return arrayToRegexp(path, keys, options);
|
|
222
|
+
}
|
|
223
|
+
return stringToRegexp(path, keys, options);
|
|
224
|
+
}
|
|
225
|
+
// Attach static methods to pathToRegexp to match original usage if needed,
|
|
226
|
+
// but since we are exporting them individually, consumers can just import them.
|
|
227
|
+
// However, the original code used `pathToRegexp_1` which had static methods attached.
|
|
228
|
+
// We can just export them as named exports.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { GenerateUrlsOptions, ResolverOptions, Route, RouteContext, RouteResult, UrlGenerator } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Universal Router (https://www.kriasoft.com/universal-router/)
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) 2015-present Kriasoft.
|
|
6
|
+
*
|
|
7
|
+
* This source code is licensed under the MIT license found in the
|
|
8
|
+
* LICENSE.txt file in the root directory of this source tree.
|
|
9
|
+
*/
|
|
10
|
+
export declare class Resolver {
|
|
11
|
+
baseUrl: string;
|
|
12
|
+
errorHandler?: (error: Error) => RouteResult;
|
|
13
|
+
resolveRoute: (context: RouteContext) => RouteResult | Promise<RouteResult> | undefined | Promise<undefined>;
|
|
14
|
+
context: Partial<RouteContext> & {
|
|
15
|
+
resolver: Resolver;
|
|
16
|
+
};
|
|
17
|
+
root: Route;
|
|
18
|
+
constructor(routes: Route | Route[], options?: ResolverOptions);
|
|
19
|
+
/**
|
|
20
|
+
* Returns the current list of routes (as a shallow copy). Adding / removing
|
|
21
|
+
* routes to / from the returned array does not affect the routing config,
|
|
22
|
+
* but modifying the route objects does.
|
|
23
|
+
*
|
|
24
|
+
* @return
|
|
25
|
+
*/
|
|
26
|
+
getRoutes(): Route[];
|
|
27
|
+
/**
|
|
28
|
+
* Sets the routing config (replacing the existing one).
|
|
29
|
+
*
|
|
30
|
+
* @param routes a single route or an array of those
|
|
31
|
+
* (the array is shallow copied)
|
|
32
|
+
*/
|
|
33
|
+
setRoutes(routes: Route | Route[]): void;
|
|
34
|
+
/**
|
|
35
|
+
* Appends one or several routes to the routing config and returns the
|
|
36
|
+
* effective routing config after the operation.
|
|
37
|
+
*
|
|
38
|
+
* @param routes a single route or an array of those
|
|
39
|
+
* (the array is shallow copied)
|
|
40
|
+
* @return
|
|
41
|
+
* @protected
|
|
42
|
+
*/
|
|
43
|
+
addRoutes(routes: Route | Route[]): Route[];
|
|
44
|
+
/**
|
|
45
|
+
* Removes all existing routes from the routing config.
|
|
46
|
+
*/
|
|
47
|
+
removeRoutes(): void;
|
|
48
|
+
/**
|
|
49
|
+
* Asynchronously resolves the given pathname, i.e. finds all routes matching
|
|
50
|
+
* the pathname and tries resolving them one after another in the order they
|
|
51
|
+
* are listed in the routes config until the first non-null result.
|
|
52
|
+
*
|
|
53
|
+
* Returns a promise that is fulfilled with the return value of an object that consists of the first
|
|
54
|
+
* route handler result that returns something other than `null` or `undefined` and context used to get this result.
|
|
55
|
+
*
|
|
56
|
+
* If no route handlers return a non-null result, or if no route matches the
|
|
57
|
+
* given pathname the returned promise is rejected with a 'page not found'
|
|
58
|
+
* `Error`.
|
|
59
|
+
*
|
|
60
|
+
* @param pathnameOrContext the pathname to
|
|
61
|
+
* resolve or a context object with a `pathname` property and other
|
|
62
|
+
* properties to pass to the route resolver functions.
|
|
63
|
+
* @return
|
|
64
|
+
*/
|
|
65
|
+
resolve(pathnameOrContext: string | Partial<RouteContext>): Promise<RouteContext>;
|
|
66
|
+
static __createUrl(url: string, base: string): URL;
|
|
67
|
+
__getEffectiveBaseUrl(): string;
|
|
68
|
+
__normalizePathname(pathname: string): string | undefined;
|
|
69
|
+
}
|
|
70
|
+
export declare function generateUrls(router: Resolver, options?: GenerateUrlsOptions): UrlGenerator;
|