Skip to content

Commit 798a7bf

Browse files
Ignore consecutive semicolons in the CSS parser (#18532)
Fixes #18523 I swear I'd already landed this but apparently not.
1 parent e0eac19 commit 798a7bf

File tree

3 files changed

+34
-17
lines changed

3 files changed

+34
-17
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
- Detect classes inside Elixir charlist, word list, and string sigils ([#18432](https://github.com/tailwindlabs/tailwindcss/pull/18432))
1515
- Track source locations through `@plugin` and `@config` ([#18345](https://github.com/tailwindlabs/tailwindcss/pull/18345))
1616
- Handle when `process.env.DEBUG` is a boolean in `@tailwindcss/node` ([#18485](https://github.com/tailwindlabs/tailwindcss/pull/18485))
17+
- Ignore consecutive semicolons in the CSS parser ([#18532](https://github.com/tailwindlabs/tailwindcss/pull/18532))
1718

1819
## [4.1.11] - 2025-06-26
1920

packages/tailwindcss/src/css-parser.test.ts

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,38 @@ describe.each(['Unix', 'Windows'])('Line endings: %s', (lineEndings) => {
10781078
},
10791079
])
10801080
})
1081+
1082+
it('should ignore consecutive semicolons', () => {
1083+
expect(parse(';;;')).toEqual([])
1084+
})
1085+
1086+
it('should ignore semicolons after an at-rule with a body', () => {
1087+
expect(parse('@plugin "foo" {} ;')).toEqual([
1088+
{
1089+
kind: 'at-rule',
1090+
name: '@plugin',
1091+
params: '"foo"',
1092+
nodes: [],
1093+
},
1094+
])
1095+
})
1096+
1097+
it('should ignore consecutive semicolons a declaration', () => {
1098+
expect(parse('.foo { color: red;;; }')).toEqual([
1099+
{
1100+
kind: 'rule',
1101+
selector: '.foo',
1102+
nodes: [
1103+
{
1104+
kind: 'declaration',
1105+
property: 'color',
1106+
value: 'red',
1107+
important: false,
1108+
},
1109+
],
1110+
},
1111+
])
1112+
})
10811113
})
10821114

10831115
describe('errors', () => {
@@ -1163,22 +1195,6 @@ describe.each(['Unix', 'Windows'])('Line endings: %s', (lineEndings) => {
11631195
`[Error: Invalid declaration: \`bar\`]`,
11641196
)
11651197
})
1166-
1167-
it('should error when a semicolon exists after an at-rule with a body', () => {
1168-
expect(() => parse('@plugin "foo" {} ;')).toThrowErrorMatchingInlineSnapshot(
1169-
`[Error: Unexpected semicolon]`,
1170-
)
1171-
})
1172-
1173-
it('should error when consecutive semicolons exist', () => {
1174-
expect(() => parse(';;;')).toThrowErrorMatchingInlineSnapshot(`[Error: Unexpected semicolon]`)
1175-
})
1176-
1177-
it('should error when consecutive semicolons exist after a declaration', () => {
1178-
expect(() => parse('.foo { color: red;;; }')).toThrowErrorMatchingInlineSnapshot(
1179-
`[Error: Unexpected semicolon]`,
1180-
)
1181-
})
11821198
})
11831199

11841200
it('ignores BOM at the beginning of a file', () => {

packages/tailwindcss/src/css-parser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ export function parse(input: string, opts?: ParseOptions) {
333333
) {
334334
let declaration = parseDeclaration(buffer)
335335
if (!declaration) {
336-
if (buffer.length === 0) throw new Error('Unexpected semicolon')
336+
if (buffer.length === 0) continue
337337
throw new Error(`Invalid declaration: \`${buffer.trim()}\``)
338338
}
339339

0 commit comments

Comments
 (0)