diff --git a/src/stringify.spec.ts b/src/stringify.spec.ts index ffd8b0c8..75812eba 100644 --- a/src/stringify.spec.ts +++ b/src/stringify.spec.ts @@ -28,6 +28,12 @@ describe("Stringify CSS spec compliance", () => { ["a\u{7F}b", String.raw`a\7f b`, "DEL character"], ["a\u{0}b", String.raw`a\fffd b`, "null → FFFD"], ["a'b", String.raw`a\'b`, "single quote"], + ["a=b", String.raw`a\=b`, "equals sign"], + ["a&b", String.raw`a\&b`, "ampersand"], + ["a{b}c", String.raw`a\{b\}c`, "braces"], + ["a?b", String.raw`a\?b`, "question mark"], + ["a@b", String.raw`a\@b`, "at sign"], + ["a`b", String.raw`a\`b`, "backtick"], ]; it.each(escapeCases)("%s → %s (%s)", (name, expected) => { @@ -44,3 +50,19 @@ describe("Stringify CSS spec compliance", () => { expect(stringify(ast)).toBe(name); }); }); + +describe("Stringify round-trips special characters in identifiers", () => { + const selectors = [ + String.raw`.x\&y`, + String.raw`[data-foo\=bar]`, + String.raw`.a\{b\}c`, + String.raw`.w-1\/2`, + String.raw`#a\?b`, + String.raw`.a\@b`, + ]; + it.each(selectors)("%s", (selector) => { + const original = parse(selector); + const roundTripped = parse(stringify(original)); + expect(roundTripped).toStrictEqual(original); + }); +}); diff --git a/src/stringify.ts b/src/stringify.ts index 85850732..4a2617b8 100644 --- a/src/stringify.ts +++ b/src/stringify.ts @@ -32,6 +32,13 @@ const charsToEscapeInName = new Set( "/", ",", ";", + "=", + "&", + "?", + "@", + "`", + "{", + "}", ].map((c) => c.charCodeAt(0)), );