@aurelia/router-lite
Advanced tools
Comparing version 2.0.0-alpha.34 to 2.0.0-alpha.35
@@ -7,3 +7,3 @@ export { type IViewport, } from './resources/viewport'; | ||
export { type Routeable, type IRouteConfig, type IChildRouteConfig, RouteConfig, Route, type RouteType, route, } from './route'; | ||
export { IRouteContext, RouteContext, } from './route-context'; | ||
export { IRouteContext, RouteContext, type INavigationModel, type INavigationRoute, } from './route-context'; | ||
export { RouteDefinition, } from './route-definition'; | ||
@@ -10,0 +10,0 @@ export { AST, RouteExpression, CompositeSegmentExpression, ScopedSegmentExpression, SegmentGroupExpression, SegmentExpression, ComponentExpression, ActionExpression, ViewportExpression, ParameterListExpression, ParameterExpression, ExpressionKind, } from './route-expression'; |
@@ -8,4 +8,5 @@ import { IContainer, IModule } from '@aurelia/kernel'; | ||
import { RouteNode } from './route-tree'; | ||
import { ResolutionMode } from './router'; | ||
import { IRouter, ResolutionMode } from './router'; | ||
import { IViewport } from './resources/viewport'; | ||
import { Params } from './instructions'; | ||
export interface IRouteContext extends RouteContext { | ||
@@ -64,3 +65,5 @@ } | ||
private _childRoutesConfigured; | ||
constructor(viewportAgent: ViewportAgent | null, parent: IRouteContext | null, component: CustomElementDefinition, definition: RouteDefinition, parentContainer: IContainer); | ||
private readonly _navigationModel; | ||
get navigationModel(): INavigationModel; | ||
constructor(viewportAgent: ViewportAgent | null, parent: IRouteContext | null, component: CustomElementDefinition, definition: RouteDefinition, parentContainer: IContainer, router: IRouter); | ||
private processDefinition; | ||
@@ -102,2 +105,20 @@ /** | ||
} | ||
export declare const INavigationModel: import("@aurelia/kernel").InterfaceSymbol<INavigationModel>; | ||
export interface INavigationModel { | ||
/** | ||
* Collection of routes. | ||
*/ | ||
readonly routes: readonly INavigationRoute[]; | ||
/** | ||
* Wait for async route configurations. | ||
*/ | ||
resolve(): Promise<void> | void; | ||
} | ||
export interface INavigationRoute { | ||
readonly id: string; | ||
readonly path: string[]; | ||
readonly title: string | ((node: RouteNode) => string | null) | null; | ||
readonly data: Params | null; | ||
readonly isActive: boolean; | ||
} | ||
//# sourceMappingURL=route-context.d.ts.map |
@@ -69,3 +69,5 @@ import { ILogger } from '@aurelia/kernel'; | ||
private constructor(); | ||
static create(input: IRouteNode): RouteNode; | ||
static create(input: IRouteNode & { | ||
originalInstruction?: ViewportInstruction<ITypedNavigationInstruction_ResolvedComponent> | null; | ||
}): RouteNode; | ||
contains(instructions: ViewportInstructionTree): boolean; | ||
@@ -72,0 +74,0 @@ appendChild(child: RouteNode): void; |
@@ -69,2 +69,8 @@ import { Constructable, ResourceType } from '@aurelia/kernel'; | ||
readonly fallback?: string | null; | ||
/** | ||
* When set to `false`, the routes won't be included in the navigation model. | ||
* | ||
* @default true | ||
*/ | ||
readonly nav?: boolean; | ||
} | ||
@@ -94,3 +100,4 @@ export interface IChildRouteConfig extends IRouteConfig { | ||
readonly component: Routeable; | ||
protected constructor(id: string | null, path: string | string[] | null, title: string | ((node: RouteNode) => string | null) | null, redirectTo: string | null, caseSensitive: boolean, transitionPlan: TransitionPlanOrFunc, viewport: string | null, data: Params, routes: readonly Routeable[], fallback: string | null, component: Routeable); | ||
readonly nav: boolean; | ||
protected constructor(id: string | null, path: string | string[] | null, title: string | ((node: RouteNode) => string | null) | null, redirectTo: string | null, caseSensitive: boolean, transitionPlan: TransitionPlanOrFunc, viewport: string | null, data: Params, routes: readonly Routeable[], fallback: string | null, component: Routeable, nav: boolean); | ||
static create(configOrPath: IRouteConfig | IChildRouteConfig | string | string[], Type: RouteType | null): RouteConfig; | ||
@@ -97,0 +104,0 @@ /** |
@@ -183,2 +183,4 @@ import { IContainer, ILogger } from '@aurelia/kernel'; | ||
private locationChangeSubscription; | ||
private _isNavigating; | ||
get isNavigating(): boolean; | ||
constructor(container: IContainer, p: IPlatform, logger: ILogger, events: IRouterEvents, locationMgr: ILocationManager); | ||
@@ -185,0 +187,0 @@ /** |
@@ -17,17 +17,2 @@ import { RouteNode } from './route-tree'; | ||
} | ||
/** | ||
* Normalize an array of potential promises, to ensure things stay synchronous when they can. | ||
* | ||
* If exactly one value is a promise, then that promise is returned. | ||
* | ||
* If more than one value is a promise, a new `Promise.all` is returned. | ||
* | ||
* If none of the values is a promise, nothing is returned, to indicate that things can stay synchronous. | ||
*/ | ||
export declare function resolveAll(maybePromises: (void | Promise<void>)[]): void | Promise<void>; | ||
export declare type ExposedPromise<T> = Promise<T> & { | ||
resolve(value?: T): void; | ||
reject(reason?: unknown): void; | ||
}; | ||
export declare function createExposedPromise<T>(): ExposedPromise<T>; | ||
export declare function mergeDistinct(prev: RouteNode[], next: RouteNode[]): RouteNode[]; | ||
@@ -34,0 +19,0 @@ export declare function tryStringify(value: unknown): string; |
{ | ||
"name": "@aurelia/router-lite", | ||
"version": "2.0.0-alpha.34", | ||
"version": "2.0.0-alpha.35", | ||
"main": "dist/cjs/index.cjs", | ||
@@ -47,12 +47,12 @@ "module": "dist/esm/index.mjs", | ||
"dependencies": { | ||
"@aurelia/kernel": "2.0.0-alpha.34", | ||
"@aurelia/metadata": "2.0.0-alpha.34", | ||
"@aurelia/platform": "2.0.0-alpha.34", | ||
"@aurelia/platform-browser": "2.0.0-alpha.34", | ||
"@aurelia/route-recognizer": "2.0.0-alpha.34", | ||
"@aurelia/runtime": "2.0.0-alpha.34", | ||
"@aurelia/runtime-html": "2.0.0-alpha.34" | ||
"@aurelia/kernel": "2.0.0-alpha.35", | ||
"@aurelia/metadata": "2.0.0-alpha.35", | ||
"@aurelia/platform": "2.0.0-alpha.35", | ||
"@aurelia/platform-browser": "2.0.0-alpha.35", | ||
"@aurelia/route-recognizer": "2.0.0-alpha.35", | ||
"@aurelia/runtime": "2.0.0-alpha.35", | ||
"@aurelia/runtime-html": "2.0.0-alpha.35" | ||
}, | ||
"devDependencies": { | ||
"typescript": "4.7.2" | ||
"typescript": "4.7.3" | ||
}, | ||
@@ -59,0 +59,0 @@ "engines": { |
@@ -48,2 +48,4 @@ export { | ||
RouteContext, | ||
type INavigationModel, | ||
type INavigationRoute, | ||
} from './route-context'; | ||
@@ -50,0 +52,0 @@ |
@@ -14,2 +14,4 @@ import { IContainer, ResourceDefinition, DI, InstanceProvider, Registration, ILogger, IModuleLoader, IModule, onResolve, noop } from '@aurelia/kernel'; | ||
import { ensureArrayOfStrings } from './util'; | ||
import { Params } from './instructions'; | ||
import { IRouterEvents } from './router-events'; | ||
@@ -117,2 +119,7 @@ export interface IRouteContext extends RouteContext {} | ||
private readonly _navigationModel: NavigationModel; | ||
public get navigationModel(): INavigationModel { | ||
return this._navigationModel; | ||
} | ||
public constructor( | ||
@@ -124,2 +131,3 @@ viewportAgent: ViewportAgent | null, | ||
public readonly parentContainer: IContainer, | ||
router: IRouter, | ||
) { | ||
@@ -158,2 +166,10 @@ this._vpa = viewportAgent; | ||
this.recognizer = new RouteRecognizer(); | ||
const navModel = this._navigationModel = new NavigationModel([]); | ||
// Note that routing-contexts have the same lifetime as the app itself; therefore, an attempt to dispose the subscription is kind of useless. | ||
// Also considering that in a realistic app the number of configured routes are limited in number, this subscription and keeping the routes' active property in sync should not create much issue. | ||
// If need be we can optimize it later. | ||
container | ||
.get(IRouterEvents) | ||
.subscribe('au:router:navigation-end', () => navModel.setIsActive(router, this)); | ||
this.processDefinition(definition); | ||
@@ -172,2 +188,3 @@ } | ||
} | ||
const navModel = this._navigationModel; | ||
let i = 0; | ||
@@ -192,2 +209,3 @@ for (; i < len; i++) { | ||
this.childRoutes.push(p); | ||
navModel.addRoute(p); | ||
allPromises.push(p.then(noop)); | ||
@@ -202,2 +220,3 @@ } else { | ||
this.childRoutes.push(routeDef); | ||
navModel.addRoute(routeDef); | ||
} | ||
@@ -400,2 +419,3 @@ } | ||
} | ||
this._navigationModel.addRoute(routeDef); | ||
this.childRoutes.push(routeDef); | ||
@@ -486,1 +506,94 @@ }); | ||
} | ||
export const INavigationModel = DI.createInterface<INavigationModel>('INavigationModel'); | ||
export interface INavigationModel { | ||
/** | ||
* Collection of routes. | ||
*/ | ||
readonly routes: readonly INavigationRoute[]; | ||
/** | ||
* Wait for async route configurations. | ||
*/ | ||
resolve(): Promise<void> | void; | ||
} | ||
// Usage of classical interface pattern is intentional. | ||
class NavigationModel implements INavigationModel { | ||
private _promise: Promise<void> | void = void 0; | ||
public constructor( | ||
public readonly routes: NavigationRoute[], | ||
) { } | ||
public resolve(): Promise<void> | void { | ||
return onResolve(this._promise, noop); | ||
} | ||
/** @internal */ | ||
public setIsActive(router: IRouter, context: IRouteContext): void { | ||
for (const route of this.routes) { | ||
route.setIsActive(router, context); | ||
} | ||
} | ||
/** @internal */ | ||
public addRoute(routeDef: RouteDefinition | Promise<RouteDefinition>): void { | ||
const routes = this.routes; | ||
if (!(routeDef instanceof Promise)) { | ||
if (routeDef.config.nav) { | ||
routes.push(NavigationRoute.create(routeDef)); | ||
} | ||
return; | ||
} | ||
const index = routes.length; | ||
routes.push((void 0)!); // reserve the slot | ||
let promise: void | Promise<void> = void 0; | ||
promise = this._promise = onResolve(this._promise, () => | ||
onResolve(routeDef, $routeDef => { | ||
if ($routeDef.config.nav) { | ||
routes[index] = NavigationRoute.create($routeDef); | ||
} else { | ||
routes.splice(index, 1); | ||
} | ||
if (this._promise === promise) { | ||
this._promise = void 0; | ||
} | ||
}) | ||
); | ||
} | ||
} | ||
export interface INavigationRoute { | ||
readonly id: string; | ||
readonly path: string[]; | ||
readonly title: string | ((node: RouteNode) => string | null) | null; | ||
readonly data: Params | null; | ||
readonly isActive: boolean; | ||
} | ||
// Usage of classical interface pattern is intentional. | ||
class NavigationRoute implements INavigationRoute { | ||
private _isActive!: boolean; | ||
private constructor( | ||
public readonly id: string, | ||
public readonly path: string[], | ||
public readonly title: string | ((node: RouteNode) => string | null) | null, | ||
public readonly data: Params | null, | ||
) { } | ||
/** @internal */ | ||
public static create(routeDef: RouteDefinition) { | ||
return new NavigationRoute( | ||
routeDef.id, | ||
routeDef.path, | ||
routeDef.config.title, | ||
routeDef.data, | ||
); | ||
} | ||
public get isActive(): boolean { | ||
return this._isActive; | ||
} | ||
/** @internal */ | ||
public setIsActive(router: IRouter, context: IRouteContext): void { | ||
this._isActive = this.path.some(path => router.isActive(path, context)); | ||
} | ||
} |
@@ -128,6 +128,6 @@ import { | ||
) { | ||
this.originalInstruction = instruction; | ||
this.originalInstruction ??= instruction; | ||
} | ||
public static create(input: IRouteNode): RouteNode { | ||
public static create(input: IRouteNode & { originalInstruction?: ViewportInstruction<ITypedNavigationInstruction_ResolvedComponent> | null }): RouteNode { | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
@@ -140,3 +140,3 @@ const { [RESIDUE]: _, ...params } = input.params ?? {}; | ||
/* context */input.context, | ||
/* originalIns */input.instruction, | ||
/* originalIns */input.originalInstruction ?? input.instruction, | ||
/* instruction */input.instruction, | ||
@@ -162,3 +162,3 @@ /* params */params, | ||
for (let j = 0, jj = instructionChildren.length; j < jj; ++j) { | ||
if (i + j < ii && (nodeChildren[i + j].instruction?.contains(instructionChildren[j]) ?? false)) { | ||
if (i + j < ii && (nodeChildren[i + j].originalInstruction?.contains(instructionChildren[j]) ?? false)) { | ||
if (j + 1 === jj) { | ||
@@ -453,17 +453,18 @@ return true; | ||
return onResolve( | ||
resolveAll( | ||
...node.residue.splice(0).map(vi => { | ||
return createAndAppendNodes(log, node, vi, node.append); | ||
}), | ||
...ctx.getAvailableViewportAgents('dynamic').map(vpa => { | ||
const defaultInstruction = ViewportInstruction.create({ | ||
component: vpa.viewport.default, | ||
viewport: vpa.viewport.name, | ||
}); | ||
return createAndAppendNodes(log, node, defaultInstruction, node.append); | ||
}), | ||
resolveAll(...node | ||
.residue | ||
.splice(0) | ||
.map(vi => createAndAppendNodes(log, node, vi, node.append))), | ||
() => onResolve( | ||
resolveAll(...ctx | ||
.getAvailableViewportAgents('dynamic') | ||
.map(vpa => { | ||
const defaultInstruction = ViewportInstruction.create({ | ||
component: vpa.viewport.default, | ||
viewport: vpa.viewport.name, | ||
}); | ||
return createAndAppendNodes(log, node, defaultInstruction, node.append); | ||
})), | ||
() => node.children.filter(x => !existingChildren.includes(x)) | ||
), | ||
() => { | ||
return node.children.filter(x => !existingChildren.includes(x)); | ||
}, | ||
); | ||
@@ -516,3 +517,3 @@ }); | ||
null); | ||
const childNode = createConfiguredNode(log, node, vi as ViewportInstruction<ITypedNavigationInstruction_ResolvedComponent>, append, rr); | ||
const childNode = createConfiguredNode(log, node, vi as ViewportInstruction<ITypedNavigationInstruction_ResolvedComponent>, append, rr, null); | ||
return appendNode(log, node, childNode); | ||
@@ -531,2 +532,3 @@ } | ||
let collapse: number = 0; | ||
const originalInstruction = vi.clone(); | ||
let path = vi.component.value; | ||
@@ -570,3 +572,3 @@ let cur = vi as ViewportInstruction; | ||
const rr = ctx.recognize(fallback, true); | ||
if (rr !== null) return createConfiguredNode(log, node, vi as ViewportInstruction<ITypedNavigationInstruction_ResolvedComponent>, append, rr); | ||
if (rr !== null) return createConfiguredNode(log, node, vi as ViewportInstruction<ITypedNavigationInstruction_ResolvedComponent>, append, rr, null); | ||
@@ -590,3 +592,3 @@ // fallback is not recognized as a configured route; treat as CE and look for a route definition. | ||
log.trace('createNode after adjustment vi:%s', vi); | ||
return createConfiguredNode(log, node, vi, append, rr); | ||
return createConfiguredNode(log, node, vi, append, rr, originalInstruction); | ||
} | ||
@@ -600,2 +602,3 @@ | ||
rr: $RecognizedRoute, | ||
originalVi: ViewportInstruction<ITypedNavigationInstruction_ResolvedComponent> | null, | ||
route: ConfigurableRoute<RouteDefinition | Promise<RouteDefinition>> = rr.route.endpoint.route, | ||
@@ -630,2 +633,3 @@ ): RouteNode | Promise<RouteNode> { | ||
instruction: vi, | ||
originalInstruction: originalVi, | ||
params: { | ||
@@ -734,3 +738,3 @@ ...node.params, | ||
return createConfiguredNode(log, node, vi, append, rr, redirRR.route.endpoint.route); | ||
return createConfiguredNode(log, node, vi, append, rr, originalVi, redirRR.route.endpoint.route); | ||
}); | ||
@@ -774,3 +778,3 @@ } | ||
vi.children.length = 0; | ||
return createConfiguredNode(log, node, vi as ViewportInstruction<ITypedNavigationInstruction_ResolvedComponent>, append, rr); | ||
return createConfiguredNode(log, node, vi as ViewportInstruction<ITypedNavigationInstruction_ResolvedComponent>, append, rr, null); | ||
} |
@@ -77,2 +77,8 @@ import { Metadata } from '@aurelia/metadata'; | ||
readonly fallback?: string | null; | ||
/** | ||
* When set to `false`, the routes won't be included in the navigation model. | ||
* | ||
* @default true | ||
*/ | ||
readonly nav?: boolean; | ||
} | ||
@@ -111,2 +117,3 @@ export interface IChildRouteConfig extends IRouteConfig { | ||
public readonly component: Routeable, | ||
public readonly nav: boolean, | ||
) { } | ||
@@ -139,2 +146,3 @@ | ||
null!, // TODO(sayan): find a TS-wise clearer way to deal with this. | ||
Type?.nav ?? true, | ||
); | ||
@@ -172,2 +180,3 @@ } else if (typeof configOrPath === 'object') { | ||
(config as IChildRouteConfig).component ?? null, | ||
config.nav ?? true, | ||
); | ||
@@ -201,2 +210,3 @@ } else { | ||
config.component ?? this.component, | ||
config.nav ?? this.nav, | ||
); | ||
@@ -203,0 +213,0 @@ } |
@@ -380,2 +380,7 @@ import { isObject } from '@aurelia/metadata'; | ||
private _isNavigating: boolean = false; | ||
public get isNavigating(): boolean { | ||
return this._isNavigating; | ||
} | ||
public constructor( | ||
@@ -594,2 +599,3 @@ @IContainer private readonly container: IContainer, | ||
container, | ||
this, | ||
), | ||
@@ -746,2 +752,3 @@ ); | ||
this._isNavigating = true; | ||
this.events.publish(new NavigationStartEvent(tr.id, tr.instructions, tr.trigger, tr.managedState)); | ||
@@ -820,2 +827,3 @@ | ||
this.instructions = tr.finalInstructions = tr.routeTree.finalizeInstructions(); | ||
this._isNavigating = false; | ||
this.events.publish(new NavigationEndEvent(tr.id, tr.instructions, this.instructions)); | ||
@@ -881,2 +889,3 @@ | ||
this._routeTree = tr.previousRouteTree; | ||
this._isNavigating = false; | ||
this.events.publish(new NavigationCancelEvent(tr.id, tr.instructions, `guardsResult is ${tr.guardsResult}`)); | ||
@@ -883,0 +892,0 @@ |
@@ -64,46 +64,2 @@ import { RouteNode } from './route-tree'; | ||
/** | ||
* Normalize an array of potential promises, to ensure things stay synchronous when they can. | ||
* | ||
* If exactly one value is a promise, then that promise is returned. | ||
* | ||
* If more than one value is a promise, a new `Promise.all` is returned. | ||
* | ||
* If none of the values is a promise, nothing is returned, to indicate that things can stay synchronous. | ||
*/ | ||
export function resolveAll(maybePromises: (void | Promise<void>)[]): void | Promise<void> { | ||
const promises: Promise<void>[] = []; | ||
for (const maybePromise of maybePromises) { | ||
if (maybePromise instanceof Promise) { | ||
promises.push(maybePromise); | ||
} | ||
} | ||
switch (promises.length) { | ||
case 0: | ||
return; | ||
case 1: | ||
return promises[0]; | ||
default: | ||
return Promise.all(promises) as unknown as Promise<void>; | ||
} | ||
} | ||
export type ExposedPromise<T> = Promise<T> & { | ||
resolve(value?: T): void; | ||
reject(reason?: unknown): void; | ||
}; | ||
export function createExposedPromise<T>(): ExposedPromise<T> { | ||
let $resolve: (value?: T) => void = (void 0)!; | ||
let $reject: (reason?: unknown) => void = (void 0)!; | ||
const promise = new Promise<void | T>(function (resolve, reject) { | ||
$resolve = resolve; | ||
$reject = reject; | ||
}) as ExposedPromise<T>; | ||
promise.resolve = $resolve; | ||
promise.reject = $reject; | ||
return promise; | ||
} | ||
export function mergeDistinct(prev: RouteNode[], next: RouteNode[]): RouteNode[] { | ||
@@ -110,0 +66,0 @@ prev = prev.slice(); |
@@ -86,2 +86,3 @@ import { IIndexable } from '@aurelia/kernel'; | ||
case 'caseSensitive': | ||
case 'nav': | ||
if (typeof value !== 'boolean') { | ||
@@ -88,0 +89,0 @@ expectType('boolean', path, value); |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1958193
30859
+ Added@aurelia/kernel@2.0.0-alpha.35(transitive)
+ Added@aurelia/metadata@2.0.0-alpha.35(transitive)
+ Added@aurelia/platform@2.0.0-alpha.35(transitive)
+ Added@aurelia/platform-browser@2.0.0-alpha.35(transitive)
+ Added@aurelia/route-recognizer@2.0.0-alpha.35(transitive)
+ Added@aurelia/runtime@2.0.0-alpha.35(transitive)
+ Added@aurelia/runtime-html@2.0.0-alpha.35(transitive)
- Removed@aurelia/kernel@2.0.0-alpha.34(transitive)
- Removed@aurelia/metadata@2.0.0-alpha.34(transitive)
- Removed@aurelia/platform@2.0.0-alpha.34(transitive)
- Removed@aurelia/platform-browser@2.0.0-alpha.34(transitive)
- Removed@aurelia/route-recognizer@2.0.0-alpha.34(transitive)
- Removed@aurelia/runtime@2.0.0-alpha.34(transitive)
- Removed@aurelia/runtime-html@2.0.0-alpha.34(transitive)