fix(router): handle urls with only secondary top-level segments
This commit is contained in:
parent
31a7709ece
commit
44709e0dca
|
@ -41,8 +41,9 @@ class InheritedFromParent {
|
||||||
export function recognize(rootComponentType: Type, config: Routes, urlTree: UrlTree, url: string):
|
export function recognize(rootComponentType: Type, config: Routes, urlTree: UrlTree, url: string):
|
||||||
Observable<RouterStateSnapshot> {
|
Observable<RouterStateSnapshot> {
|
||||||
try {
|
try {
|
||||||
|
const rootSegment = split(urlTree.root, [], [], config).segment;
|
||||||
const children =
|
const children =
|
||||||
processSegment(config, urlTree.root, InheritedFromParent.empty(null), PRIMARY_OUTLET);
|
processSegment(config, rootSegment, InheritedFromParent.empty(null), PRIMARY_OUTLET);
|
||||||
const root = new ActivatedRouteSnapshot(
|
const root = new ActivatedRouteSnapshot(
|
||||||
[], Object.freeze({}), {}, PRIMARY_OUTLET, rootComponentType, null, urlTree.root, -1,
|
[], Object.freeze({}), {}, PRIMARY_OUTLET, rootComponentType, null, urlTree.root, -1,
|
||||||
InheritedResolve.empty);
|
InheritedResolve.empty);
|
||||||
|
@ -127,6 +128,8 @@ function processPathsWithParamsAgainstRoute(
|
||||||
const childConfig = getChildConfig(route);
|
const childConfig = getChildConfig(route);
|
||||||
|
|
||||||
const {segment, slicedPath} = split(rawSegment, consumedPaths, rawSlicedPath, childConfig);
|
const {segment, slicedPath} = split(rawSegment, consumedPaths, rawSlicedPath, childConfig);
|
||||||
|
// console.log("raw", rawSegment)
|
||||||
|
// console.log(segment.toString(), childConfig)
|
||||||
|
|
||||||
const snapshot = new ActivatedRouteSnapshot(
|
const snapshot = new ActivatedRouteSnapshot(
|
||||||
consumedPaths, Object.freeze(merge(inherited.allParams, parameters)),
|
consumedPaths, Object.freeze(merge(inherited.allParams, parameters)),
|
||||||
|
|
|
@ -195,8 +195,10 @@ export function serializePaths(segment: UrlSegment): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
function serializeSegment(segment: UrlSegment, root: boolean): string {
|
function serializeSegment(segment: UrlSegment, root: boolean): string {
|
||||||
if (segment.children[PRIMARY_OUTLET] && root) {
|
if (segment.hasChildren() && root) {
|
||||||
const primary = serializeSegment(segment.children[PRIMARY_OUTLET], false);
|
const primary = segment.children[PRIMARY_OUTLET] ?
|
||||||
|
serializeSegment(segment.children[PRIMARY_OUTLET], false) :
|
||||||
|
'';
|
||||||
const children: string[] = [];
|
const children: string[] = [];
|
||||||
forEach(segment.children, (v: UrlSegment, k: string) => {
|
forEach(segment.children, (v: UrlSegment, k: string) => {
|
||||||
if (k !== PRIMARY_OUTLET) {
|
if (k !== PRIMARY_OUTLET) {
|
||||||
|
@ -307,7 +309,10 @@ class UrlParser {
|
||||||
this.capture('/');
|
this.capture('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
const paths = [this.parsePathWithParams()];
|
let paths: any[] = [];
|
||||||
|
if (!this.peekStartsWith('(')) {
|
||||||
|
paths.push(this.parsePathWithParams());
|
||||||
|
}
|
||||||
|
|
||||||
while (this.peekStartsWith('/') && !this.peekStartsWith('//') && !this.peekStartsWith('/(')) {
|
while (this.peekStartsWith('/') && !this.peekStartsWith('//') && !this.peekStartsWith('/(')) {
|
||||||
this.capture('/');
|
this.capture('/');
|
||||||
|
@ -325,7 +330,10 @@ class UrlParser {
|
||||||
res = this.parseParens(false);
|
res = this.parseParens(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (paths.length > 0 || Object.keys(children).length > 0) {
|
||||||
res[PRIMARY_OUTLET] = new UrlSegment(paths, children);
|
res[PRIMARY_OUTLET] = new UrlSegment(paths, children);
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,7 +421,6 @@ class UrlParser {
|
||||||
parseParens(allowPrimary: boolean): {[key: string]: UrlSegment} {
|
parseParens(allowPrimary: boolean): {[key: string]: UrlSegment} {
|
||||||
const segments: {[key: string]: UrlSegment} = {};
|
const segments: {[key: string]: UrlSegment} = {};
|
||||||
this.capture('(');
|
this.capture('(');
|
||||||
|
|
||||||
while (!this.peekStartsWith(')') && this.remaining.length > 0) {
|
while (!this.peekStartsWith(')') && this.remaining.length > 0) {
|
||||||
let path = matchPathWithParams(this.remaining);
|
let path = matchPathWithParams(this.remaining);
|
||||||
let outletName: string;
|
let outletName: string;
|
||||||
|
@ -434,7 +441,6 @@ class UrlParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.capture(')');
|
this.capture(')');
|
||||||
|
|
||||||
return segments;
|
return segments;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -494,6 +494,22 @@ describe('recognize', () => {
|
||||||
checkActivatedRoute(c[1], 'c', {}, ComponentC, 'aux');
|
checkActivatedRoute(c[1], 'c', {}, ComponentC, 'aux');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should work when split is at the root level', () => {
|
||||||
|
checkRecognize(
|
||||||
|
[
|
||||||
|
{path: '', component: ComponentA}, {path: 'b', component: ComponentB},
|
||||||
|
{path: 'c', component: ComponentC, outlet: 'aux'}
|
||||||
|
],
|
||||||
|
'(aux:c)', (s: RouterStateSnapshot) => {
|
||||||
|
checkActivatedRoute(s.root, '', {}, RootComponent);
|
||||||
|
|
||||||
|
const children = s.children(s.root);
|
||||||
|
expect(children.length).toEqual(2);
|
||||||
|
checkActivatedRoute(children[0], '', {}, ComponentA);
|
||||||
|
checkActivatedRoute(children[1], 'c', {}, ComponentC, 'aux');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('split at the end (right child)', () => {
|
describe('split at the end (right child)', () => {
|
||||||
|
|
|
@ -6,7 +6,6 @@ describe('url serializer', () => {
|
||||||
|
|
||||||
it('should parse the root url', () => {
|
it('should parse the root url', () => {
|
||||||
const tree = url.parse('/');
|
const tree = url.parse('/');
|
||||||
|
|
||||||
expectSegment(tree.root, '');
|
expectSegment(tree.root, '');
|
||||||
expect(url.serialize(tree)).toEqual('/');
|
expect(url.serialize(tree)).toEqual('/');
|
||||||
});
|
});
|
||||||
|
@ -27,6 +26,26 @@ describe('url serializer', () => {
|
||||||
expect(url.serialize(tree)).toEqual('/one/two(left:three//right:four)');
|
expect(url.serialize(tree)).toEqual('/one/two(left:three//right:four)');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should parse top-level nodes with only secondary segment', () => {
|
||||||
|
const tree = url.parse('/(left:one)');
|
||||||
|
|
||||||
|
expect(tree.root.numberOfChildren).toEqual(1);
|
||||||
|
expectSegment(tree.root.children['left'], 'one');
|
||||||
|
|
||||||
|
expect(url.serialize(tree)).toEqual('/(left:one)');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse nodes with only secondary segment', () => {
|
||||||
|
const tree = url.parse('/one/(left:two)');
|
||||||
|
|
||||||
|
const one = tree.root.children[PRIMARY_OUTLET];
|
||||||
|
expectSegment(one, 'one', true);
|
||||||
|
expect(one.numberOfChildren).toEqual(1);
|
||||||
|
expectSegment(one.children['left'], 'two');
|
||||||
|
|
||||||
|
expect(url.serialize(tree)).toEqual('/one/(left:two)');
|
||||||
|
});
|
||||||
|
|
||||||
it('should not parse empty path segments with params', () => {
|
it('should not parse empty path segments with params', () => {
|
||||||
expect(() => url.parse('/one/two/(;a=1//right:;b=2)'))
|
expect(() => url.parse('/one/two/(;a=1//right:;b=2)'))
|
||||||
.toThrowError(/Empty path url segment cannot have parameters/);
|
.toThrowError(/Empty path url segment cannot have parameters/);
|
||||||
|
@ -167,6 +186,9 @@ describe('url serializer', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
function expectSegment(segment: UrlSegment, expected: string, hasChildren: boolean = false): void {
|
function expectSegment(segment: UrlSegment, expected: string, hasChildren: boolean = false): void {
|
||||||
|
if (segment.pathsWithParams.filter(s => s.path === '').length > 0) {
|
||||||
|
throw new Error(`UrlPathWithParams cannot be empty ${segment.pathsWithParams}`);
|
||||||
|
}
|
||||||
const p = segment.pathsWithParams.map(p => serializePath(p)).join('/');
|
const p = segment.pathsWithParams.map(p => serializePath(p)).join('/');
|
||||||
expect(p).toEqual(expected);
|
expect(p).toEqual(expected);
|
||||||
expect(Object.keys(segment.children).length > 0).toEqual(hasChildren);
|
expect(Object.keys(segment.children).length > 0).toEqual(hasChildren);
|
||||||
|
|
Loading…
Reference in New Issue