import { Buffer } from "node:buffer";
import { encodeStr, hexTable } from "ext:deno_node/internal/querystring.ts";
import { unhexTable } from "ext:deno_node/internal_binding/_utils.ts";
export const decode = parse;
export const encode = stringify;
function qsEscape(str) {
if (typeof str !== "string") {
if (typeof str === "object") {
str = String(str);
} else {
str += "";
}
}
return encodeStr(str, noEscape, hexTable);
}
export const escape = qsEscape;
const isHexTable = new Int8Array([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]);
function charCodes(str) {
const ret = new Array(str.length);
for (let i = 0; i < str.length; ++i) {
ret[i] = str.charCodeAt(i);
}
return ret;
}
function addKeyVal(
obj,
key,
value,
keyEncoded,
valEncoded,
decode,
) {
if (key.length > 0 && keyEncoded) {
key = decodeStr(key, decode);
}
if (value.length > 0 && valEncoded) {
value = decodeStr(value, decode);
}
if (obj[key] === undefined) {
obj[key] = value;
} else {
const curValue = obj[key];
if (curValue.pop) {
curValue[curValue.length] = value;
} else {
obj[key] = [curValue, value];
}
}
}
export function parse(
str,
sep = "&",
eq = "=",
{ decodeURIComponent, maxKeys = 1000 } = {},
) {
const obj = Object.create(null);
if (typeof str !== "string" || str.length === 0) {
return obj;
}
const sepCodes = !sep ? [38] : charCodes(String(sep));
const eqCodes = !eq ? [61] : charCodes(String(eq));
const sepLen = sepCodes.length;
const eqLen = eqCodes.length;
let pairs = 1000;
if (typeof maxKeys === "number") {
pairs = maxKeys > 0 ? maxKeys : -1;
}
let decode = QS.unescape;
if (decodeURIComponent) {
decode = decodeURIComponent;
}
const customDecode = decode !== unescape;
let lastPos = 0;
let sepIdx = 0;
let eqIdx = 0;
let key = "";
let value = "";
let keyEncoded = customDecode;
let valEncoded = customDecode;
const plusChar = customDecode ? "%20" : " ";
let encodeCheck = 0;
for (let i = 0; i < str.length; ++i) {
const code = str.charCodeAt(i);
if (code === sepCodes[sepIdx]) {
if (++sepIdx === sepLen) {
const end = i - sepIdx + 1;
if (eqIdx < eqLen) {
if (lastPos < end) {
key += str.slice(lastPos, end);
} else if (key.length === 0) {
if (--pairs === 0) {
return obj;
}
lastPos = i + 1;
sepIdx = eqIdx = 0;
continue;
}
} else if (lastPos < end) {
value += str.slice(lastPos, end);
}
addKeyVal(obj, key, value, keyEncoded, valEncoded, decode);
if (--pairs === 0) {
return obj;
}
key = value = "";
encodeCheck = 0;
lastPos = i + 1;
sepIdx = eqIdx = 0;
}
} else {
sepIdx = 0;
if (eqIdx < eqLen) {
if (code === eqCodes[eqIdx]) {
if (++eqIdx === eqLen) {
const end = i - eqIdx + 1;
if (lastPos < end) {
key += str.slice(lastPos, end);
}
encodeCheck = 0;
lastPos = i + 1;
}
continue;
} else {
eqIdx = 0;
if (!keyEncoded) {
if (code === 37 ) {
encodeCheck = 1;
continue;
} else if (encodeCheck > 0) {
if (isHexTable[code] === 1) {
if (++encodeCheck === 3) {
keyEncoded = true;
}
continue;
} else {
encodeCheck = 0;
}
}
}
}
if (code === 43 ) {
if (lastPos < i) {
key += str.slice(lastPos, i);
}
key += plusChar;
lastPos = i + 1;
continue;
}
}
if (code === 43 ) {
if (lastPos < i) {
value += str.slice(lastPos, i);
}
value += plusChar;
lastPos = i + 1;
} else if (!valEncoded) {
if (code === 37 ) {
encodeCheck = 1;
} else if (encodeCheck > 0) {
if (isHexTable[code] === 1) {
if (++encodeCheck === 3) {
valEncoded = true;
}
} else {
encodeCheck = 0;
}
}
}
}
}
if (lastPos < str.length) {
if (eqIdx < eqLen) {
key += str.slice(lastPos);
} else if (sepIdx < sepLen) {
value += str.slice(lastPos);
}
} else if (eqIdx === 0 && key.length === 0) {
return obj;
}
addKeyVal(obj, key, value, keyEncoded, valEncoded, decode);
return obj;
}
const noEscape = new Int8Array([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, ]);
function stringifyPrimitive(v) {
if (typeof v === "string") {
return v;
}
if (typeof v === "number" && isFinite(v)) {
return "" + v;
}
if (typeof v === "bigint") {
return "" + v;
}
if (typeof v === "boolean") {
return v ? "true" : "false";
}
return "";
}
function encodeStringifiedCustom(
v,
encode,
) {
return encode(stringifyPrimitive(v));
}
function encodeStringified(v, encode) {
if (typeof v === "string") {
return (v.length ? encode(v) : "");
}
if (typeof v === "number" && isFinite(v)) {
return (Math.abs(v) < 1e21 ? "" + v : encode("" + v));
}
if (typeof v === "bigint") {
return "" + v;
}
if (typeof v === "boolean") {
return v ? "true" : "false";
}
return "";
}
export function stringify(
obj,
sep,
eq,
options,
) {
sep ||= "&";
eq ||= "=";
const encode = options ? (options.encodeURIComponent || qsEscape) : qsEscape;
const convert = options ? encodeStringifiedCustom : encodeStringified;
if (obj !== null && typeof obj === "object") {
const keys = Object.keys(obj);
const len = keys.length;
let fields = "";
for (let i = 0; i < len; ++i) {
const k = keys[i];
const v = obj[k];
let ks = convert(k, encode);
ks += eq;
if (Array.isArray(v)) {
const vlen = v.length;
if (vlen === 0) continue;
if (fields) {
fields += sep;
}
for (let j = 0; j < vlen; ++j) {
if (j) {
fields += sep;
}
fields += ks;
fields += convert(v[j], encode);
}
} else {
if (fields) {
fields += sep;
}
fields += ks;
fields += convert(v, encode);
}
}
return fields;
}
return "";
}
export function unescapeBuffer(s, decodeSpaces = false) {
const out = Buffer.alloc(s.length);
let index = 0;
let outIndex = 0;
let currentChar;
let nextChar;
let hexHigh;
let hexLow;
const maxLength = s.length - 2;
let hasHex = false;
while (index < s.length) {
currentChar = s.charCodeAt(index);
if (currentChar === 43 && decodeSpaces) {
out[outIndex++] = 32; index++;
continue;
}
if (currentChar === 37 && index < maxLength) {
currentChar = s.charCodeAt(++index);
hexHigh = unhexTable[currentChar];
if (!(hexHigh >= 0)) {
out[outIndex++] = 37; continue;
} else {
nextChar = s.charCodeAt(++index);
hexLow = unhexTable[nextChar];
if (!(hexLow >= 0)) {
out[outIndex++] = 37; index--;
} else {
hasHex = true;
currentChar = hexHigh * 16 + hexLow;
}
}
}
out[outIndex++] = currentChar;
index++;
}
return hasHex ? out.slice(0, outIndex) : out;
}
function qsUnescape(s) {
try {
return decodeURIComponent(s);
} catch {
return unescapeBuffer(s).toString();
}
}
function decodeStr(s, decoder) {
try {
return decoder(s);
} catch {
return QS.unescape(s);
}
}
export const unescape = qsUnescape;
const QS = {
parse,
stringify,
decode,
encode,
unescape,
escape,
unescapeBuffer,
};
export default QS;