From f78c0e551d2df4149e0f442435ffee883bf7349f Mon Sep 17 00:00:00 2001 From: dajiaohuang Date: Fri, 25 Sep 2026 19:40:52 +0800 Subject: [PATCH] fix(codegen): serialize object keys safely --- packages/codegen/src/serialize.test.ts | 27 ++++++++++++++++++++++++++ packages/codegen/src/serialize.ts | 11 +++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 packages/codegen/src/serialize.test.ts diff --git a/packages/codegen/src/serialize.test.ts b/packages/codegen/src/serialize.test.ts new file mode 100644 index 00000000..c9aaca71 --- /dev/null +++ b/packages/codegen/src/serialize.test.ts @@ -0,0 +1,27 @@ +import { describe, expect, it } from "vitest"; +import { serializePropValue } from "./serialize"; + +describe("serializePropValue", () => { + it("quotes non-identifier object keys", () => { + expect(serializePropValue({ "data-testid": "widget" })).toEqual({ + value: '{ "data-testid": "widget" }', + needsBraces: true, + }); + }); + + it("keeps simple identifier keys readable", () => { + expect(serializePropValue({ name: "widget" })).toEqual({ + value: '{ name: "widget" }', + needsBraces: true, + }); + }); + + it("preserves an own __proto__ property", () => { + const value = JSON.parse('{"__proto__":"data"}'); + + expect(serializePropValue(value)).toEqual({ + value: '{ ["__proto__"]: "data" }', + needsBraces: true, + }); + }); +}); diff --git a/packages/codegen/src/serialize.ts b/packages/codegen/src/serialize.ts index 0d67f061..6c6982c6 100644 --- a/packages/codegen/src/serialize.ts +++ b/packages/codegen/src/serialize.ts @@ -92,8 +92,15 @@ export function serializePropValue( .filter(([, v]) => v !== undefined) .map(([k, v]) => { const serialized = serializePropValue(v, opts).value; - // Use shorthand if key matches value for simple identifiers - return `${k}: ${serialized}`; + const quotedKey = JSON.stringify(k) ?? '""'; + // A quoted __proto__ key still has special object-literal semantics. + const propertyKey = + k === "__proto__" + ? `[${quotedKey}]` + : /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(k) + ? k + : quotedKey; + return `${propertyKey}: ${serialized}`; }); return { value: `{ ${entries.join(", ")} }`, needsBraces: true };