@lwrjs/router 0.12.0-alpha.1 → 0.12.0-alpha.10
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 +777 -0
- package/build/bundle/prod/lwr/navigation/navigation.js +1 -1
- package/build/bundle/prod/lwr/router/router.js +1 -1
- package/build/bundle/prod/lwr/routerContainer/routerContainer.js +1 -1
- package/build/cjs/modules/lwr/domRouter/domRouter.cjs +20 -10
- package/build/cjs/modules/lwr/historyRouter/historyRouter.cjs +3 -3
- package/build/cjs/modules/lwr/navigation/navigationApi.cjs +4 -4
- package/build/cjs/modules/lwr/navigation/navigationMixin.cjs +4 -4
- package/build/cjs/modules/lwr/router/router.cjs +14 -13
- package/build/cjs/modules/lwr/routerUtils/routeUtils.cjs +21 -8
- package/build/cjs/modules/lwr/routerUtils/routerUtils.cjs +1 -0
- package/build/cjs/modules/lwr/serverRouter/serverRouter.cjs +10 -10
- package/build/cjs/services/index.cjs +0 -1
- package/build/cjs/services/module-provider/index.cjs +13 -36
- package/build/cjs/services/module-provider/utils.cjs +18 -8
- package/build/es/modules/lwr/contextUtils/navigationApiStore.d.ts +3 -2
- package/build/es/modules/lwr/domRouter/domRouter.d.ts +14 -8
- package/build/es/modules/lwr/domRouter/domRouter.js +25 -10
- package/build/es/modules/lwr/historyRouter/historyRouter.d.ts +3 -2
- package/build/es/modules/lwr/historyRouter/historyRouter.js +4 -4
- package/build/es/modules/lwr/navigation/navigationApi.d.ts +9 -8
- package/build/es/modules/lwr/navigation/navigationApi.js +10 -10
- package/build/es/modules/lwr/navigation/navigationMixin.js +4 -4
- package/build/es/modules/lwr/router/router.d.ts +1 -1
- package/build/es/modules/lwr/router/router.js +15 -14
- package/build/es/modules/lwr/routerUtils/routeUtils.d.ts +7 -5
- package/build/es/modules/lwr/routerUtils/routeUtils.js +22 -8
- package/build/es/modules/lwr/routerUtils/routerUtils.d.ts +1 -1
- package/build/es/modules/lwr/routerUtils/routerUtils.js +1 -1
- package/build/es/modules/lwr/routerUtils/types.d.ts +17 -13
- package/build/es/modules/lwr/serverRouter/serverRouter.d.ts +4 -3
- package/build/es/modules/lwr/serverRouter/serverRouter.js +11 -11
- package/build/es/services/index.d.ts +3 -1
- package/build/es/services/index.js +0 -1
- package/build/es/services/module-provider/index.d.ts +6 -7
- package/build/es/services/module-provider/index.js +15 -47
- package/build/es/services/module-provider/utils.d.ts +2 -2
- package/build/es/services/module-provider/utils.js +24 -8
- package/build/modules/lwr/contextUtils/contextUtils.js +1 -0
- package/build/modules/lwr/domRouter/domRouter.js +27 -10
- package/build/modules/lwr/domRouterUtils/historyUtils.js +1 -0
- package/build/modules/lwr/historyRouter/historyRouter.js +4 -4
- package/build/modules/lwr/navigation/navigationApi.js +10 -10
- package/build/modules/lwr/navigation/navigationMixin.js +4 -4
- package/build/modules/lwr/router/router.js +15 -14
- package/build/modules/lwr/routerBridge/routerBridge.js +0 -1
- package/build/modules/lwr/routerContainer/utils.js +3 -1
- package/build/modules/lwr/routerUtils/routeDefUtils.js +0 -1
- package/build/modules/lwr/routerUtils/routeUtils.js +23 -8
- package/build/modules/lwr/routerUtils/routerUtils.js +1 -1
- package/build/modules/lwr/routerUtils/typeUtils.js +1 -0
- package/build/modules/lwr/serverRouter/serverRouter.js +11 -11
- package/package.json +9 -9
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { getPathFromUrl, getQueryFromUrl, getQueryString, isParam, getParamName, getQueryNames, } from './uriUtils';
|
|
8
8
|
import { getPageReferenceFromUriAndRouteDef, matchRouteDefinitionByPageReference, getPathParams, getQueryParams, } from './routeDefUtils';
|
|
9
|
+
export const DEFAULT_I18N_ROUTER_CONFIG = {
|
|
10
|
+
locale: 'en-US',
|
|
11
|
+
defaultLocale: 'en-US',
|
|
12
|
+
};
|
|
9
13
|
/**
|
|
10
14
|
* Returns true if the given path & queryObj match the patterns (if any) defined in the routeDef
|
|
11
15
|
*
|
|
@@ -70,14 +74,22 @@ function getRouteDefinitionForUri(uri, routeDefs) {
|
|
|
70
74
|
* @param {string} url - URL string to turn into a route
|
|
71
75
|
* @param {array[object]} routeDefs - List of Route Definitions to match to the url
|
|
72
76
|
* @param {string} basePath - Optional: if provided, remove the base path before conversion.
|
|
77
|
+
* @param {object} i18n - Optional: if provided, remove the non-default locale before conversion.
|
|
73
78
|
*
|
|
74
79
|
* @returns {object}
|
|
75
80
|
*/
|
|
76
|
-
export function matchRouteByUrl(url, routeDefs, basePath = '') {
|
|
81
|
+
export function matchRouteByUrl(url, routeDefs, basePath = '', i18n = DEFAULT_I18N_ROUTER_CONFIG, options) {
|
|
77
82
|
// Pass in the rest of the URL for matching, without the prefix.
|
|
78
|
-
if (basePath && url
|
|
83
|
+
if (basePath && url?.indexOf(basePath) === 0) {
|
|
79
84
|
url = url.replace(basePath, '');
|
|
80
85
|
}
|
|
86
|
+
// Remove the locale
|
|
87
|
+
if (options?.locale || i18n?.locale) {
|
|
88
|
+
const localePath = `/${options?.locale || i18n.locale}`;
|
|
89
|
+
if (url?.indexOf(localePath) === 0) {
|
|
90
|
+
url = url.replace(localePath, '');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
81
93
|
// Parse the URL.
|
|
82
94
|
const routeDef = getRouteDefinitionForUri(url, routeDefs);
|
|
83
95
|
let matchInfo;
|
|
@@ -117,10 +129,10 @@ export function matchRouteByUrl(url, routeDefs, basePath = '') {
|
|
|
117
129
|
* @param basePath Base path for the url
|
|
118
130
|
* @returns the url or null if no match
|
|
119
131
|
*/
|
|
120
|
-
export function getUrlFromPageReference(pageReference, routeDefs, basePath = '') {
|
|
132
|
+
export function getUrlFromPageReference(pageReference, routeDefs, basePath = '', i18n = DEFAULT_I18N_ROUTER_CONFIG, options) {
|
|
121
133
|
const routeDef = matchRouteDefinitionByPageReference(pageReference, routeDefs);
|
|
122
134
|
if (routeDef) {
|
|
123
|
-
return getUrlFromPageReferenceAndRouteDef(pageReference, routeDef, basePath);
|
|
135
|
+
return getUrlFromPageReferenceAndRouteDef(pageReference, routeDef, basePath, i18n, options);
|
|
124
136
|
}
|
|
125
137
|
return null;
|
|
126
138
|
}
|
|
@@ -159,7 +171,7 @@ function extractBindingValues(parameters, pageReference, pageBindings) {
|
|
|
159
171
|
* @param routeDef routeDef to that defines how serialize the given pageReference
|
|
160
172
|
* @returns url for the given pageReference
|
|
161
173
|
*/
|
|
162
|
-
export function getUrlFromPageReferenceAndRouteDef(pageReference, routeDef, basePath = '') {
|
|
174
|
+
export function getUrlFromPageReferenceAndRouteDef(pageReference, routeDef, basePath = '', i18n = DEFAULT_I18N_ROUTER_CONFIG, options) {
|
|
163
175
|
const { params, original: { page = {} } = {}, toPath, compiledQuery } = routeDef;
|
|
164
176
|
const { attributes: attributeBindings = {}, state: stateBindings = {} } = page;
|
|
165
177
|
//
|
|
@@ -188,7 +200,9 @@ export function getUrlFromPageReferenceAndRouteDef(pageReference, routeDef, base
|
|
|
188
200
|
});
|
|
189
201
|
const queryObject = getQueryObjectForParametersAndPageReference(pageReference, queryParameters, routeDef);
|
|
190
202
|
const queryString = getQueryString(queryObject);
|
|
191
|
-
|
|
203
|
+
const locale = options?.locale || (i18n && i18n.locale);
|
|
204
|
+
const localePart = locale !== i18n.defaultLocale ? `/${locale}` : '';
|
|
205
|
+
return `${basePath}${localePart}${toPathUrl}${queryString}`;
|
|
192
206
|
}
|
|
193
207
|
/**
|
|
194
208
|
* Create a queryObject using the given pageReference, queryParameters, using the routeDef to specify
|
|
@@ -229,8 +243,8 @@ function getQueryObjectForParametersAndPageReference(pageReference, queryParamet
|
|
|
229
243
|
/**
|
|
230
244
|
* Obtains the pageReference for the given URL
|
|
231
245
|
*/
|
|
232
|
-
export function getPageReferenceFromUrl(url, routeDefs, basePath = '') {
|
|
233
|
-
const routingMatch = matchRouteByUrl(url, routeDefs, basePath);
|
|
246
|
+
export function getPageReferenceFromUrl(url, routeDefs, basePath = '', i18n = DEFAULT_I18N_ROUTER_CONFIG) {
|
|
247
|
+
const routingMatch = matchRouteByUrl(url, routeDefs, basePath, i18n);
|
|
234
248
|
if (routingMatch && routingMatch.route && routingMatch.route.pageReference) {
|
|
235
249
|
return routingMatch.route.pageReference;
|
|
236
250
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export { createFilterChain } from './filterUtils';
|
|
8
8
|
export { getPageReferenceFromUriAndRouteDef } from './routeDefUtils';
|
|
9
|
-
export { getUrlFromPageReference, getPageReferenceFromUrl, matchRouteByUrl, getUrlFromPageReferenceAndRouteDef, } from './routeUtils';
|
|
9
|
+
export { DEFAULT_I18N_ROUTER_CONFIG, getUrlFromPageReference, getPageReferenceFromUrl, matchRouteByUrl, getUrlFromPageReferenceAndRouteDef, } from './routeUtils';
|
|
10
10
|
export { isObject, freeze, guid, isValidRoute } from './typeUtils';
|
|
11
11
|
export { parseRoutes } from './parseUtils';
|
|
12
12
|
import { pathToRegexp as ptr, compile as ptrCompile } from './pathToRegexp';
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export { createFilterChain } from './filterUtils';
|
|
8
8
|
export { getPageReferenceFromUriAndRouteDef } from './routeDefUtils';
|
|
9
|
-
export { getUrlFromPageReference, getPageReferenceFromUrl, matchRouteByUrl, getUrlFromPageReferenceAndRouteDef, } from './routeUtils';
|
|
9
|
+
export { DEFAULT_I18N_ROUTER_CONFIG, getUrlFromPageReference, getPageReferenceFromUrl, matchRouteByUrl, getUrlFromPageReferenceAndRouteDef, } from './routeUtils';
|
|
10
10
|
export { isObject, freeze, guid, isValidRoute } from './typeUtils';
|
|
11
11
|
export { parseRoutes } from './parseUtils';
|
|
12
12
|
import { pathToRegexp as ptr, compile as ptrCompile } from './pathToRegexp';
|
|
@@ -7,33 +7,34 @@ export interface Constructable<T = object> {
|
|
|
7
7
|
constructor: Constructor<T>;
|
|
8
8
|
}
|
|
9
9
|
export type UrlMapper<TAddress> = {
|
|
10
|
-
generateUrl(address: TAddress): string | null;
|
|
10
|
+
generateUrl(address: TAddress, options?: NavigateOptions): string | null;
|
|
11
11
|
parseUrl(url: string): TAddress | null;
|
|
12
12
|
};
|
|
13
13
|
export type RouteMatcher<TAddress> = {
|
|
14
|
-
matchRoute(address: TAddress): RoutingMatch | null;
|
|
14
|
+
matchRoute(address: TAddress, options?: NavigateOptions): RoutingMatch | null;
|
|
15
15
|
};
|
|
16
16
|
export type ViewMapper<TAddress> = {
|
|
17
|
-
navigate(address: TAddress): void;
|
|
17
|
+
navigate(address: TAddress, options?: NavigateOptions): void;
|
|
18
18
|
subscribe(callback: RouteCallback, replay?: boolean): Unsubscriber;
|
|
19
19
|
resolveView(address: TAddress): Promise<RouteDestination>;
|
|
20
20
|
contextId?: ContextId;
|
|
21
21
|
};
|
|
22
22
|
export type Router<TAddress = string> = ViewMapper<TAddress> & UrlMapper<TAddress> & RouteMatcher<TAddress>;
|
|
23
|
-
export
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
export type RouterConfig = {
|
|
23
|
+
export type DEPRECATED_getRouteFromUrl<TAddress> = (url: string, defaultImpl: UrlMapper<TAddress>['parseUrl']) => TAddress | null;
|
|
24
|
+
export type DEPRECATED_getUrlFromRoute<TAddress> = (route: TAddress, defaultImpl: UrlMapper<TAddress>['generateUrl'], options?: NavigateOptions) => string | null;
|
|
25
|
+
export type I18nRouterConfig = {
|
|
26
|
+
locale: string;
|
|
27
|
+
defaultLocale: string;
|
|
28
|
+
};
|
|
29
|
+
export type RouterConfig<TAddress> = {
|
|
30
30
|
basePath?: string;
|
|
31
|
+
i18n?: I18nRouterConfig;
|
|
31
32
|
routes?: RouteDefinition[];
|
|
32
33
|
caseSensitive?: boolean;
|
|
33
|
-
DEPRECATED_getRouteFromUrl?: DEPRECATED_getRouteFromUrl
|
|
34
|
-
DEPRECATED_getUrlFromRoute?: DEPRECATED_getUrlFromRoute
|
|
34
|
+
DEPRECATED_getRouteFromUrl?: DEPRECATED_getRouteFromUrl<TAddress>;
|
|
35
|
+
DEPRECATED_getUrlFromRoute?: DEPRECATED_getUrlFromRoute<TAddress>;
|
|
35
36
|
};
|
|
36
|
-
export type RouterSerializationConfig<TAddress> = Required<Omit<RouterConfig
|
|
37
|
+
export type RouterSerializationConfig<TAddress> = Required<Omit<RouterConfig<TAddress>, 'DEPRECATED_getRouteFromUrl' | 'DEPRECATED_getUrlFromRoute'> & UrlMapper<TAddress>>;
|
|
37
38
|
export type RouteParameterPatterns = {
|
|
38
39
|
[paramName: string]: string;
|
|
39
40
|
};
|
|
@@ -129,5 +130,8 @@ export interface StringAttributes {
|
|
|
129
130
|
export interface NullableStringAttributes {
|
|
130
131
|
[key: string]: string | null;
|
|
131
132
|
}
|
|
133
|
+
export interface NavigateOptions {
|
|
134
|
+
locale?: string;
|
|
135
|
+
}
|
|
132
136
|
export {};
|
|
133
137
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -2,10 +2,11 @@ import type { RouteChange } from 'lwr/domRouterUtils';
|
|
|
2
2
|
import type { ContextId } from 'lwr/navigation';
|
|
3
3
|
import type { PageReference, Router, RouterConfig, RoutingMatch } from 'lwr/router';
|
|
4
4
|
import type { MessageObject } from 'lwr/routerUtils';
|
|
5
|
+
import type { NavigateOptions } from '../routerUtils/types';
|
|
5
6
|
type HandleNavFunction = (p: PageReference) => boolean;
|
|
6
7
|
type PreNavFunction = (r: RouteChange) => boolean | Promise<boolean>;
|
|
7
8
|
type ErrorNavFunction = (m: MessageObject) => void;
|
|
8
|
-
type ServerRouterConfig = RouterConfig & {
|
|
9
|
+
type ServerRouterConfig = RouterConfig<PageReference> & {
|
|
9
10
|
url?: string;
|
|
10
11
|
handleNavigation?: HandleNavFunction;
|
|
11
12
|
preNavigate?: PreNavFunction;
|
|
@@ -25,12 +26,12 @@ export declare class ServerRouter {
|
|
|
25
26
|
* Perform a hard navigation to the given page reference
|
|
26
27
|
* Client only!
|
|
27
28
|
*/
|
|
28
|
-
navigate(address: PageReference): Promise<void>;
|
|
29
|
+
navigate(address: PageReference, _replace?: boolean, options?: NavigateOptions): Promise<void>;
|
|
29
30
|
/**
|
|
30
31
|
* lightning/navigation
|
|
31
32
|
* Generate a URL based on the given page reference
|
|
32
33
|
*/
|
|
33
|
-
generateUrl(address: PageReference): string | null;
|
|
34
|
+
generateUrl(address: PageReference, options?: NavigateOptions): string | null;
|
|
34
35
|
/**
|
|
35
36
|
* Initialize the CurrentPageReference & NavigationContext wires plus the client-only NavigationMixin
|
|
36
37
|
* On the server, use the URL from the config
|
|
@@ -21,14 +21,14 @@ export class ServerRouter {
|
|
|
21
21
|
* Perform a hard navigation to the given page reference
|
|
22
22
|
* Client only!
|
|
23
23
|
*/
|
|
24
|
-
async navigate(address) {
|
|
24
|
+
async navigate(address, _replace, options) {
|
|
25
25
|
if (hasDocument) {
|
|
26
26
|
// invoke the handleNavigation hook, which intercepts the raw page ref
|
|
27
27
|
if (this.handleNavHook && !this.handleNavHook(address)) {
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
30
|
// continue navigating
|
|
31
|
-
const url = await this.getValidatedUrl(address);
|
|
31
|
+
const url = await this.getValidatedUrl(address, options);
|
|
32
32
|
if (url) {
|
|
33
33
|
// hard navigation
|
|
34
34
|
document.location.href = url;
|
|
@@ -39,8 +39,8 @@ export class ServerRouter {
|
|
|
39
39
|
* lightning/navigation
|
|
40
40
|
* Generate a URL based on the given page reference
|
|
41
41
|
*/
|
|
42
|
-
generateUrl(address) {
|
|
43
|
-
return this.router.generateUrl(address);
|
|
42
|
+
generateUrl(address, options) {
|
|
43
|
+
return this.router.generateUrl(address, options);
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
46
|
* Initialize the CurrentPageReference & NavigationContext wires plus the client-only NavigationMixin
|
|
@@ -59,7 +59,7 @@ export class ServerRouter {
|
|
|
59
59
|
}
|
|
60
60
|
url = this.getRelativeUrl(url);
|
|
61
61
|
// ensure the initial URL matches a valid route definition
|
|
62
|
-
const routingMatch = this.router.matchRoute(url);
|
|
62
|
+
const routingMatch = this.router.matchRoute(url, {});
|
|
63
63
|
if (!routingMatch) {
|
|
64
64
|
this.processError(generateMessageObject(messages.MISSING_ROUTE, [url]));
|
|
65
65
|
return;
|
|
@@ -67,9 +67,9 @@ export class ServerRouter {
|
|
|
67
67
|
this.currentRoute = routingMatch;
|
|
68
68
|
// set up the navigation context APIs
|
|
69
69
|
registerNavigationHelm(this.contextId, {
|
|
70
|
-
navigate: (address) => this.navigate(address),
|
|
71
|
-
generateUrl: (address) => this.generateUrl(address),
|
|
72
|
-
// the JS context is lost during hard
|
|
70
|
+
navigate: (address, replace, options) => this.navigate(address, replace, options),
|
|
71
|
+
generateUrl: (address, options) => this.generateUrl(address, options),
|
|
72
|
+
// the JS context is lost during hard navigation, so subscribing to route changes will not work
|
|
73
73
|
subscribe: () => {
|
|
74
74
|
throw new Error('The server router does not support the subscribe API');
|
|
75
75
|
},
|
|
@@ -102,9 +102,9 @@ export class ServerRouter {
|
|
|
102
102
|
/**
|
|
103
103
|
* Validate the page reference passed to the navigate API
|
|
104
104
|
*/
|
|
105
|
-
async getValidatedUrl(address) {
|
|
105
|
+
async getValidatedUrl(address, options) {
|
|
106
106
|
// match the URL to a route definition; fail if there is no match
|
|
107
|
-
const routingMatch = this.router.matchRoute(address);
|
|
107
|
+
const routingMatch = this.router.matchRoute(address, {});
|
|
108
108
|
if (!routingMatch) {
|
|
109
109
|
this.processError(generateMessageObject(messages.NO_ROUTE_MATCH, [JSON.stringify(address)]));
|
|
110
110
|
return;
|
|
@@ -119,7 +119,7 @@ export class ServerRouter {
|
|
|
119
119
|
this.processError(generateMessageObject(messages.PRENAV_FAILED, [JSON.stringify(address)]));
|
|
120
120
|
return;
|
|
121
121
|
}
|
|
122
|
-
return this.router.generateUrl(address);
|
|
122
|
+
return this.router.generateUrl(address, options);
|
|
123
123
|
}
|
|
124
124
|
/**
|
|
125
125
|
* Run the errorNavigate filters
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import type { I18nRouterConfig } from '../modules/lwr/routerUtils/types';
|
|
1
2
|
export declare const DEFAULT_SCHEMA = "pageReference_v1";
|
|
2
3
|
export interface LwrRouterConfig {
|
|
3
|
-
basePath?: string;
|
|
4
4
|
caseSensitive?: boolean;
|
|
5
5
|
routes: LwrConfigRouteDefinition[];
|
|
6
|
+
basePath?: string;
|
|
7
|
+
i18n?: I18nRouterConfig;
|
|
6
8
|
}
|
|
7
9
|
export interface LwrConfigRouteDefinition {
|
|
8
10
|
id: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AbstractModuleId, ModuleCompiled, ModuleEntry, ModuleProvider, ProviderContext } from '@lwrjs/types';
|
|
1
|
+
import type { AbstractModuleId, I18NConfig, ModuleCompiled, ModuleEntry, ModuleProvider, ProviderContext, RuntimeParams } from '@lwrjs/types';
|
|
2
2
|
interface RouterProviderOptions {
|
|
3
3
|
routesDir?: string;
|
|
4
4
|
}
|
|
@@ -7,16 +7,15 @@ export default class RouterModuleProvider implements ModuleProvider {
|
|
|
7
7
|
version: string;
|
|
8
8
|
routesDir: string;
|
|
9
9
|
appBasePath?: string;
|
|
10
|
-
|
|
10
|
+
i18n: I18NConfig;
|
|
11
11
|
private routerWatcher?;
|
|
12
|
-
private
|
|
13
|
-
private routerModuleCache;
|
|
12
|
+
private watchedFileSet;
|
|
14
13
|
constructor({ routesDir }: RouterProviderOptions, context: ProviderContext);
|
|
15
|
-
onRouterModuleChange(configPath: string
|
|
14
|
+
onRouterModuleChange(configPath: string): Promise<void>;
|
|
16
15
|
private watchConfigs;
|
|
17
16
|
private getRouterConfig;
|
|
18
|
-
getModuleEntry({ specifier }: AbstractModuleId): Promise<ModuleEntry | undefined>;
|
|
19
|
-
getModule(moduleId: AbstractModuleId): Promise<ModuleCompiled | undefined>;
|
|
17
|
+
getModuleEntry({ specifier }: AbstractModuleId, runtimeParams: RuntimeParams): Promise<ModuleEntry | undefined>;
|
|
18
|
+
getModule(moduleId: AbstractModuleId, runtimeParams: RuntimeParams): Promise<ModuleCompiled | undefined>;
|
|
20
19
|
}
|
|
21
20
|
export {};
|
|
22
21
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -5,13 +5,10 @@ const DEFAULT_DIR = '$rootDir/src/routes';
|
|
|
5
5
|
export default class RouterModuleProvider {
|
|
6
6
|
constructor({ routesDir = DEFAULT_DIR }, context) {
|
|
7
7
|
this.name = 'router-module-provider';
|
|
8
|
-
this.
|
|
9
|
-
|
|
10
|
-
// 1. Cache the Router Config JSON objects read from the file system, by config path (routerConfigJsonCache in ../index)
|
|
11
|
-
// 2. Cache the modules generated from the config, by config path
|
|
12
|
-
this.routerModuleCache = new Map();
|
|
13
|
-
const { appEmitter, config: { basePath, rootDir, contentDir, layoutsDir }, runtimeEnvironment: { lwrVersion, watchFiles }, watcherFactory, } = context;
|
|
8
|
+
this.watchedFileSet = new Set(); // <config path, module id>
|
|
9
|
+
const { config: { rootDir, contentDir, i18n, layoutsDir }, runtimeEnvironment: { lwrVersion, watchFiles }, watcherFactory, } = context;
|
|
14
10
|
this.version = lwrVersion;
|
|
11
|
+
this.i18n = i18n;
|
|
15
12
|
// Replace aliases and remove trailing slash from the routes directory
|
|
16
13
|
this.routesDir = normalizeResourcePath(routesDir, {
|
|
17
14
|
rootDir,
|
|
@@ -19,11 +16,7 @@ export default class RouterModuleProvider {
|
|
|
19
16
|
contentDir,
|
|
20
17
|
layoutsDir,
|
|
21
18
|
}).replace(/\/$/, '');
|
|
22
|
-
// Save the base path from the app config
|
|
23
|
-
// Note: The default basePath = ''
|
|
24
|
-
this.appBasePath = basePath ? basePath : undefined;
|
|
25
19
|
// Set up watcher on Router Config files
|
|
26
|
-
this.routerEmitter = appEmitter;
|
|
27
20
|
this.routerWatcher =
|
|
28
21
|
watchFiles && watcherFactory
|
|
29
22
|
? setUpWatcher(watcherFactory, this.onRouterModuleChange.bind(this))
|
|
@@ -31,38 +24,23 @@ export default class RouterModuleProvider {
|
|
|
31
24
|
}
|
|
32
25
|
// When Router Metadata changes on the file system:
|
|
33
26
|
// 1. delete the config data from the routerConfigJsonCache (in ../index)
|
|
34
|
-
|
|
35
|
-
// 3. recompile the module based on the new data and emit
|
|
36
|
-
async onRouterModuleChange(configPath, deleted = false) {
|
|
37
|
-
const moduleId = this.watchedFileMap.get(configPath);
|
|
38
|
-
if (!moduleId) {
|
|
39
|
-
throw new Error('We are observing an unprocessed Router Config file, this should not happen...');
|
|
40
|
-
}
|
|
27
|
+
async onRouterModuleChange(configPath) {
|
|
41
28
|
deleteRouterConfigJsonCacheEntry(configPath);
|
|
42
|
-
this.routerModuleCache.delete(configPath);
|
|
43
|
-
if (!deleted) {
|
|
44
|
-
const recompiledModule = await this.getModule(moduleId);
|
|
45
|
-
if (recompiledModule) {
|
|
46
|
-
this.routerEmitter.notifyModuleSourceChanged(recompiledModule);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
29
|
}
|
|
50
30
|
// Watch Router Config files:
|
|
51
31
|
// 1. Add files to the watcher
|
|
52
|
-
// 2. Track watched files in the
|
|
53
|
-
watchConfigs(
|
|
32
|
+
// 2. Track watched files in the watchedFileSet
|
|
33
|
+
watchConfigs(configPath) {
|
|
54
34
|
if (this.routerWatcher) {
|
|
55
|
-
|
|
56
|
-
if (!this.watchedFileMap.has(configPath)) {
|
|
35
|
+
if (!this.watchedFileSet.has(configPath)) {
|
|
57
36
|
this.routerWatcher.add(configPath);
|
|
37
|
+
this.watchedFileSet.add(configPath);
|
|
58
38
|
}
|
|
59
|
-
this.watchedFileMap.set(configPath, moduleId);
|
|
60
39
|
}
|
|
61
40
|
}
|
|
62
41
|
// 1. Check that:
|
|
63
42
|
// a. the specifier is in the correct format: "@lwrjs/router/{routerId}"
|
|
64
43
|
// b. the config JSON addressed by "routerId" is available on the file system
|
|
65
|
-
// 2. Maintain the Router Config cache
|
|
66
44
|
getRouterConfig(specifier) {
|
|
67
45
|
let config;
|
|
68
46
|
const routerId = parseSpecifier(specifier);
|
|
@@ -70,18 +48,16 @@ export default class RouterModuleProvider {
|
|
|
70
48
|
// Fetch the Router Config JSON
|
|
71
49
|
const configPath = getRouterConfigPath(this.routesDir, specifier);
|
|
72
50
|
config = getClientRoutes(configPath);
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
config.basePath = this.appBasePath;
|
|
76
|
-
}
|
|
51
|
+
// Watch for file changes
|
|
52
|
+
this.watchConfigs(configPath);
|
|
77
53
|
}
|
|
78
54
|
return config;
|
|
79
55
|
}
|
|
80
|
-
async getModuleEntry({ specifier }) {
|
|
56
|
+
async getModuleEntry({ specifier }, runtimeParams) {
|
|
81
57
|
const config = this.getRouterConfig(specifier);
|
|
82
58
|
if (config) {
|
|
83
59
|
return {
|
|
84
|
-
id: `${specifier}|${this.version}`,
|
|
60
|
+
id: `${specifier}|${this.version}|${runtimeParams.basePath}|${runtimeParams.locale}`,
|
|
85
61
|
virtual: true,
|
|
86
62
|
entry: `<virtual>/${specifier}.js`,
|
|
87
63
|
specifier,
|
|
@@ -89,21 +65,16 @@ export default class RouterModuleProvider {
|
|
|
89
65
|
};
|
|
90
66
|
}
|
|
91
67
|
}
|
|
92
|
-
async getModule(moduleId) {
|
|
68
|
+
async getModule(moduleId, runtimeParams) {
|
|
93
69
|
// Retrieve the Module Entry
|
|
94
70
|
const { specifier, namespace, name = specifier } = moduleId;
|
|
95
|
-
const moduleEntry = await this.getModuleEntry({ specifier });
|
|
71
|
+
const moduleEntry = await this.getModuleEntry({ specifier }, runtimeParams);
|
|
96
72
|
if (!moduleEntry) {
|
|
97
73
|
return;
|
|
98
74
|
}
|
|
99
|
-
// Check the module cache first
|
|
100
|
-
const configPath = getRouterConfigPath(this.routesDir, specifier);
|
|
101
|
-
if (this.routerModuleCache.has(configPath)) {
|
|
102
|
-
return this.routerModuleCache.get(configPath);
|
|
103
|
-
}
|
|
104
75
|
// Generate code for the requested module
|
|
105
76
|
const config = this.getRouterConfig(specifier);
|
|
106
|
-
const compiledSource = generateModule(config);
|
|
77
|
+
const compiledSource = generateModule(config, this.i18n, runtimeParams);
|
|
107
78
|
// Construct a Compiled Module
|
|
108
79
|
const moduleCompiled = {
|
|
109
80
|
id: moduleEntry.id,
|
|
@@ -116,9 +87,6 @@ export default class RouterModuleProvider {
|
|
|
116
87
|
ownHash: hashContent(compiledSource),
|
|
117
88
|
compiledSource,
|
|
118
89
|
};
|
|
119
|
-
// Watch Router Config file, add cache entries, and return
|
|
120
|
-
this.watchConfigs(specifier, moduleId);
|
|
121
|
-
this.routerModuleCache.set(configPath, moduleCompiled);
|
|
122
90
|
return moduleCompiled;
|
|
123
91
|
}
|
|
124
92
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Watcher } from '@lwrjs/types';
|
|
1
|
+
import type { I18NConfig, RuntimeParams, Watcher } from '@lwrjs/types';
|
|
2
2
|
import type { LwrRouterConfig } from '../index.js';
|
|
3
3
|
import type { WatcherFactory } from '@lwrjs/types';
|
|
4
4
|
export declare const SPECIFIER_PREFIX = "@lwrjs/router/";
|
|
@@ -23,5 +23,5 @@ export declare function setUpWatcher(factory: WatcherFactory, onModuleChange: (f
|
|
|
23
23
|
* Generate a module string which fulfills a router request
|
|
24
24
|
* @param routes - The array of route definitions
|
|
25
25
|
*/
|
|
26
|
-
export declare function generateModule(config
|
|
26
|
+
export declare function generateModule(config: LwrRouterConfig | undefined, { defaultLocale, uriPattern }: I18NConfig, runtimeParams: RuntimeParams): string;
|
|
27
27
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -43,10 +43,22 @@ function getHandlerClassName(specifier) {
|
|
|
43
43
|
*/
|
|
44
44
|
function generateHandlerClasses(routes) {
|
|
45
45
|
let handlerClasses = '';
|
|
46
|
-
|
|
46
|
+
const seenComponents = new Set();
|
|
47
|
+
const filteredAndDeDupedArray = routes.filter((item) => {
|
|
48
|
+
// Filter out entries without a component
|
|
49
|
+
if (!item.component)
|
|
50
|
+
return false;
|
|
51
|
+
// De-dupe entries with a component
|
|
52
|
+
if (!seenComponents.has(item.component)) {
|
|
53
|
+
seenComponents.add(item.component);
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
});
|
|
58
|
+
filteredAndDeDupedArray.forEach((r) => {
|
|
59
|
+
// filtered above
|
|
47
60
|
const component = r.component;
|
|
48
|
-
|
|
49
|
-
handlerClasses += `class ${getHandlerClassName(component)} {
|
|
61
|
+
handlerClasses += `class ${getHandlerClassName(component)} {
|
|
50
62
|
callback;
|
|
51
63
|
constructor(callback) {
|
|
52
64
|
this.callback = callback;
|
|
@@ -63,7 +75,6 @@ function generateHandlerClasses(routes) {
|
|
|
63
75
|
});
|
|
64
76
|
}
|
|
65
77
|
}\n`;
|
|
66
|
-
}
|
|
67
78
|
});
|
|
68
79
|
return handlerClasses;
|
|
69
80
|
}
|
|
@@ -96,15 +107,20 @@ function generateRouteDefinitions(routes) {
|
|
|
96
107
|
* Generate a module string which fulfills a router request
|
|
97
108
|
* @param routes - The array of route definitions
|
|
98
109
|
*/
|
|
99
|
-
export function generateModule(config = { routes: [] }) {
|
|
100
|
-
const {
|
|
110
|
+
export function generateModule(config = { routes: [] }, { defaultLocale, uriPattern }, runtimeParams) {
|
|
111
|
+
const { caseSensitive, routes: jsonRoutes } = config;
|
|
101
112
|
const csString = caseSensitive ? 'true' : 'false';
|
|
102
113
|
const routes = generateRouteDefinitions(jsonRoutes);
|
|
103
114
|
const handlers = generateHandlerClasses(jsonRoutes);
|
|
115
|
+
// Do we need to check basePath from router config?
|
|
116
|
+
const basePath = runtimeParams?.basePath || '';
|
|
117
|
+
const i18nRouterConfig = uriPattern === 'path-prefix'
|
|
118
|
+
? `${JSON.stringify({ locale: runtimeParams?.locale, defaultLocale })}`
|
|
119
|
+
: undefined;
|
|
104
120
|
return `import { createRouter as createLwrRouter } from 'lwr/router';
|
|
105
121
|
${handlers}
|
|
106
|
-
export function createRouter({ basePath = '${basePath}', caseSensitive = ${csString} } = {}) {
|
|
107
|
-
return createLwrRouter({ basePath, caseSensitive, routes: ${routes} });
|
|
122
|
+
export function createRouter({ basePath = '${basePath}', caseSensitive = ${csString}, DEPRECATED_getRouteFromUrl, DEPRECATED_getUrlFromRoute } = {}) {
|
|
123
|
+
return createLwrRouter({ basePath, caseSensitive, i18n: ${i18nRouterConfig}, routes: ${routes}, DEPRECATED_getRouteFromUrl, DEPRECATED_getUrlFromRoute });
|
|
108
124
|
}`;
|
|
109
125
|
}
|
|
110
126
|
//# sourceMappingURL=utils.js.map
|
|
@@ -92,5 +92,6 @@ export function generateContextualWireAdapter(contextInstance) {
|
|
|
92
92
|
// Adding the ts-ignore in case this code is compiled with a version of LWC that is older than 4.0.
|
|
93
93
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
94
94
|
// @ts-ignore
|
|
95
|
+
|
|
95
96
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
96
97
|
// @ts-ignore
|
|
@@ -134,7 +134,7 @@ export class DomRouterImpl {
|
|
|
134
134
|
});
|
|
135
135
|
const contextApi = {
|
|
136
136
|
navigate: (address, replace) => this.navigate(address, replace),
|
|
137
|
-
generateUrl: address => this.generateUrl(address),
|
|
137
|
+
generateUrl: (address, options) => this.generateUrl(address, options),
|
|
138
138
|
subscribe: (callback, replay) => this.subscribe(callback, replay)
|
|
139
139
|
};
|
|
140
140
|
registerNavigationHelm(this.contextId, contextApi);
|
|
@@ -262,10 +262,11 @@ export class DomRouterImpl {
|
|
|
262
262
|
* After processing, delegate to a child router, if it exists.
|
|
263
263
|
*
|
|
264
264
|
* @param {string} url - Relative URL string to process
|
|
265
|
+
* @param {NavigateOptions} options - Additional navigation options (i.e. switch root locale)
|
|
265
266
|
* @returns {boolean} - True if the processing was NOT blocked by a preNavigate listener
|
|
266
267
|
*/
|
|
267
268
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
268
|
-
async process(url,
|
|
269
|
+
async process(url, _shouldReplace, options, _updateHistory) {
|
|
269
270
|
// Mark the navigation event here instead of in navigate()
|
|
270
271
|
// This way, we catch ALL navigation events, since they all must go through process():
|
|
271
272
|
// 1. A component calls navigate()
|
|
@@ -281,7 +282,7 @@ export class DomRouterImpl {
|
|
|
281
282
|
// Run the root -> leaf chain of pre navigate filters, if this is the root.
|
|
282
283
|
try {
|
|
283
284
|
if (!this.parent) {
|
|
284
|
-
await this.preProcess(url);
|
|
285
|
+
await this.preProcess(url, options);
|
|
285
286
|
}
|
|
286
287
|
} catch (e) {
|
|
287
288
|
if (e.code) {
|
|
@@ -295,7 +296,7 @@ export class DomRouterImpl {
|
|
|
295
296
|
// trigger the child to navigate afterwards
|
|
296
297
|
const address = this.router.parseUrl(url);
|
|
297
298
|
if (address) {
|
|
298
|
-
this.router.navigate(address);
|
|
299
|
+
this.router.navigate(address, options);
|
|
299
300
|
}
|
|
300
301
|
return true;
|
|
301
302
|
}
|
|
@@ -309,9 +310,9 @@ export class DomRouterImpl {
|
|
|
309
310
|
*
|
|
310
311
|
* @returns {Promise<boolean>} - Resolves to true if successful
|
|
311
312
|
*/
|
|
312
|
-
preProcess(url) {
|
|
313
|
+
preProcess(url, options) {
|
|
313
314
|
const address = this.router.parseUrl(url);
|
|
314
|
-
const routingMatch = address && this.router.matchRoute(address);
|
|
315
|
+
const routingMatch = address && this.router.matchRoute(address, options);
|
|
315
316
|
|
|
316
317
|
// Check that the URL has a matching route, otherwise it is an error.
|
|
317
318
|
if (!routingMatch) {
|
|
@@ -363,9 +364,11 @@ export class DomRouterImpl {
|
|
|
363
364
|
* @param {*} options - Usually a boolean; when true the previous browser history
|
|
364
365
|
* entry should be replaced by this one
|
|
365
366
|
*/
|
|
366
|
-
navigate(address, replace) {
|
|
367
|
+
navigate(address, replace, options) {
|
|
368
|
+
const routerOptions = this.filterNavigateOptions(options);
|
|
369
|
+
|
|
367
370
|
// Ensure there is a string URL to pass to the navigation event.
|
|
368
|
-
let url = this.router.generateUrl(address);
|
|
371
|
+
let url = this.router.generateUrl(address, routerOptions);
|
|
369
372
|
if (url) {
|
|
370
373
|
// If this router is a child, we need to prepend the parent's matching portion
|
|
371
374
|
// of the url before sending the navigate event up
|
|
@@ -390,8 +393,9 @@ export class DomRouterImpl {
|
|
|
390
393
|
*
|
|
391
394
|
* @returns {Promise<string>}
|
|
392
395
|
*/
|
|
393
|
-
generateUrl(address) {
|
|
394
|
-
const
|
|
396
|
+
generateUrl(address, options) {
|
|
397
|
+
const routerOptions = this.filterNavigateOptions(options);
|
|
398
|
+
const url = this.router.generateUrl(address, routerOptions);
|
|
395
399
|
|
|
396
400
|
// Invalid addresses need to return null to indicate they are invalid
|
|
397
401
|
if (!url) {
|
|
@@ -482,6 +486,19 @@ export class DomRouterImpl {
|
|
|
482
486
|
}
|
|
483
487
|
return url;
|
|
484
488
|
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Filter the navigate options based on if this is a root router or not.
|
|
492
|
+
*/
|
|
493
|
+
filterNavigateOptions(options) {
|
|
494
|
+
const isRoot = !this.parent;
|
|
495
|
+
const routerOptions = {
|
|
496
|
+
...options,
|
|
497
|
+
// Only allow switch locales if this is a root router
|
|
498
|
+
locale: isRoot ? options?.locale : undefined
|
|
499
|
+
};
|
|
500
|
+
return routerOptions;
|
|
501
|
+
}
|
|
485
502
|
}
|
|
486
503
|
|
|
487
504
|
/**
|
|
@@ -50,9 +50,9 @@ export class HistoryRouter extends DomRouterImpl {
|
|
|
50
50
|
*
|
|
51
51
|
* @returns {boolean} - True if the processing was NOT blocked by a preNavigate listener
|
|
52
52
|
*/
|
|
53
|
-
async process(url, shouldReplace, updateHistory = true) {
|
|
53
|
+
async process(url, shouldReplace, options, updateHistory = true) {
|
|
54
54
|
// Run the preNavigate hooks to check if this event should be processed.
|
|
55
|
-
const canContinue = await super.process(url);
|
|
55
|
+
const canContinue = await super.process(url, shouldReplace, options, updateHistory);
|
|
56
56
|
|
|
57
57
|
// Update the window location if this router is connected and is the root router
|
|
58
58
|
if (canContinue && !this.historyDisabled && updateHistory && this.connected && !this.parent) {
|
|
@@ -73,13 +73,13 @@ export class HistoryRouter extends DomRouterImpl {
|
|
|
73
73
|
* @param {string} url - The URL to go to
|
|
74
74
|
*/
|
|
75
75
|
catchBrowserUpdate(url) {
|
|
76
|
-
this.process(url, false, false);
|
|
76
|
+
this.process(url, false, {}, false);
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
/**
|
|
81
81
|
* Create a new root Router, attach to the Window.
|
|
82
|
-
* This is the public,
|
|
82
|
+
* This is the public, programmatic API for root router creation.
|
|
83
83
|
* An application can only have ONE root router.
|
|
84
84
|
*
|
|
85
85
|
* @param {object} config - The router config object
|