/** * @license * Copyright Google Inc. All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import { PRIMARY_OUTLET } from './shared'; import { UrlSegment, UrlSegmentGroup, UrlTree } from './url_tree'; import { forEach, last, shallowEqual } from './utils/collection'; /** * @param {?} route * @param {?} urlTree * @param {?} commands * @param {?} queryParams * @param {?} fragment * @return {?} */ export function createUrlTree(route, urlTree, commands, queryParams, fragment) { if (commands.length === 0) { return tree(urlTree.root, urlTree.root, urlTree, queryParams, fragment); } var /** @type {?} */ nav = computeNavigation(commands); if (nav.toRoot()) { return tree(urlTree.root, new UrlSegmentGroup([], {}), urlTree, queryParams, fragment); } var /** @type {?} */ startingPosition = findStartingPosition(nav, urlTree, route); var /** @type {?} */ segmentGroup = startingPosition.processChildren ? updateSegmentGroupChildren(startingPosition.segmentGroup, startingPosition.index, nav.commands) : updateSegmentGroup(startingPosition.segmentGroup, startingPosition.index, nav.commands); return tree(startingPosition.segmentGroup, segmentGroup, urlTree, queryParams, fragment); } /** * @param {?} command * @return {?} */ function isMatrixParams(command) { return typeof command === 'object' && command != null && !command.outlets && !command.segmentPath; } /** * @param {?} oldSegmentGroup * @param {?} newSegmentGroup * @param {?} urlTree * @param {?} queryParams * @param {?} fragment * @return {?} */ function tree(oldSegmentGroup, newSegmentGroup, urlTree, queryParams, fragment) { if (urlTree.root === oldSegmentGroup) { return new UrlTree(newSegmentGroup, stringify(queryParams), fragment); } return new UrlTree(replaceSegment(urlTree.root, oldSegmentGroup, newSegmentGroup), stringify(queryParams), fragment); } /** * @param {?} current * @param {?} oldSegment * @param {?} newSegment * @return {?} */ function replaceSegment(current, oldSegment, newSegment) { var /** @type {?} */ children = {}; forEach(current.children, function (c, outletName) { if (c === oldSegment) { children[outletName] = newSegment; } else { children[outletName] = replaceSegment(c, oldSegment, newSegment); } }); return new UrlSegmentGroup(current.segments, children); } var Navigation = (function () { /** * @param {?} isAbsolute * @param {?} numberOfDoubleDots * @param {?} commands */ function Navigation(isAbsolute, numberOfDoubleDots, commands) { this.isAbsolute = isAbsolute; this.numberOfDoubleDots = numberOfDoubleDots; this.commands = commands; if (isAbsolute && commands.length > 0 && isMatrixParams(commands[0])) { throw new Error('Root segment cannot have matrix parameters'); } var cmdWithOutlet = commands.find(function (c) { return typeof c === 'object' && c != null && c.outlets; }); if (cmdWithOutlet && cmdWithOutlet !== last(commands)) { throw new Error('{outlets:{}} has to be the last command'); } } /** * @return {?} */ Navigation.prototype.toRoot = function () { return this.isAbsolute && this.commands.length === 1 && this.commands[0] == '/'; }; return Navigation; }()); function Navigation_tsickle_Closure_declarations() { /** @type {?} */ Navigation.prototype.isAbsolute; /** @type {?} */ Navigation.prototype.numberOfDoubleDots; /** @type {?} */ Navigation.prototype.commands; } /** * Transforms commands to a normalized `Navigation` * @param {?} commands * @return {?} */ function computeNavigation(commands) { if ((typeof commands[0] === 'string') && commands.length === 1 && commands[0] === '/') { return new Navigation(true, 0, commands); } var /** @type {?} */ numberOfDoubleDots = 0; var /** @type {?} */ isAbsolute = false; var /** @type {?} */ res = commands.reduce(function (res, cmd, cmdIdx) { if (typeof cmd === 'object' && cmd != null) { if (cmd.outlets) { var /** @type {?} */ outlets_1 = {}; forEach(cmd.outlets, function (commands, name) { outlets_1[name] = typeof commands === 'string' ? commands.split('/') : commands; }); return res.concat([{ outlets: outlets_1 }]); } if (cmd.segmentPath) { return res.concat([cmd.segmentPath]); } } if (!(typeof cmd === 'string')) { return res.concat([cmd]); } if (cmdIdx === 0) { cmd.split('/').forEach(function (urlPart, partIndex) { if (partIndex == 0 && urlPart === '.') { } else if (partIndex == 0 && urlPart === '') { isAbsolute = true; } else if (urlPart === '..') { numberOfDoubleDots++; } else if (urlPart != '') { res.push(urlPart); } }); return res; } return res.concat([cmd]); }, []); return new Navigation(isAbsolute, numberOfDoubleDots, res); } var Position = (function () { /** * @param {?} segmentGroup * @param {?} processChildren * @param {?} index */ function Position(segmentGroup, processChildren, index) { this.segmentGroup = segmentGroup; this.processChildren = processChildren; this.index = index; } return Position; }()); function Position_tsickle_Closure_declarations() { /** @type {?} */ Position.prototype.segmentGroup; /** @type {?} */ Position.prototype.processChildren; /** @type {?} */ Position.prototype.index; } /** * @param {?} nav * @param {?} tree * @param {?} route * @return {?} */ function findStartingPosition(nav, tree, route) { if (nav.isAbsolute) { return new Position(tree.root, true, 0); } if (route.snapshot._lastPathIndex === -1) { return new Position(route.snapshot._urlSegment, true, 0); } var /** @type {?} */ modifier = isMatrixParams(nav.commands[0]) ? 0 : 1; var /** @type {?} */ index = route.snapshot._lastPathIndex + modifier; return createPositionApplyingDoubleDots(route.snapshot._urlSegment, index, nav.numberOfDoubleDots); } /** * @param {?} group * @param {?} index * @param {?} numberOfDoubleDots * @return {?} */ function createPositionApplyingDoubleDots(group, index, numberOfDoubleDots) { var /** @type {?} */ g = group; var /** @type {?} */ ci = index; var /** @type {?} */ dd = numberOfDoubleDots; while (dd > ci) { dd -= ci; g = g.parent; if (!g) { throw new Error('Invalid number of \'../\''); } ci = g.segments.length; } return new Position(g, false, ci - dd); } /** * @param {?} command * @return {?} */ function getPath(command) { if (typeof command === 'object' && command != null && command.outlets) { return command.outlets[PRIMARY_OUTLET]; } return "" + command; } /** * @param {?} commands * @return {?} */ function getOutlets(commands) { if (!(typeof commands[0] === 'object')) return (_a = {}, _a[PRIMARY_OUTLET] = commands, _a); if (commands[0].outlets === undefined) return (_b = {}, _b[PRIMARY_OUTLET] = commands, _b); return commands[0].outlets; var _a, _b; } /** * @param {?} segmentGroup * @param {?} startIndex * @param {?} commands * @return {?} */ function updateSegmentGroup(segmentGroup, startIndex, commands) { if (!segmentGroup) { segmentGroup = new UrlSegmentGroup([], {}); } if (segmentGroup.segments.length === 0 && segmentGroup.hasChildren()) { return updateSegmentGroupChildren(segmentGroup, startIndex, commands); } var /** @type {?} */ m = prefixedWith(segmentGroup, startIndex, commands); var /** @type {?} */ slicedCommands = commands.slice(m.commandIndex); if (m.match && m.pathIndex < segmentGroup.segments.length) { var /** @type {?} */ g = new UrlSegmentGroup(segmentGroup.segments.slice(0, m.pathIndex), {}); g.children[PRIMARY_OUTLET] = new UrlSegmentGroup(segmentGroup.segments.slice(m.pathIndex), segmentGroup.children); return updateSegmentGroupChildren(g, 0, slicedCommands); } else if (m.match && slicedCommands.length === 0) { return new UrlSegmentGroup(segmentGroup.segments, {}); } else if (m.match && !segmentGroup.hasChildren()) { return createNewSegmentGroup(segmentGroup, startIndex, commands); } else if (m.match) { return updateSegmentGroupChildren(segmentGroup, 0, slicedCommands); } else { return createNewSegmentGroup(segmentGroup, startIndex, commands); } } /** * @param {?} segmentGroup * @param {?} startIndex * @param {?} commands * @return {?} */ function updateSegmentGroupChildren(segmentGroup, startIndex, commands) { if (commands.length === 0) { return new UrlSegmentGroup(segmentGroup.segments, {}); } else { var /** @type {?} */ outlets_2 = getOutlets(commands); var /** @type {?} */ children_1 = {}; forEach(outlets_2, function (commands, outlet) { if (commands !== null) { children_1[outlet] = updateSegmentGroup(segmentGroup.children[outlet], startIndex, commands); } }); forEach(segmentGroup.children, function (child, childOutlet) { if (outlets_2[childOutlet] === undefined) { children_1[childOutlet] = child; } }); return new UrlSegmentGroup(segmentGroup.segments, children_1); } } /** * @param {?} segmentGroup * @param {?} startIndex * @param {?} commands * @return {?} */ function prefixedWith(segmentGroup, startIndex, commands) { var /** @type {?} */ currentCommandIndex = 0; var /** @type {?} */ currentPathIndex = startIndex; var /** @type {?} */ noMatch = { match: false, pathIndex: 0, commandIndex: 0 }; while (currentPathIndex < segmentGroup.segments.length) { if (currentCommandIndex >= commands.length) return noMatch; var /** @type {?} */ path = segmentGroup.segments[currentPathIndex]; var /** @type {?} */ curr = getPath(commands[currentCommandIndex]); var /** @type {?} */ next = currentCommandIndex < commands.length - 1 ? commands[currentCommandIndex + 1] : null; if (currentPathIndex > 0 && curr === undefined) break; if (curr && next && (typeof next === 'object') && next.outlets === undefined) { if (!compare(curr, next, path)) return noMatch; currentCommandIndex += 2; } else { if (!compare(curr, {}, path)) return noMatch; currentCommandIndex++; } currentPathIndex++; } return { match: true, pathIndex: currentPathIndex, commandIndex: currentCommandIndex }; } /** * @param {?} segmentGroup * @param {?} startIndex * @param {?} commands * @return {?} */ function createNewSegmentGroup(segmentGroup, startIndex, commands) { var /** @type {?} */ paths = segmentGroup.segments.slice(0, startIndex); var /** @type {?} */ i = 0; while (i < commands.length) { if (typeof commands[i] === 'object' && commands[i].outlets !== undefined) { var /** @type {?} */ children = createNewSegmentChildren(commands[i].outlets); return new UrlSegmentGroup(paths, children); } // if we start with an object literal, we need to reuse the path part from the segment if (i === 0 && isMatrixParams(commands[0])) { var /** @type {?} */ p = segmentGroup.segments[startIndex]; paths.push(new UrlSegment(p.path, commands[0])); i++; continue; } var /** @type {?} */ curr = getPath(commands[i]); var /** @type {?} */ next = (i < commands.length - 1) ? commands[i + 1] : null; if (curr && next && isMatrixParams(next)) { paths.push(new UrlSegment(curr, stringify(next))); i += 2; } else { paths.push(new UrlSegment(curr, {})); i++; } } return new UrlSegmentGroup(paths, {}); } /** * @param {?} outlets * @return {?} */ function createNewSegmentChildren(outlets) { var /** @type {?} */ children = {}; forEach(outlets, function (commands, outlet) { if (commands !== null) { children[outlet] = createNewSegmentGroup(new UrlSegmentGroup([], {}), 0, commands); } }); return children; } /** * @param {?} params * @return {?} */ function stringify(params) { var /** @type {?} */ res = {}; forEach(params, function (v, k) { return res[k] = "" + v; }); return res; } /** * @param {?} path * @param {?} params * @param {?} segment * @return {?} */ function compare(path, params, segment) { return path == segment.path && shallowEqual(params, segment.parameters); } //# sourceMappingURL=create_url_tree.js.map