From 02848648093830d3e3b2468faf74bc96c1d390a4 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Wed, 5 Feb 2020 14:34:11 +0100 Subject: [PATCH] refactor: move query utils out of history --- __tests__/parseQuery.spec.ts | 22 ++++++- __tests__/query.spec.ts | 22 ------- __tests__/stringifyQuery.spec.ts | 2 +- __tests__/url.spec.ts | 3 +- src/history/common.ts | 101 +------------------------------ src/router.ts | 10 +-- src/types/index.ts | 2 +- 7 files changed, 27 insertions(+), 135 deletions(-) delete mode 100644 __tests__/query.spec.ts diff --git a/__tests__/parseQuery.spec.ts b/__tests__/parseQuery.spec.ts index f42b92fa..ee017eeb 100644 --- a/__tests__/parseQuery.spec.ts +++ b/__tests__/parseQuery.spec.ts @@ -1,8 +1,28 @@ -import { parseQuery } from '../src/history/common' +import { parseQuery } from '../src/utils/query' import { mockWarn } from './mockWarn' describe('parseQuery', () => { mockWarn() + + it('works with leading ?', () => { + expect(parseQuery('?foo=a')).toEqual({ + foo: 'a', + }) + }) + + it('works without leading ?', () => { + expect(parseQuery('foo=a')).toEqual({ + foo: 'a', + }) + }) + + it('works with an empty string', () => { + const emptyQuery = parseQuery('') + expect(Object.keys(emptyQuery)).toHaveLength(0) + expect(emptyQuery).toEqual({}) + expect(parseQuery('?')).toEqual({}) + }) + it('decodes values in query', () => { expect(parseQuery('e=%25')).toEqual({ e: '%', diff --git a/__tests__/query.spec.ts b/__tests__/query.spec.ts deleted file mode 100644 index 8c50da28..00000000 --- a/__tests__/query.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { parseQuery } from '../src/history/common' - -describe('parseQuery', () => { - it('works with leading ?', () => { - expect(parseQuery('?foo=a')).toEqual({ - foo: 'a', - }) - }) - - it('works without leading ?', () => { - expect(parseQuery('foo=a')).toEqual({ - foo: 'a', - }) - }) - - it('works with an empty string', () => { - const emptyQuery = parseQuery('') - expect(Object.keys(emptyQuery)).toHaveLength(0) - expect(emptyQuery).toEqual({}) - expect(parseQuery('?')).toEqual({}) - }) -}) diff --git a/__tests__/stringifyQuery.spec.ts b/__tests__/stringifyQuery.spec.ts index de221c37..61b436be 100644 --- a/__tests__/stringifyQuery.spec.ts +++ b/__tests__/stringifyQuery.spec.ts @@ -1,4 +1,4 @@ -import { stringifyQuery } from '../src/history/common' +import { stringifyQuery } from '../src/utils/query' import { mockWarn } from './mockWarn' describe('stringifyQuery', () => { diff --git a/__tests__/url.spec.ts b/__tests__/url.spec.ts index ea4fe7b1..0e3b2ca0 100644 --- a/__tests__/url.spec.ts +++ b/__tests__/url.spec.ts @@ -1,10 +1,9 @@ import { parseURL as originalParseURL, stringifyURL as originalStringifyURL, - parseQuery, - stringifyQuery, normalizeHistoryLocation as normalizeLocation, } from '../src/history/common' +import { parseQuery, stringifyQuery } from '../src/utils/query' describe('parseURL', () => { let parseURL = originalParseURL.bind(null, parseQuery) diff --git a/src/history/common.ts b/src/history/common.ts index edade696..20226d31 100644 --- a/src/history/common.ts +++ b/src/history/common.ts @@ -1,17 +1,5 @@ import { ListenerRemover } from '../types' -import { decode, encodeQueryProperty } from '../utils/encoding' -// import { encodeQueryProperty, encodeHash } from '../utils/encoding' - -type HistoryQueryValue = string | null -type RawHistoryQueryValue = HistoryQueryValue | number | undefined -export type HistoryQuery = Record< - string, - HistoryQueryValue | HistoryQueryValue[] -> -export type RawHistoryQuery = Record< - string | number, - RawHistoryQueryValue | RawHistoryQueryValue[] -> +import { RawHistoryQuery, HistoryQuery } from '../utils/query' interface HistoryLocation { fullPath: string @@ -158,93 +146,6 @@ export function stringifyURL( return location.path + (query && '?') + query + (location.hash || '') } -/** - * Transform a queryString into a query object. Accept both, a version with the leading `?` and without - * Should work as URLSearchParams - * @param search - * @returns a query object - */ -export function parseQuery(search: string): HistoryQuery { - const query: HistoryQuery = {} - // avoid creating an object with an empty key and empty value - // because of split('&') - if (search === '' || search === '?') return query - const hasLeadingIM = search[0] === '?' - const searchParams = (hasLeadingIM ? search.slice(1) : search).split('&') - for (let i = 0; i < searchParams.length; ++i) { - let [key, rawValue] = searchParams[i].split('=') as [ - string, - string | undefined - ] - key = decode(key) - // avoid decoding null - let value = rawValue == null ? null : decode(rawValue) - if (key in query) { - // an extra variable for ts types - let currentValue = query[key] - if (!Array.isArray(currentValue)) { - currentValue = query[key] = [currentValue] - } - currentValue.push(value) - } else { - query[key] = value - } - } - return query -} -/** - * Stringify an object query. Works like URLSearchParams. Doesn't prepend a `?` - * @param query - */ -export function stringifyQuery(query: RawHistoryQuery): string { - let search = '' - for (let key in query) { - if (search.length) search += '&' - const value = query[key] - key = encodeQueryProperty(key) - if (value == null) { - // only null adds the value - if (value !== undefined) search += key - continue - } - // keep null values - let values: RawHistoryQueryValue[] = Array.isArray(value) - ? value.map(v => v && encodeQueryProperty(v)) - : [value && encodeQueryProperty(value)] - - for (let i = 0; i < values.length; i++) { - // only append & with i > 0 - search += (i ? '&' : '') + key - if (values[i] != null) search += ('=' + values[i]) as string - } - } - - return search -} - -/** - * Transforms a RawQuery intoe a NormalizedQuery by casting numbers into - * strings, removing keys with an undefined value and replacing undefined with - * null in arrays - * @param query - */ -export function normalizeQuery(query: RawHistoryQuery): HistoryQuery { - const normalizedQuery: HistoryQuery = {} - - for (let key in query) { - let value = query[key] - if (value !== undefined) { - normalizedQuery[key] = Array.isArray(value) - ? value.map(v => (v == null ? null : '' + v)) - : value == null - ? value - : '' + value - } - } - - return normalizedQuery -} - /** * Strips off the base from the beginning of a location.pathname * @param pathname location.pathname diff --git a/src/router.ts b/src/router.ts index e5f0cb8e..0c1cf823 100644 --- a/src/router.ts +++ b/src/router.ts @@ -11,14 +11,7 @@ import { Immutable, RouteParams, } from './types' -import { - RouterHistory, - parseQuery, - parseURL, - stringifyQuery, - stringifyURL, - normalizeQuery, -} from './history/common' +import { RouterHistory, parseURL, stringifyURL } from './history/common' import { ScrollToPosition, ScrollPosition, @@ -33,6 +26,7 @@ import { import { extractComponentsGuards, guardToPromiseFn } from './utils' import { useCallbacks } from './utils/callbacks' import { encodeParam, decode } from './utils/encoding' +import { normalizeQuery, parseQuery, stringifyQuery } from './utils/query' import { ref, Ref, markNonReactive, nextTick, App } from 'vue' import { RouteRecordMatched } from './matcher/types' import Link from './components/Link' diff --git a/src/types/index.ts b/src/types/index.ts index cbb6c489..c35eb36e 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,4 +1,4 @@ -import { HistoryQuery, RawHistoryQuery } from '../history/common' +import { HistoryQuery, RawHistoryQuery } from '../utils/query' import { PathParserOptions } from '../matcher/path-parser-ranker' import { markNonReactive } from 'vue' import { RouteRecordMatched } from '../matcher/types' -- 2.39.5