import { ListenerRemover } from '../types'
+import { encodeQueryProperty, encodeHash, encodePath } from '../utils/encoding'
export type HistoryQuery = Record<string, string | string[]>
// TODO: is it reall worth allowing null to form queries like ?q&b&c
// Generic utils
-// needed for the global flag
-const PERCENT_RE = /%/g
-
/**
* Transforms an URI into a normalized history location
* @param location URI to normalize
}
}
+// TODO: the encoding would be handled at a router level instead where encoding functions can be customized
+// that way the matcher can encode/decode params properly
+
function safeDecodeUriComponent(value: string): string {
try {
value = decodeURIComponent(value)
const searchParams = (hasLeadingIM ? search.slice(1) : search).split('&')
for (let i = 0; i < searchParams.length; ++i) {
let [key, value] = searchParams[i].split('=')
- key = safeDecodeUriComponent(key)
- value = safeDecodeUriComponent(value)
if (key in query) {
// an extra variable for ts types
let currentValue = query[key]
let url = location.path
let query = location.query ? stringifyQuery(location.query) : ''
- return url + (query && '?' + query) + (location.hash || '')
+ return (
+ encodePath(url) + (query && '?' + query) + encodeHash(location.hash || '')
+ )
}
/**
*/
export function stringifyQuery(query: RawHistoryQuery): string {
let search = ''
- // TODO: util function?
for (const key in query) {
if (search.length > 1) search += '&'
const value = query[key]
search += key
continue
}
- let encodedKey = safeEncodeUriComponent(key)
+ const encodedKey = encodeQueryProperty(key)
let values: string[] = Array.isArray(value) ? value : [value]
- values = values.map(safeEncodeUriComponent)
+ const encodedValues = values.map(encodeQueryProperty)
search += `${encodedKey}=${values[0]}`
for (let i = 1; i < values.length; i++) {
- search += `&${encodedKey}=${values[i]}`
+ search += `&${encodedKey}=${encodedValues[i]}`
}
}
return normalizedQuery
}
-// FIXME: not used
-/**
- * Prepare a URI string to be passed to pushState
- * @param uri
- */
-export function prepareURI(uri: string) {
- // encode the % symbol so it also works on IE
- return uri.replace(PERCENT_RE, '%25')
-}
-
// use regular decodeURI
// Use a renamed export instead of global.decodeURI
// to support node and browser at the same time
.replace(ENC_CARET_RE, '^')
}
-export function encodeParam(text: string): string {
+export function encodePath(text: string): string {
return commonEncode(text)
- .replace(SLASH_RE, '%2F')
.replace(HASH_RE, '%23')
.replace(IM_RE, '%3F')
}
+export function encodeParam(text: string): string {
+ return encodePath(text).replace(SLASH_RE, '%2F')
+}
+
export const decode = decodeURIComponent