mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-21 05:50:55 +08:00
- Share bounded JSON scanning and copy string spans in chunks. - Avoid temporary key snapshots for primitive containers. - Preserve Unicode, property ordering, and callback behavior.
75 lines
3.0 KiB
JavaScript
75 lines
3.0 KiB
JavaScript
// Word boundaries, escaped prefixes and UTF-8 tails share the same JSON path.
|
|
for (let length = 0; length < 40; length++) {
|
|
const prefix = "a".repeat(length);
|
|
const value = prefix + "\n\t\u0000\"\\雪🙂" + "tail".repeat(length);
|
|
const text = JSON.stringify({ [prefix + "\"key"]: value, value, enabled: true });
|
|
console.log(text, JSON.stringify(JSON.parse(text)) === text);
|
|
console.log(JSON.parse('"' + prefix + '\\u0041long plain suffix\\n雪🙂"'));
|
|
try {
|
|
JSON.parse('"' + prefix + '\u0001"');
|
|
} catch (error) {
|
|
console.log(error instanceof SyntaxError);
|
|
}
|
|
}
|
|
|
|
const separators = ["\n", "\r\n", "::", "\u0000", "雪", "🙂", "missing"];
|
|
for (const separator of separators) {
|
|
const text = separator + "ab" + separator + separator + "é🙂" + separator;
|
|
for (const limit of [0, 1, 3, 20, -1, NaN]) {
|
|
console.log(JSON.stringify(text.split(separator, limit)));
|
|
}
|
|
console.log(text.includes(separator), text.indexOf(separator), text.indexOf(separator, 1));
|
|
console.log("".includes(separator), "".indexOf(separator), JSON.stringify("".split(separator)));
|
|
}
|
|
console.log("aaabaaaaab".indexOf("aab"), "aaabaaaaab".indexOf("aab", 3));
|
|
console.log("🙂abc🙂".indexOf("🙂", 1), "🙂abc🙂".indexOf("🙂", 2));
|
|
console.log(JSON.stringify("é🙂".split("", 1)));
|
|
|
|
// Primitive records and dense arrays can change shape between serializations.
|
|
const record = JSON.parse('{"empty":"","text":"é🙂","value":1,"active":true,"nil":null}');
|
|
record.omitted = undefined;
|
|
record.symbol = Symbol("value");
|
|
record.value = -0;
|
|
record.large = Infinity;
|
|
Object.defineProperty(record, "hidden", { get() { throw new Error("not enumerable"); } });
|
|
console.log(JSON.stringify(record), JSON.stringify(record, undefined, ".."));
|
|
record["10"] = 10;
|
|
record["2"] = 2;
|
|
record["01"] = 1;
|
|
record["4294967295"] = 3;
|
|
console.log(JSON.stringify(record));
|
|
delete record["2"];
|
|
record.child = { nested: true };
|
|
console.log(JSON.stringify(record));
|
|
|
|
const values = JSON.parse('[1,"雪",true,null]');
|
|
values.push(undefined, NaN, -0);
|
|
console.log(JSON.stringify(values), JSON.stringify(values, undefined, 2));
|
|
delete values[1];
|
|
values.extra = "ignored";
|
|
values[2] = "replacement";
|
|
console.log(JSON.stringify(values));
|
|
|
|
// Getters, toJSON and replacers retain their live reads and key snapshots.
|
|
const changing = JSON.parse('{"first":1,"later":2}');
|
|
Object.defineProperty(changing, "first", {
|
|
get() { changing.later = 8; changing.extra = 9; return 7; },
|
|
enumerable: true,
|
|
});
|
|
console.log(JSON.stringify(changing), JSON.stringify(changing));
|
|
const outer = JSON.parse('{"child":{},"later":{"value":1}}');
|
|
outer.child.toJSON = function (key) {
|
|
outer.later.value = 5;
|
|
outer.extra = 6;
|
|
return { key, converted: true };
|
|
};
|
|
console.log(JSON.stringify(outer));
|
|
const replaced = JSON.parse('{"first":1,"later":2}');
|
|
console.log(JSON.stringify(replaced, function (key, value) {
|
|
if (key === "first") { this.later = 10; this.extra = 11; }
|
|
return value;
|
|
}));
|
|
const cyclic = JSON.parse('{"value":1}');
|
|
cyclic.self = cyclic;
|
|
try { JSON.stringify(cyclic); } catch (error) { console.log(error instanceof TypeError); }
|