import { isSameLocationObject, isSameRouteRecord } from './location'
import { routerKey, routeLocationKey } from './injectionSymbols'
import { RouteRecord } from './matcher/types'
+import { assign } from './utils'
export interface RouterLinkProps {
to: RouteLocationRaw
? children
: h(
'a',
- {
- 'aria-current': link.isExactActive ? 'page' : null,
- onClick: link.navigate,
- href: link.href,
- ...attrs,
- class: elClass.value,
- },
+ assign(
+ {
+ 'aria-current': link.isExactActive ? 'page' : null,
+ onClick: link.navigate,
+ href: link.href,
+ },
+ attrs,
+ {
+ class: elClass.value,
+ }
+ ),
children
)
}
viewDepthKey,
routeLocationKey,
} from './injectionSymbols'
+import { assign } from './utils'
export interface RouterViewProps {
name?: string
}
let Component = ViewComponent.value
- const componentProps: Parameters<typeof h>[1] = {
+ const componentProps: Parameters<typeof h>[1] = assign(
+ {},
// only compute props if there is a matched record
- ...(Component && propsData.value),
- ...attrs,
- onVnodeMounted,
- onVnodeUnmounted,
- ref: viewRef,
- }
+ Component && propsData.value,
+ attrs,
+ {
+ onVnodeMounted,
+ onVnodeUnmounted,
+ ref: viewRef,
+ }
+ )
// NOTE: we could also not render if there is no route match
const children =
RouteLocationRaw,
RouteLocationNormalized,
} from './types'
+import { assign } from './utils'
/**
* order is important to make it backwards compatible with v3
params: Omit<E, 'type' | keyof Error>
): E {
if (__DEV__ || !__BROWSER__) {
- return Object.assign(
+ return assign(
new Error(ErrorTypeMessages[type](params as any)),
{ type },
params
) as E
} else {
- return Object.assign(new Error(), { type }, params) as E
+ return assign(new Error(), { type }, params) as E
}
}
} from '../scrollBehavior'
import { warn } from '../warning'
import { stripBase } from '../location'
+import { assign } from '../utils'
type PopStateListener = (this: Window, ev: PopStateEvent) => any
const { history } = window
if (!history.state) return
history.replaceState(
- {
- ...history.state,
- scroll: computeScrollPosition(),
- },
+ assign({}, history.state, { scroll: computeScrollPosition() }),
''
)
}
function replace(to: RawHistoryLocation, data?: HistoryState) {
const normalized = normalizeHistoryLocation(to)
- const state: StateEntry = {
- ...history.state,
- ...buildState(
+ const state: StateEntry = assign(
+ {},
+ history.state,
+ buildState(
historyState.value.back,
// keep back and forward entries but override current position
normalized,
historyState.value.forward,
true
),
- ...data,
- position: historyState.value.position,
- }
+ data,
+ { position: historyState.value.position }
+ )
changeLocation(normalized, state, true)
location.value = normalized
// Add to current entry the information of where we are going
// as well as saving the current position
- const currentState: StateEntry = {
- ...history.state,
+ const currentState: StateEntry = assign({}, history.state, {
forward: normalized,
scroll: computeScrollPosition(),
- }
+ })
changeLocation(currentState.current, currentState, true)
- const state: StateEntry = {
- ...buildState(location.value, normalized, null),
- position: currentState.position + 1,
- ...data,
- }
+ const state: StateEntry = assign(
+ {},
+ buildState(location.value, normalized, null),
+ {
+ position: currentState.position + 1,
+ },
+ data
+ )
changeLocation(normalized, state, false)
location.value = normalized
if (!triggerListeners) historyListeners.pauseListeners()
history.go(delta)
}
- const routerHistory: RouterHistory = {
- // it's overridden right after
- // @ts-ignore
- location: '',
- base,
- go,
- ...historyNavigation,
- ...historyListeners,
- }
+ const routerHistory: RouterHistory = assign(
+ {
+ // it's overridden right after
+ location: ('' as unknown) as HistoryLocationNormalized,
+ base,
+ go,
+ },
+
+ historyNavigation,
+ historyListeners
+ )
Object.defineProperty(routerHistory, 'location', {
get: () => historyNavigation.location.value,
_PathParserOptions,
} from './pathParserRanker'
import { warn } from '../warning'
+import { assign } from '../utils'
let noop = () => {}
const aliases =
typeof record.alias === 'string' ? [record.alias] : record.alias!
for (const alias of aliases) {
- normalizedRecords.push({
- ...mainNormalizedRecord,
- // this allows us to hold a copy of the `components` option
- // so that async components cache is hold on the original record
- components: originalRecord
- ? originalRecord.record.components
- : mainNormalizedRecord.components,
- path: alias,
- // we might be the child of an alias
- aliasOf: originalRecord
- ? originalRecord.record
- : mainNormalizedRecord,
- // the aliases are always of the same kind as the original since they
- // are defined on the same record
- } as typeof mainNormalizedRecord)
+ normalizedRecords.push(
+ assign({}, mainNormalizedRecord, {
+ // this allows us to hold a copy of the `components` option
+ // so that async components cache is hold on the original record
+ components: originalRecord
+ ? originalRecord.record.components
+ : mainNormalizedRecord.components,
+ path: alias,
+ // we might be the child of an alias
+ aliasOf: originalRecord
+ ? originalRecord.record
+ : mainNormalizedRecord,
+ // the aliases are always of the same kind as the original since they
+ // are defined on the same record
+ }) as typeof mainNormalizedRecord
+ )
}
}
})
name = matcher.record.name
- params = {
- ...paramsFromLocation(
+ params = assign(
+ // paramsFromLocation is a new object
+ paramsFromLocation(
currentLocation.params,
matcher.keys.map(k => k.name)
),
- ...location.params,
- }
+ location.params
+ )
// throws if cannot be stringified
path = matcher.stringify(params)
} else if ('path' in location) {
name = matcher.record.name
// since we are navigating to the same location, we don't need to pick the
// params like when `name` is provided
- params = { ...currentLocation.params, ...location.params }
+ params = assign({}, currentLocation.params, location.params)
path = matcher.stringify(params)
}
}
/**
- * Normalizes a RouteRecordRaw. Transforms the `redirect` option into a `beforeEnter`
+ * Normalizes a RouteRecordRaw. Transforms the `redirect` option into a
+ * `beforeEnter`. This function creates a copy
* @param record
* @returns the normalized version
*/
}
if ('redirect' in record) {
- return {
- ...commonInitialValues,
- redirect: record.redirect,
- }
+ return assign(commonInitialValues, { redirect: record.redirect })
} else {
const components =
'components' in record ? record.components : { default: record.component }
- return {
- ...commonInitialValues,
+ return assign(commonInitialValues, {
beforeEnter: record.beforeEnter,
props: normalizeRecordProps(record),
children: record.children || [],
leaveGuards: [],
updateGuards: [],
components,
- }
+ })
}
}
*/
function mergeMetaFields(matched: MatcherLocation['matched']) {
return matched.reduce(
- (meta, record) => ({
- ...meta,
- ...record.meta,
- }),
+ (meta, record) => assign(meta, record.meta),
{} as MatcherLocation['meta']
)
}
} from './pathParserRanker'
import { tokenizePath } from './pathTokenizer'
import { warn } from '../warning'
+import { assign } from '../utils'
export interface RouteRecordMatcher extends PathParser {
record: RouteRecord
}
}
- const matcher: RouteRecordMatcher = {
- ...parser,
+ const matcher: RouteRecordMatcher = assign(parser, {
record,
parent,
// these needs to be populated by the parent
children: [],
alias: [],
- }
+ })
if (parent) {
// both are aliases or both are not aliases
import { Token, TokenType } from './pathTokenizer'
+import { assign } from '../utils'
export type PathParams = Record<string, string | string[]>
segments: Array<Token[]>,
extraOptions?: _PathParserOptions
): PathParser {
- const options = {
- ...BASE_PATH_PARSER_OPTIONS,
- ...extraOptions,
- }
+ const options = assign({}, BASE_PATH_PARSER_OPTIONS, extraOptions)
// the amount of scores is the same as the length of segments except for the root segment "/"
let score: Array<number[]> = []
NavigationFailure,
NavigationRedirectError,
} from './errors'
-import { applyToParams, isBrowser } from './utils'
+import { applyToParams, isBrowser, assign } from './utils'
import { useCallbacks } from './utils/callbacks'
import { encodeParam, decode, encodeHash } from './encoding'
import {
}
}
- return {
- // fullPath: locationNormalized.fullPath,
- // query: locationNormalized.query,
- // hash: locationNormalized.hash,
- ...locationNormalized,
- ...matchedRoute,
- // path: matchedRoute.path,
- // name: matchedRoute.name,
- // meta: matchedRoute.meta,
- // matched: matchedRoute.matched,
+ // locationNormalized is always a new object
+ return assign(locationNormalized, matchedRoute, {
params: decodeParams(matchedRoute.params),
redirectedFrom: undefined,
href: routerHistory.base + locationNormalized.fullPath,
- }
+ })
}
let matcherLocation: MatcherLocationRaw
}" was passed with params but they will be ignored. Use a named route alongside params instead.`
)
}
- matcherLocation = {
- ...rawLocation,
+ matcherLocation = assign({}, rawLocation, {
path: parseURL(parseQuery, rawLocation.path, currentLocation.path).path,
- }
+ })
} else {
- matcherLocation = {
- ...rawLocation,
+ matcherLocation = assign({}, rawLocation, {
params: encodeParams(rawLocation.params),
- }
+ })
}
let matchedRoute = matcher.resolve(matcherLocation, currentLocation)
? normalizeParams(rawLocation.params)
: decodeParams(matchedRoute.params)
- const fullPath = stringifyURL(stringifyQuery, {
- ...rawLocation,
- hash,
- path: matchedRoute.path,
- })
+ const fullPath = stringifyURL(
+ stringifyQuery,
+ assign({}, rawLocation, {
+ hash,
+ path: matchedRoute.path,
+ })
+ )
if (__DEV__) {
let href = routerHistory.base + fullPath
}
}
- return {
- fullPath,
- // keep the hash encoded so fullPath is effectively path + encodedQuery +
- // hash
- hash,
- query: normalizeQuery(rawLocation.query),
- ...matchedRoute,
- redirectedFrom: undefined,
- href: routerHistory.base + fullPath,
- }
+ return assign(
+ {
+ fullPath,
+ // keep the hash encoded so fullPath is effectively path + encodedQuery +
+ // hash
+ hash,
+ query: normalizeQuery(rawLocation.query),
+ },
+ matchedRoute,
+ {
+ redirectedFrom: undefined,
+ href: routerHistory.base + fullPath,
+ }
+ )
}
function locationAsObject(
to: RouteLocationRaw | RouteLocationNormalized
): Exclude<RouteLocationRaw, string> | RouteLocationNormalized {
- return typeof to === 'string' ? { path: to } : to
+ return typeof to === 'string' ? { path: to } : assign({}, to)
}
function push(to: RouteLocationRaw | RouteLocation) {
}
function replace(to: RouteLocationRaw | RouteLocationNormalized) {
- return push({ ...locationAsObject(to), replace: true })
+ return push(assign(locationAsObject(to), { replace: true }))
}
function pushWithRedirect(
return Promise.reject(new Error('Invalid redirect'))
}
return pushWithRedirect(
- {
+ assign(
+ {},
// having a path here would be a problem with relative locations but
// at the same time it doesn't make sense for a redirect to be
// relative (no name, no path) because it would create an infinite
// loop. Since newTargetLocation must either have a `path` or a
// `name`, this will never happen
- ...targetLocation,
- ...newTargetLocation,
- state: data,
- force,
- replace,
- },
+ targetLocation,
+ newTargetLocation,
+ {
+ state: data,
+ force,
+ replace,
+ }
+ ),
// keep original redirectedFrom if it exists
redirectedFrom || targetLocation
)
// preserve the original redirectedFrom if any
return pushWithRedirect(
// keep options
- {
- ...locationAsObject(failure.to),
+ assign(locationAsObject(failure.to), {
state: data,
force,
replace,
- },
+ }),
redirectedFrom || toLocation
)
} else {
// on the initial navigation, we want to reuse the scroll position from
// history state if it exists
if (replace || isFirstNavigation)
- routerHistory.replace(toLocation, {
- scroll: isFirstNavigation && state && state.scroll,
- ...data,
- })
+ routerHistory.replace(
+ toLocation,
+ assign(
+ {
+ scroll: isFirstNavigation && state && state.scroll,
+ },
+ data
+ )
+ )
else routerHistory.push(toLocation, data)
}
return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module')
}
+export const assign = Object.assign
+
export function applyToParams(
fn: (v: string | number) => string,
params: RouteParamsRaw | undefined