Skip to content

Commit a247518

Browse files
mizdraclaude
andauthored
refactor(core): parse @value with postcss-value-parser (#412)
Replace the regex-based parser with postcss-value-parser, which provides node positions directly. This removes the manual line/column/offset arithmetic and aligns the implementation with composes-parser. Behavior for syntax supported by css-loader is unchanged. For syntax not supported by css-loader, the leading word is now accepted as the token name instead of emitting a diagnostic. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 41ec0a2 commit a247518

3 files changed

Lines changed: 193 additions & 152 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@css-modules-kit/core': minor
3+
---
4+
5+
refactor(core): parse `@value` with postcss-value-parser
6+
7+
The `@value` parser is reimplemented on top of postcss-value-parser. Behavior for syntax supported by css-loader is unchanged.
8+
9+
For syntax that css-loader does not support (where css-modules-kit does not guarantee a specific behavior), the result changed:
10+
11+
- `@value \\c: #000;` and `@value \'d: #000;` are now parsed as a token declaration instead of reporting an error.
12+
- `@value \31 e: #000;` is now read as the token name `\31` instead of `e`.

packages/core/src/parser/at-value-parser.test.ts

Lines changed: 63 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { fakeAtValues, fakeRoot } from '../test/ast.js';
44
import { parseAtValue } from './at-value-parser.js';
55

66
describe('parseAtValue', () => {
7-
test('valid', () => {
7+
test('parses syntax supported by css-loader', () => {
88
const atValues = fakeAtValues(
99
fakeRoot(dedent`
1010
@value basic: #000;
@@ -411,10 +411,14 @@ describe('parseAtValue', () => {
411411
]
412412
`);
413413
});
414-
test('invalid', () => {
415-
// NOTE: These test cases are invalid as the syntax of @value. The behavior when using
416-
// these syntaxes is undefined. A diagnostic like "`@value` is a invalid syntax." may
417-
// or may not be reported.
414+
test('parses syntax unsupported by css-loader', () => {
415+
// NOTE: These syntaxes are not supported by css-loader, so css-modules-kit does not
416+
// guarantee any specific behavior for them. The snapshots below document how the current
417+
// implementation parses them rather than a behavior we commit to.
418+
//
419+
// The `@value \31 e` case is tokenized as `\31` and `e` instead of a single ident `1e`,
420+
// because postcss-value-parser does not interpret CSS escape sequences in identifiers.
421+
// This is a known bug: https://github.com/postcss/postcss-value-parser/issues/64
418422
const atValues = fakeAtValues(
419423
fakeRoot(dedent`
420424
@value;
@@ -494,38 +498,74 @@ describe('parseAtValue', () => {
494498
"category": "error",
495499
"length": 0,
496500
"start": {
497-
"column": 8,
501+
"column": 10,
498502
"line": 2,
499503
},
500504
"text": "\`\` is invalid syntax.",
501505
},
502506
],
503507
},
504508
{
505-
"diagnostics": [
506-
{
507-
"category": "error",
508-
"length": 17,
509+
"atValue": {
510+
"declarationLoc": {
511+
"end": {
512+
"column": 17,
513+
"line": 3,
514+
"offset": 53,
515+
},
509516
"start": {
510517
"column": 1,
511518
"line": 3,
519+
"offset": 37,
512520
},
513-
"text": "\`@value \\\\c: #000\` is a invalid syntax.",
514521
},
515-
],
522+
"loc": {
523+
"end": {
524+
"column": 11,
525+
"line": 3,
526+
"offset": 47,
527+
},
528+
"start": {
529+
"column": 8,
530+
"line": 3,
531+
"offset": 44,
532+
},
533+
},
534+
"name": "\\\\c",
535+
"type": "valueDeclaration",
536+
},
537+
"diagnostics": [],
516538
},
517539
{
518-
"diagnostics": [
519-
{
520-
"category": "error",
521-
"length": 17,
540+
"atValue": {
541+
"declarationLoc": {
542+
"end": {
543+
"column": 17,
544+
"line": 4,
545+
"offset": 71,
546+
},
522547
"start": {
523548
"column": 1,
524549
"line": 4,
550+
"offset": 55,
525551
},
526-
"text": "\`@value \\'d: #000\` is a invalid syntax.",
527552
},
528-
],
553+
"loc": {
554+
"end": {
555+
"column": 11,
556+
"line": 4,
557+
"offset": 65,
558+
},
559+
"start": {
560+
"column": 8,
561+
"line": 4,
562+
"offset": 62,
563+
},
564+
},
565+
"name": "\\'d",
566+
"type": "valueDeclaration",
567+
},
568+
"diagnostics": [],
529569
},
530570
{
531571
"atValue": {
@@ -543,17 +583,17 @@ describe('parseAtValue', () => {
543583
},
544584
"loc": {
545585
"end": {
546-
"column": 13,
586+
"column": 11,
547587
"line": 5,
548-
"offset": 85,
588+
"offset": 83,
549589
},
550590
"start": {
551-
"column": 12,
591+
"column": 8,
552592
"line": 5,
553-
"offset": 84,
593+
"offset": 80,
554594
},
555595
},
556-
"name": "e",
596+
"name": "\\31",
557597
"type": "valueDeclaration",
558598
},
559599
"diagnostics": [],

0 commit comments

Comments
 (0)