Skip to content

Commit

Permalink
feat: allow numbers as params
Browse files Browse the repository at this point in the history
Close #206

Co-authored-by: Eduardo San Martin Morote <posva13@gmail.com>
  • Loading branch information
pikax and posva committed May 3, 2020
1 parent f5b5949 commit ef0920a
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 30 deletions.
6 changes: 6 additions & 0 deletions __tests__/router.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,12 @@ describe('Router', () => {
expect(spy).toHaveBeenCalledTimes(1)
})

it('casts number params to string', async () => {
const { router } = await newRouter()
await router.push({ name: 'Param', params: { p: 0 } })
expect(router.currentRoute.value).toMatchObject({ params: { p: '0' } })
})

it('navigates to same route record but different query', async () => {
const { router } = await newRouter()
await router.push('/?q=1')
Expand Down
10 changes: 5 additions & 5 deletions src/encoding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export function encodeQueryProperty(text: string | number): string {
* @param text - string to encode
* @returns encoded string
*/
export function encodePath(text: string): string {
export function encodePath(text: string | number): string {
return commonEncode(text).replace(HASH_RE, '%23').replace(IM_RE, '%3F')
}

Expand All @@ -96,7 +96,7 @@ export function encodePath(text: string): string {
* @param text - string to encode
* @returns encoded string
*/
export function encodeParam(text: string): string {
export function encodeParam(text: string | number): string {
return encodePath(text).replace(SLASH_RE, '%2F')
}

Expand All @@ -107,11 +107,11 @@ export function encodeParam(text: string): string {
* @param text - string to decode
* @returns decoded string
*/
export function decode(text: string): string {
export function decode(text: string | number): string {
try {
return decodeURIComponent(text)
return decodeURIComponent('' + text)
} catch (err) {
__DEV__ && warn(`Error decoding "${text}". Using original value`)
}
return text
return '' + text
}
27 changes: 15 additions & 12 deletions src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import {
PostNavigationGuard,
START_LOCATION_NORMALIZED,
Lazy,
MatcherLocation,
RouteLocationNormalizedLoaded,
RouteLocation,
RouteRecordName,
isRouteName,
NavigationGuardWithThis,
RouteLocationOptions,
MatcherLocationRaw,
} from './types'
import { RouterHistory, HistoryState } from './history/common'
import {
Expand Down Expand Up @@ -180,6 +180,10 @@ export function createRouter(options: RouterOptions): Router {
history.scrollRestoration = 'manual'
}

const normalizeParams = applyToParams.bind(
null,
paramValue => '' + paramValue
)
const encodeParams = applyToParams.bind(null, encodeParam)
const decodeParams = applyToParams.bind(null, decode)

Expand Down Expand Up @@ -249,6 +253,8 @@ export function createRouter(options: RouterOptions): Router {
}
}

let matcherLocation: MatcherLocationRaw

// path could be relative in object as well
if ('path' in rawLocation) {
if (
Expand All @@ -263,28 +269,25 @@ export function createRouter(options: RouterOptions): Router {
}" was passed with params but they will be ignored. Use a named route alongside params instead.`
)
}
rawLocation = {
matcherLocation = {
...rawLocation,
path: parseURL(parseQuery, rawLocation.path, currentLocation.path).path,
}
} else {
matcherLocation = {
...rawLocation,
params: encodeParams(rawLocation.params),
}
}

let matchedRoute: MatcherLocation = // relative or named location, path is ignored
// for same reason TS thinks rawLocation.params can be undefined
matcher.resolve(
'params' in rawLocation
? { ...rawLocation, params: encodeParams(rawLocation.params) }
: rawLocation,
currentLocation
)
let matchedRoute = matcher.resolve(matcherLocation, currentLocation)

const hash = encodeHash(rawLocation.hash || '')

// put back the unencoded params as given by the user (avoid the cost of decoding them)
// TODO: normalize params if we accept numbers as raw values
matchedRoute.params =
'params' in rawLocation
? rawLocation.params!
? normalizeParams(rawLocation.params)
: decodeParams(matchedRoute.params)

const fullPath = stringifyURL(stringifyQuery, {
Expand Down
27 changes: 17 additions & 10 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,12 @@ export type VueUseOptions<T> = {
export type TODO = any

export type RouteParamValue = string
// TODO: should we allow more values like numbers and normalize them to strings?
// type RouteParamValueRaw = RouteParamValue | number
export type RouteParamValueRaw = RouteParamValue | number
export type RouteParams = Record<string, RouteParamValue | RouteParamValue[]>
export type RouteParamsRaw = RouteParams
// export type RouteParamsRaw = Record<
// string,
// RouteParamValueRaw | RouteParamValueRaw[]
// >
export type RouteParamsRaw = Record<
string,
RouteParamValueRaw | RouteParamValueRaw[]
>

export interface RouteQueryAndHash {
query?: LocationQueryRaw
Expand All @@ -37,13 +35,22 @@ export interface LocationAsPath {
path: string
}

export interface LocationAsNameRaw {
name: RouteRecordName
params?: RouteParamsRaw
}

export interface LocationAsName {
name: RouteRecordName
params?: RouteParams
}

export interface LocationAsRelativeRaw {
params?: RouteParamsRaw
}

export interface LocationAsRelative {
params?: RouteParamsRaw
params?: RouteParams
}

export interface RouteLocationOptions {
Expand All @@ -67,8 +74,8 @@ export interface RouteLocationOptions {
export type RouteLocationRaw =
| string
| (RouteQueryAndHash & LocationAsPath & RouteLocationOptions)
| (RouteQueryAndHash & LocationAsName & RouteLocationOptions)
| (RouteQueryAndHash & LocationAsRelative & RouteLocationOptions)
| (RouteQueryAndHash & LocationAsNameRaw & RouteLocationOptions)
| (RouteQueryAndHash & LocationAsRelativeRaw & RouteLocationOptions)

export interface RouteLocationMatched extends RouteRecordNormalized {
// components cannot be Lazy<RouteComponent>
Expand Down
6 changes: 3 additions & 3 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { RouteParams, RouteComponent } from '../types'
import { RouteParams, RouteComponent, RouteParamsRaw } from '../types'
import { hasSymbol } from '../injectionSymbols'

export * from './env'
Expand All @@ -8,8 +8,8 @@ export function isESModule(obj: any): obj is { default: RouteComponent } {
}

export function applyToParams(
fn: (v: string) => string,
params: RouteParams | undefined
fn: (v: string | number) => string,
params: RouteParamsRaw | undefined
): RouteParams {
const newParams: RouteParams = {}

Expand Down

0 comments on commit ef0920a

Please sign in to comment.