Skip to content

Commit

Permalink
fix: ignore order of keys in query and params
Browse files Browse the repository at this point in the history
  • Loading branch information
posva committed Apr 7, 2020
1 parent 8bbed1b commit 643bd15
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 20 deletions.
32 changes: 32 additions & 0 deletions __tests__/location.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
stringifyURL as originalStringifyURL,
stripBase,
} from '../src/utils/location'
import { isSameLocationObject } from '../src/utils'

describe('parseURL', () => {
let parseURL = originalParseURL.bind(null, parseQuery)
Expand Down Expand Up @@ -160,3 +161,34 @@ describe('stripBase', () => {
expect(stripBase('/base/foo', '/base')).toBe('/foo')
})
})

describe('isSameLocationObject', () => {
it('compare simple values', () => {
expect(isSameLocationObject({ a: '2' }, { a: '2' })).toBe(true)
expect(isSameLocationObject({ a: '3' }, { a: '2' })).toBe(false)
// different order
expect(isSameLocationObject({ a: '2', b: '3' }, { b: '3', a: '2' })).toBe(
true
)
expect(isSameLocationObject({ a: '3', b: '3' }, { b: '3', a: '2' })).toBe(
false
)
})

it('compare array values', () => {
expect(isSameLocationObject({ a: ['2'] }, { a: ['2'] })).toBe(true)
expect(isSameLocationObject({ a: ['3'] }, { a: ['2'] })).toBe(false)
// different order
expect(
isSameLocationObject({ a: ['2'], b: ['3'] }, { b: ['3'], a: ['2'] })
).toBe(true)
expect(
isSameLocationObject({ a: ['3'], b: ['3'] }, { b: ['3'], a: ['2'] })
).toBe(false)
})

it('considers arrays of one item same as the item itself', () => {
expect(isSameLocationObject({ a: ['2'] }, { a: '2' })).toBe(true)
expect(isSameLocationObject({ a: ['3'] }, { a: '2' })).toBe(false)
})
})
56 changes: 36 additions & 20 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
RouteParams,
RouteComponent,
RouteLocationNormalizedLoaded,
RouteParamValue,
} from '../types'
import { guardToPromiseFn } from './guardToPromiseFn'
import { RouteRecord, RouteRecordNormalized } from '../matcher/types'
Expand Down Expand Up @@ -90,16 +91,10 @@ export function isSameLocationObject(
a: RouteLocationNormalized['query' | 'params'],
b: RouteLocationNormalized['query' | 'params']
): boolean {
const aKeys = Object.keys(a)
const bKeys = Object.keys(b)
if (aKeys.length !== bKeys.length) return false
let i = 0
let key: string
while (i < aKeys.length) {
key = aKeys[i]
if (key !== bKeys[i]) return false
if (Object.keys(a).length !== Object.keys(b).length) return false

for (let key in a) {
if (!isSameLocationObjectValue(a[key], b[key])) return false
i++
}

return true
Expand All @@ -109,17 +104,38 @@ function isSameLocationObjectValue(
a: LocationQueryValue | LocationQueryValue[],
b: LocationQueryValue | LocationQueryValue[]
): boolean
function isSameLocationObjectValue(a: RouteParams, b: RouteParams): boolean
function isSameLocationObjectValue(
a: LocationQueryValue | LocationQueryValue[] | RouteParams,
b: LocationQueryValue | LocationQueryValue[] | RouteParams
a: RouteParamValue | RouteParamValue[],
b: RouteParamValue | RouteParamValue[]
): boolean
function isSameLocationObjectValue(
a:
| LocationQueryValue
| LocationQueryValue[]
| RouteParamValue
| RouteParamValue[],
b:
| LocationQueryValue
| LocationQueryValue[]
| RouteParamValue
| RouteParamValue[]
): boolean {
if (typeof a !== typeof b) return false
// both a and b are arrays
if (Array.isArray(a))
return (
a.length === (b as any[]).length &&
a.every((value, i) => value === (b as LocationQueryValue[])[i])
)
return a === b
return Array.isArray(a)
? isEquivalentArray(a, b)
: Array.isArray(b)
? isEquivalentArray(b, a)
: a === b
}

/**
* Check if two arrays are the same or if an array with one single entry is the
* same as another primitive value. Used to check query and parameters
*
* @param a array of values
* @param b array of values or a single value
*/
function isEquivalentArray<T>(a: T[], b: T[] | T): boolean {
return Array.isArray(b)
? a.length === b.length && a.every((value, i) => value === b[i])
: a.length === 1 && a[0] === b
}

0 comments on commit 643bd15

Please sign in to comment.