diff --git a/.changeset/twenty-windows-peel.md b/.changeset/twenty-windows-peel.md new file mode 100644 index 00000000..ca2de15d --- /dev/null +++ b/.changeset/twenty-windows-peel.md @@ -0,0 +1,5 @@ +--- +'@css-modules-kit/core': patch +--- + +fix: disallow non-JavaScript identifier `@value` diff --git a/packages/core/src/parser/at-value-parser.test.ts b/packages/core/src/parser/at-value-parser.test.ts index 5fa7b213..3fc995f3 100644 --- a/packages/core/src/parser/at-value-parser.test.ts +++ b/packages/core/src/parser/at-value-parser.test.ts @@ -412,10 +412,12 @@ describe('parseAtValue', () => { `); }); test('invalid', () => { - const [atValue1, atValue2] = fakeAtValues( + const [atValue1, atValue2, atValue3, atValue4] = fakeAtValues( fakeRoot(dedent` @value; @value a,,b from "test.css"; + @value non-js-ident-1: #000; + @value non-js-ident-1, non-js-ident-2 as alias_1, a as non-js-ident-3 from "test.css"; `), ); expect(parseAtValue(atValue1!)).toMatchInlineSnapshot(` @@ -496,5 +498,70 @@ describe('parseAtValue', () => { ], } `); + expect(parseAtValue(atValue3!)).toMatchInlineSnapshot(` + { + "diagnostics": [ + { + "category": "error", + "length": 14, + "start": { + "column": 8, + "line": 3, + }, + "text": "css-modules-kit does not support non-JavaScript identifier as value names.", + }, + ], + } + `); + expect(parseAtValue(atValue4!)).toMatchInlineSnapshot(` + { + "atValue": { + "from": "test.css", + "fromLoc": { + "end": { + "column": 85, + "line": 4, + "offset": 150, + }, + "start": { + "column": 77, + "line": 4, + "offset": 142, + }, + }, + "type": "valueImportDeclaration", + "values": [], + }, + "diagnostics": [ + { + "category": "error", + "length": 14, + "start": { + "column": 8, + "line": 4, + }, + "text": "css-modules-kit does not support non-JavaScript identifier as value names.", + }, + { + "category": "error", + "length": 14, + "start": { + "column": 24, + "line": 4, + }, + "text": "css-modules-kit does not support non-JavaScript identifier as value names.", + }, + { + "category": "error", + "length": 14, + "start": { + "column": 56, + "line": 4, + }, + "text": "css-modules-kit does not support non-JavaScript identifier as value names.", + }, + ], + } + `); }); }); diff --git a/packages/core/src/parser/at-value-parser.ts b/packages/core/src/parser/at-value-parser.ts index 0118e17a..3c81e20d 100644 --- a/packages/core/src/parser/at-value-parser.ts +++ b/packages/core/src/parser/at-value-parser.ts @@ -1,5 +1,6 @@ import type { AtRule } from 'postcss'; import type { DiagnosticPosition, DiagnosticWithDetachedLocation, Location } from '../type.js'; +import { JS_IDENTIFIER_PATTERN } from '../util.js'; interface ValueDeclaration { type: 'valueDeclaration'; @@ -83,6 +84,17 @@ export function parseAtValue(atValue: AtRule): ParseAtValueResult { column: start.column + name.length, offset: start.offset + name.length, }; + + if (!JS_IDENTIFIER_PATTERN.test(name)) { + diagnostics.push({ + start: { line: start.line, column: start.column }, + length: name.length, + text: `css-modules-kit does not support non-JavaScript identifier as value names.`, + category: 'error', + }); + continue; + } + const result = { name, loc: { start, end } }; if (localName === undefined) { values.push(result); @@ -98,6 +110,17 @@ export function parseAtValue(atValue: AtRule): ParseAtValueResult { column: start.column + localName.length, offset: start.offset + localName.length, }; + + if (!JS_IDENTIFIER_PATTERN.test(localName)) { + diagnostics.push({ + start: { line: start.line, column: start.column }, + length: localName.length, + text: `css-modules-kit does not support non-JavaScript identifier as value names.`, + category: 'error', + }); + continue; + } + values.push({ ...result, localName, localLoc: { start, end } }); } } else { @@ -154,6 +177,17 @@ export function parseAtValue(atValue: AtRule): ParseAtValueResult { column: start.column + name.length, offset: start.offset + name.length, }; + + if (!JS_IDENTIFIER_PATTERN.test(name)) { + diagnostics.push({ + start: { line: start.line, column: start.column }, + length: name.length, + text: `css-modules-kit does not support non-JavaScript identifier as value names.`, + category: 'error', + }); + return { diagnostics }; + } + const parsedAtValue: ValueDeclaration = { type: 'valueDeclaration', name,