| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- /* @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--
- }
- }
- if (process.env.NODE_ENV === 'development') {
- // warn if routes do not include leading slashes
- const found = pathList
- // check for missing leading slash
- .filter(path => path && path.charAt(0) !== '*' && path.charAt(0) !== '/')
- if (found.length > 0) {
- const pathNames = found.map(path => `- ${path}`).join('\n')
- warn(false, `Non-nested routes must include a leading slash character. Fix the following routes: \n${pathNames}`)
- }
- }
- 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.`
- )
- warn(
- // eslint-disable-next-line no-control-regex
- !/[^\u0000-\u007F]+/.test(path),
- `Route with path "${path}" contains unencoded characters, make sure ` +
- `your path is correctly encoded before passing it to the router. Use ` +
- `encodeURI to encode static segments of your path.`
- )
- }
- 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: {},
- enteredCbs: {},
- 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 (!pathMap[record.path]) {
- pathList.push(record.path)
- pathMap[record.path] = record
- }
- if (route.alias !== undefined) {
- const aliases = Array.isArray(route.alias) ? route.alias : [route.alias]
- for (let i = 0; i < aliases.length; ++i) {
- const alias = aliases[i]
- if (process.env.NODE_ENV !== 'production' && alias === path) {
- warn(
- false,
- `Found an alias with the same value as the path: "${path}". You have to remove that alias. It will be ignored in development.`
- )
- // skip in dev to make it work
- continue
- }
- const aliasRoute = {
- path: alias,
- children: route.children
- }
- addRouteRecord(
- pathList,
- pathMap,
- nameMap,
- aliasRoute,
- parent,
- record.path || '/' // matchAs
- )
- }
- }
- 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}`)
- }
|