123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- /* @flow */
-
- import Regexp from 'path-to-regexp'
- import { cleanPath } from './util/path'
- import { assert, warn } from './util/warn'
-
- export function createRouteMap (
- routes: Array<RouteConfig>,
- oldPathList?: Array<string>,
- oldPathMap?: Dictionary<RouteRecord>,
- oldNameMap?: Dictionary<RouteRecord>
- ): {
- pathList: Array<string>;
- pathMap: Dictionary<RouteRecord>;
- nameMap: Dictionary<RouteRecord>;
- } {
- // the path list is used to control path matching priority
- const pathList: Array<string> = oldPathList || []
- // $flow-disable-line
- const pathMap: Dictionary<RouteRecord> = oldPathMap || Object.create(null)
- // $flow-disable-line
- const nameMap: Dictionary<RouteRecord> = oldNameMap || Object.create(null)
-
- routes.forEach(route => {
- addRouteRecord(pathList, pathMap, nameMap, route)
- })
-
- // ensure wildcard routes are always at the end
- for (let i = 0, l = pathList.length; i < l; i++) {
- if (pathList[i] === '*') {
- pathList.push(pathList.splice(i, 1)[0])
- l--
- i--
- }
- }
-
- return {
- pathList,
- pathMap,
- nameMap
- }
- }
-
- function addRouteRecord (
- pathList: Array<string>,
- pathMap: Dictionary<RouteRecord>,
- nameMap: Dictionary<RouteRecord>,
- route: RouteConfig,
- parent?: RouteRecord,
- matchAs?: string
- ) {
- const { path, name } = route
- if (process.env.NODE_ENV !== 'production') {
- assert(path != null, `"path" is required in a route configuration.`)
- assert(
- typeof route.component !== 'string',
- `route config "component" for path: ${String(path || name)} cannot be a ` +
- `string id. Use an actual component instead.`
- )
- }
-
- const pathToRegexpOptions: PathToRegexpOptions = route.pathToRegexpOptions || {}
- const normalizedPath = normalizePath(
- path,
- parent,
- pathToRegexpOptions.strict
- )
-
- if (typeof route.caseSensitive === 'boolean') {
- pathToRegexpOptions.sensitive = route.caseSensitive
- }
-
- const record: RouteRecord = {
- path: normalizedPath,
- regex: compileRouteRegex(normalizedPath, pathToRegexpOptions),
- components: route.components || { default: route.component },
- instances: {},
- name,
- parent,
- matchAs,
- redirect: route.redirect,
- beforeEnter: route.beforeEnter,
- meta: route.meta || {},
- props: route.props == null
- ? {}
- : route.components
- ? route.props
- : { default: route.props }
- }
-
- if (route.children) {
- // Warn if route is named, does not redirect and has a default child route.
- // If users navigate to this route by name, the default child will
- // not be rendered (GH Issue #629)
- if (process.env.NODE_ENV !== 'production') {
- if (route.name && !route.redirect && route.children.some(child => /^\/?$/.test(child.path))) {
- warn(
- false,
- `Named Route '${route.name}' has a default child route. ` +
- `When navigating to this named route (:to="{name: '${route.name}'"), ` +
- `the default child route will not be rendered. Remove the name from ` +
- `this route and use the name of the default child route for named ` +
- `links instead.`
- )
- }
- }
- route.children.forEach(child => {
- const childMatchAs = matchAs
- ? cleanPath(`${matchAs}/${child.path}`)
- : undefined
- addRouteRecord(pathList, pathMap, nameMap, child, record, childMatchAs)
- })
- }
-
- if (route.alias !== undefined) {
- const aliases = Array.isArray(route.alias)
- ? route.alias
- : [route.alias]
-
- aliases.forEach(alias => {
- const aliasRoute = {
- path: alias,
- children: route.children
- }
- addRouteRecord(
- pathList,
- pathMap,
- nameMap,
- aliasRoute,
- parent,
- record.path || '/' // matchAs
- )
- })
- }
-
- if (!pathMap[record.path]) {
- pathList.push(record.path)
- pathMap[record.path] = record
- }
-
- if (name) {
- if (!nameMap[name]) {
- nameMap[name] = record
- } else if (process.env.NODE_ENV !== 'production' && !matchAs) {
- warn(
- false,
- `Duplicate named routes definition: ` +
- `{ name: "${name}", path: "${record.path}" }`
- )
- }
- }
- }
-
- function compileRouteRegex (path: string, pathToRegexpOptions: PathToRegexpOptions): RouteRegExp {
- const regex = Regexp(path, [], pathToRegexpOptions)
- if (process.env.NODE_ENV !== 'production') {
- const keys: any = Object.create(null)
- regex.keys.forEach(key => {
- warn(!keys[key.name], `Duplicate param keys in route with path: "${path}"`)
- keys[key.name] = true
- })
- }
- return regex
- }
-
- function normalizePath (path: string, parent?: RouteRecord, strict?: boolean): string {
- if (!strict) path = path.replace(/\/$/, '')
- if (path[0] === '/') return path
- if (parent == null) return path
- return cleanPath(`${parent.path}/${path}`)
- }
|