/
githubmirror
/
webpack
Обзор
Документация
Войти
/
githubmirror
/
webpack
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
test/parseJson.unittest.js
159 строк
5 KB
Alexander Akait
test: run AbstractMethodError and parseJson unit tests under Bun (#21273)
24 июн 2026, 21:18
Не верифицирован
24 июн 2026, 21:18
03a0433
Код
Авторство
О чём код?
"use strict"; const JSONParseError = require("../lib/errors/JSONParseError"); const parseJson = require("../lib/util/parseJson"); // parseJson wraps the host engine's JSON.parse error into a JSONParseError. // JSC (Bun) and V8 (Node, Deno) word their SyntaxError messages differently, so // the live cases assert the parts webpack itself produces — name, systemError, // position and the appended "while parsing …" context. The normalization logic // (token→hex, position extraction, source slicing) targets V8-shaped text, so it // is exercised directly against synthetic messages to stay engine-independent. const catchError = (/** @type {() => void} */ fn) => { try { fn(); } catch (err) { return /** @type {JSONParseError} */ (err); } throw new Error("expected parseJson to throw"); }; describe("parseJson", () => { it("parses JSON", () => { const cases = Object.entries({ object: { foo: 1, bar: { baz: [1, 2, 3, "four"] } }, array: [1, 2, null, "hello", { world: true }, false], num: 420.69, null: null, true: true, false: false }).map(([name, obj]) => [name, JSON.stringify(obj)]); for (const [, data] of cases) { // Use JSON.stringify for comparison to ignore Symbol properties expect(JSON.stringify(parseJson(data))).toStrictEqual( JSON.stringify(JSON.parse(data)) ); } }); it("parses JSON if it is a Buffer, removing BOM bytes", () => { const str = JSON.stringify({ foo: 1, bar: { baz: [1, 2, 3, "four"] } }); const data = Buffer.from(str); const bom = Buffer.concat([Buffer.from([0xef, 0xbb, 0xbf]), data]); expect(JSON.stringify(parseJson(/** @type {EXPECTED_ANY} */ (data)))).toBe( str ); expect(JSON.stringify(parseJson(/** @type {EXPECTED_ANY} */ (bom)))).toBe( str ); }); const str = JSON.stringify({ foo: 1, bar: { baz: [1, 2, 3, "four"] } }); const parseErrorCases = [ ["repeated BOM bytes", `\uFEFF\uFEFF${str}`, null], ["trailing control characters", `${str}\b\b\b`, null], ["an unexpected token", "foo", "foo"], ["an unterminated string", '{"foo: bar}', "foo: bar"], ["an unexpected number", "[[1,2],{3,3,3,3,3}]", "[[1,2]"], ["a broken object", '{"6543210', "6543210"], ["characters like a string", "abcde", "abcde"], ["a missing colon", '{"a":1,""', ":1,"] ]; for (const [title, data, snippet] of parseErrorCases) { it(`wraps a JSON.parse failure for ${title}`, () => { const err = catchError(() => parseJson(/** @type {string} */ (data))); expect(err).toBeInstanceOf(JSONParseError); expect(err.name).toBe("JSONParseError"); expect(err.systemError).toBeInstanceOf(SyntaxError); expect(typeof err.position).toBe("number"); expect(err.message).toMatch(/ while parsing /); if (snippet !== null) expect(err.message).toContain(snippet); }); } it("reports the empty string helpfully", () => { const err = catchError(() => parseJson("")); expect(err.name).toBe("JSONParseError"); expect(err.position).toBe(0); expect(err.message).toMatch(/ while parsing empty string$/); }); const nonStringCases = [ [undefined, "Cannot parse undefined"], [new Map(), "Cannot parse [object Map]"], [[], "Cannot parse an empty array"] ]; for (const [input, message] of nonStringCases) { it(`reports a helpful message for ${String(message)}`, () => { const err = catchError(() => parseJson(/** @type {EXPECTED_ANY} */ (input)) ); expect(err.name).toBe("JSONParseError"); expect(err.position).toBe(0); expect(err.message).toBe(message); expect(err.systemError).toBeInstanceOf(SyntaxError); }); } }); describe("JSONParseError", () => { // Feed V8-shaped messages directly so the engine-specific text is fixed and the // transformation is checked the same way on V8 and JSC. const wrap = (/** @type {string} */ message, /** @type {string} */ txt) => new JSONParseError(new SyntaxError(message), txt, txt); it("rewrites an unexpected token to include its char code", () => { const err = wrap("Unexpected token 'o', \"foo\" is not valid JSON", "foo"); expect(err.message).toBe( 'Unexpected token "o" (0x6F), "foo" is not valid JSON while parsing \'foo\'' ); expect(err.position).toBe(0); }); it("extracts the position and quotes a short source verbatim", () => { const err = wrap("Unexpected token x in JSON at position 1", "foo"); expect(err.message).toBe( 'Unexpected token "x" (0x78) in JSON at position 1 while parsing "foo"' ); expect(err.position).toBe(1); }); it("slices a near-context window around the error position", () => { const txt = "0123456789".repeat(5); const err = wrap("Unexpected token x in JSON at position 25", txt); expect(err.position).toBe(25); expect(err.message).toBe( `Unexpected token "x" (0x78) in JSON at position 25 while parsing near "...${txt.slice( 5, 45 )}..."` ); }); it("derives the position for an unexpected end of input", () => { const err = wrap("Unexpected end of JSON input", "{"); expect(err.message).toBe('Unexpected end of JSON input while parsing "{"'); expect(err.position).toBe(0); }); it("handles an empty source", () => { const err = wrap("Unexpected end of JSON input", ""); expect(err.message).toBe( "Unexpected end of JSON input while parsing empty string" ); expect(err.position).toBe(0); }); });