EdgeAIG's picture
download
raw
7.75 kB
/**
* @since 1.0.0
*/
// Taken from https://github.com/anonrig/fast-querystring under MIT License
const plusRegex = /\+/g
const Empty: new () => Record<string, any> = function () {} as any
Empty.prototype = Object.create(null)
/**
* @category parsing
* @since 1.0.0
*/
export function parse(input: string) {
// Optimization: Use new Empty() instead of Object.create(null) for performance
// v8 has a better optimization for initializing functions compared to Object
const result = new Empty()
if (typeof input !== "string") {
return result
}
const inputLength = input.length
let key = ""
let value = ""
let startingIndex = -1
let equalityIndex = -1
let shouldDecodeKey = false
let shouldDecodeValue = false
let keyHasPlus = false
let valueHasPlus = false
let hasBothKeyValuePair = false
let c = 0
// Have a boundary of input.length + 1 to access last pair inside the loop.
for (let i = 0; i < inputLength + 1; i++) {
c = i !== inputLength ? input.charCodeAt(i) : 38
// Handle '&' and end of line to pass the current values to result
if (c === 38) {
hasBothKeyValuePair = equalityIndex > startingIndex
// Optimization: Reuse equality index to store the end of key
if (!hasBothKeyValuePair) {
equalityIndex = i
}
key = input.slice(startingIndex + 1, equalityIndex)
// Add key/value pair only if the range size is greater than 1; a.k.a. contains at least "="
if (hasBothKeyValuePair || key.length > 0) {
// Optimization: Replace '+' with space
if (keyHasPlus) {
key = key.replace(plusRegex, " ")
}
// Optimization: Do not decode if it's not necessary.
if (shouldDecodeKey) {
try {
key = decodeURIComponent(key) || key
} catch {}
}
if (hasBothKeyValuePair) {
value = input.slice(equalityIndex + 1, i)
if (valueHasPlus) {
value = value.replace(plusRegex, " ")
}
if (shouldDecodeValue) {
try {
value = decodeURIComponent(value) || value
} catch {}
}
}
const currentValue = result[key]
if (currentValue === undefined) {
result[key] = value
} else {
// Optimization: value.pop is faster than Array.isArray(value)
if (currentValue.pop) {
currentValue.push(value)
} else {
result[key] = [currentValue, value]
}
}
}
// Reset reading key value pairs
value = ""
startingIndex = i
equalityIndex = i
shouldDecodeKey = false
shouldDecodeValue = false
keyHasPlus = false
valueHasPlus = false
}
// Check '='
else if (c === 61) {
if (equalityIndex <= startingIndex) {
equalityIndex = i
}
// If '=' character occurs again, we should decode the input.
else {
shouldDecodeValue = true
}
}
// Check '+', and remember to replace it with empty space.
else if (c === 43) {
if (equalityIndex > startingIndex) {
valueHasPlus = true
} else {
keyHasPlus = true
}
}
// Check '%' character for encoding
else if (c === 37) {
if (equalityIndex > startingIndex) {
shouldDecodeValue = true
} else {
shouldDecodeKey = true
}
}
}
return result
}
function getAsPrimitive(value: any) {
const type = typeof value
if (type === "string") {
// Length check is handled inside encodeString function
return encodeString(value)
} else if (type === "bigint" || type === "boolean") {
return "" + value
} else if (type === "number" && Number.isFinite(value)) {
return value < 1e21 ? "" + value : encodeString("" + value)
}
return ""
}
/**
* @category encoding
* @since 1.0.0
*/
export function stringify(input: Record<string, any>): string {
let result = ""
if (input === null || typeof input !== "object") {
return result
}
const separator = "&"
const keys = Object.keys(input)
const keyLength = keys.length
let valueLength = 0
for (let i = 0; i < keyLength; i++) {
const key = keys[i]
const value = input[key]
const encodedKey = encodeString(key) + "="
if (i) {
result += separator
}
if (Array.isArray(value)) {
valueLength = value.length
for (let j = 0; j < valueLength; j++) {
if (j) {
result += separator
}
// Optimization: Dividing into multiple lines improves the performance.
// Since v8 does not need to care about the '+' character if it was one-liner.
result += encodedKey
result += getAsPrimitive(value[j])
}
} else {
result += encodedKey
result += getAsPrimitive(value)
}
}
return result
}
// -----------------------------------------------------------------------------
// This has been taken from Node.js project.
// Full implementation can be found from https://github.com/nodejs/node/blob/main/lib/internal/querystring.js
const hexTable = Array.from(
{ length: 256 },
(_, i) => "%" + ((i < 16 ? "0" : "") + i.toString(16)).toUpperCase(),
)
// These characters do not need escaping when generating query strings:
// ! - . _ ~
// ' ( ) *
// digits
// alpha (uppercase)
// alpha (lowercase)
// biome-ignore format: the array should not be formatted
const noEscape = new Int8Array([
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0, // 0 - 15
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0, // 16 - 31
0,
1,
0,
0,
0,
0,
0,
1,
1,
1,
1,
0,
0,
1,
1,
0, // 32 - 47
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
0,
0,
0,
0,
0,
0, // 48 - 63
0,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1, // 64 - 79
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
0,
0,
0,
0,
1, // 80 - 95
0,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1, // 96 - 111
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
0,
0,
0,
1,
0, // 112 - 127
])
function encodeString(str: string) {
const len = str.length
if (len === 0) return ""
let out = ""
let lastPos = 0
let i = 0
outer: for (; i < len; i++) {
let c = str.charCodeAt(i)
// ASCII
while (c < 0x80) {
if (noEscape[c] !== 1) {
if (lastPos < i) out += str.slice(lastPos, i)
lastPos = i + 1
out += hexTable[c]
}
if (++i === len) break outer
c = str.charCodeAt(i)
}
if (lastPos < i) out += str.slice(lastPos, i)
// Multi-byte characters ...
if (c < 0x800) {
lastPos = i + 1
out += hexTable[0xc0 | (c >> 6)] + hexTable[0x80 | (c & 0x3f)]
continue
}
if (c < 0xd800 || c >= 0xe000) {
lastPos = i + 1
out +=
hexTable[0xe0 | (c >> 12)] +
hexTable[0x80 | ((c >> 6) & 0x3f)] +
hexTable[0x80 | (c & 0x3f)]
continue
}
// Surrogate pair
++i
// This branch should never happen because all URLSearchParams entries
// should already be converted to USVString. But, included for
// completion's sake anyway.
if (i >= len) {
throw new Error("URI malformed")
}
const c2 = str.charCodeAt(i) & 0x3ff
lastPos = i + 1
c = 0x10000 + (((c & 0x3ff) << 10) | c2)
out +=
hexTable[0xf0 | (c >> 18)] +
hexTable[0x80 | ((c >> 12) & 0x3f)] +
hexTable[0x80 | ((c >> 6) & 0x3f)] +
hexTable[0x80 | (c & 0x3f)]
}
if (lastPos === 0) return str
if (lastPos < len) return out + str.slice(lastPos)
return out
}

Xet Storage Details

Size:
7.75 kB
·
Xet hash:
7ad86ca9dd54894968a373e2e9f15b47fb0ebf82e3ba8a6d22f5f2d3f51e398c

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.