Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: null should be preserved in relative navigations #2083

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions packages/router/__tests__/router.spec.ts
Expand Up @@ -331,6 +331,19 @@ describe('Router', () => {
expect(router.currentRoute.value.params).toEqual({})
})

it('removes null/undefined optional params when current location has it on relative navigations', async () => {
const { router } = await newRouter()
const withParam = router.resolve({ name: 'optional', params: { p: 'a' } })
const implicitNull = router.resolve({ params: { p: null } }, withParam)
const implicitUndefined = router.resolve(
{ params: { p: undefined } },
withParam
)

expect(implicitNull.params).toEqual({})
expect(implicitUndefined.params).toEqual({})
})

it('keeps empty strings in optional params', async () => {
const { router } = await newRouter()
const route1 = router.resolve({ name: 'optional', params: { p: '' } })
Expand Down
29 changes: 25 additions & 4 deletions packages/router/src/encoding.ts
@@ -1,3 +1,4 @@
import { assign } from './utils'
import { warn } from './warning'

/**
Expand Down Expand Up @@ -120,14 +121,34 @@ export function encodePath(text: string | number): string {
/**
* Encode characters that need to be encoded on the path section of the URL as a
* param. This function encodes everything {@link encodePath} does plus the
* slash (`/`) character. If `text` is `null` or `undefined`, returns an empty
* string instead.
* slash (`/`) character. If `text` is `null` or `undefined`, it keeps the value as is.
*
* @param text - string to encode
* @returns encoded string
*/
export function encodeParam(text: string | number | null | undefined): string {
return text == null ? '' : encodePath(text).replace(SLASH_RE, '%2F')
export function encodeParam(
text: string | number | null | undefined
): string | null | undefined {
return text == null ? text : encodePath(text).replace(SLASH_RE, '%2F')
}

/**
* Remove nullish values from an object. This function creates a copy of the object. Used for params and query.
*
* @param obj - plain object to remove nullish values from
* @returns a new object with only defined values
*/
export function withoutNullishValues(
obj: Record<string, unknown>
): Record<string, unknown> {
const targetParams = assign({}, obj)
for (const key in targetParams) {
if (targetParams[key] == null) {
delete targetParams[key]
}
}

return targetParams
}

/**
Expand Down
10 changes: 9 additions & 1 deletion packages/router/src/utils/index.ts
Expand Up @@ -13,10 +13,18 @@ export function isESModule(obj: any): obj is { default: RouteComponent } {

export const assign = Object.assign

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

for (const key in params) {
Expand Down