mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-22 05:59:31 +08:00
54 lines
2.2 KiB
TypeScript
54 lines
2.2 KiB
TypeScript
// URLSearchParams parse/serialize edges, byte-for-byte against Node's
|
||
// application/x-www-form-urlencoded: '&' splitting with empty segments
|
||
// skipped, first-'=' pair split, '+' as space, case-insensitive %XX
|
||
// decoding with malformed escapes passing through verbatim, decoded
|
||
// bytes running WHATWG UTF-8 decode-with-replacement (U+FFFD per maximal
|
||
// invalid subpart — %FF, truncated sequences, encoded surrogates), and
|
||
// the serializer's exact byte set ([A-Za-z0-9*\-._] verbatim, space →
|
||
// '+', uppercase %XX otherwise — '~' and '!' encode, '*' does not).
|
||
// Sort order is UTF-16 code units: astral pairs sort BELOW U+E000..FFFF
|
||
// where raw UTF-8 byte order would put them above.
|
||
for (const q of ["", "&", "&&", "a", "=x", "a=", "=", "a==b", "a=b=c", "%", "%2", "%2G", "%2b=%2B", "%ff=%FF", "a+b=c+d", "%41=%61", "??a=1", "a=%E2%88", "a=%ED%A0%80", "🚀=💥"]) {
|
||
const sp = new URLSearchParams(q);
|
||
const parts: string[] = [];
|
||
sp.forEach((v, k) => parts.push(JSON.stringify(k) + ":" + JSON.stringify(v)));
|
||
console.log("q " + JSON.stringify(q) + " -> " + parts.join(",") + " | " + sp.toString() + " | " + String(sp.size));
|
||
}
|
||
// The serializer over every ASCII byte (as one name and one value).
|
||
{
|
||
const sp = new URLSearchParams();
|
||
let s = "";
|
||
for (let i = 1; i < 128; i++) s += String.fromCharCode(i);
|
||
sp.append(s, s);
|
||
console.log(sp.toString());
|
||
}
|
||
// Non-ASCII UTF-8 percent-encodes byte-wise; U+FFFD stays U+FFFD.
|
||
{
|
||
const sp = new URLSearchParams();
|
||
sp.append("é", "漢字");
|
||
sp.append("𝒳", "�x");
|
||
console.log(sp.toString());
|
||
}
|
||
// Sort: code-unit order (empty first, ASCII, astral pair, then U+FFFB).
|
||
{
|
||
const sp = new URLSearchParams();
|
||
sp.append("", "1");
|
||
sp.append("🚀", "2");
|
||
sp.append("", "3");
|
||
sp.append("z", "4");
|
||
sp.append("a", "5");
|
||
sp.append("z", "6");
|
||
sp.sort();
|
||
const ks: string[] = [];
|
||
sp.forEach((v, k) => ks.push(k + "=" + v));
|
||
console.log(ks.join("|"));
|
||
}
|
||
// Round-trip: parse(serialize(list)) preserves the decoded pairs.
|
||
{
|
||
const sp = new URLSearchParams();
|
||
sp.append("a b", "c&d=e");
|
||
sp.append("%", "100%");
|
||
const rt = new URLSearchParams(sp.toString());
|
||
console.log(sp.toString() === rt.toString(), JSON.stringify(rt.get("a b")), JSON.stringify(rt.get("%")));
|
||
}
|