const encodeReserveRE = /[!'()*]/g
|
const encodeReserveReplacer = c => '%' + c.charCodeAt(0).toString(16)
|
const commaRE = /%2C/g
|
|
// fixed encodeURIComponent which is more conformant to RFC3986:
|
// - escapes [!'()*]
|
// - preserve commas
|
const encode = str => encodeURIComponent(str)
|
.replace(encodeReserveRE, encodeReserveReplacer)
|
.replace(commaRE, ',')
|
|
const decode = decodeURIComponent
|
|
export function parseQuery (query) {
|
const res = {}
|
|
query = query.trim().replace(/^(\?|#|&)/, '')
|
|
if (!query) {
|
return res
|
}
|
|
query.split('&').forEach(param => {
|
const parts = param.replace(/\+/g, ' ').split('=')
|
const key = decode(parts.shift())
|
const val = parts.length > 0
|
? decode(parts.join('='))
|
: null
|
|
if (res[key] === undefined) {
|
res[key] = val
|
} else if (Array.isArray(res[key])) {
|
res[key].push(val)
|
} else {
|
res[key] = [res[key], val]
|
}
|
})
|
|
return res
|
}
|
|
export function stringifyQuery (obj, encodeStr = encode) {
|
const res = obj ? Object.keys(obj).map(key => {
|
const val = obj[key]
|
|
if (val === undefined) {
|
return ''
|
}
|
|
if (val === null) {
|
return encodeStr(key)
|
}
|
|
if (Array.isArray(val)) {
|
const result = []
|
val.forEach(val2 => {
|
if (val2 === undefined) {
|
return
|
}
|
if (val2 === null) {
|
result.push(encodeStr(key))
|
} else {
|
result.push(encodeStr(key) + '=' + encodeStr(val2))
|
}
|
})
|
return result.join('&')
|
}
|
|
return encodeStr(key) + '=' + encodeStr(val)
|
}).filter(x => x.length > 0).join('&') : null
|
return res ? `?${res}` : ''
|
}
|
|
export function decodedQuery (query = {}) {
|
const decodedQuery = {}
|
Object.keys(query).forEach(name => {
|
try {
|
decodedQuery[name] = decode(query[name])
|
} catch (e) {
|
decodedQuery[name] = query[name]
|
}
|
})
|
return decodedQuery
|
}
|