Files
scriptc/tests/corpus/structured-text-boundaries.js
Chris Tate 150e529d84 Streamline structured text scanning and serialization
- Share bounded JSON scanning and copy string spans in chunks.
- Avoid temporary key snapshots for primitive containers.
- Preserve Unicode, property ordering, and callback behavior.
2026-10-05 23:41:57 -05:00

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); }