Ignore consecutive semicolons in the CSS parser (#18532)

Fixes #18523

I swear I'd already landed this but apparently not.
This commit is contained in:
Jordan Pittman 2025-07-14 11:44:31 -04:00 committed by GitHub
parent e0eac192ff
commit 798a7bf905
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 34 additions and 17 deletions

View File

@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Detect classes inside Elixir charlist, word list, and string sigils ([#18432](https://github.com/tailwindlabs/tailwindcss/pull/18432))
- Track source locations through `@plugin` and `@config` ([#18345](https://github.com/tailwindlabs/tailwindcss/pull/18345))
- Handle when `process.env.DEBUG` is a boolean in `@tailwindcss/node` ([#18485](https://github.com/tailwindlabs/tailwindcss/pull/18485))
- Ignore consecutive semicolons in the CSS parser ([#18532](https://github.com/tailwindlabs/tailwindcss/pull/18532))
## [4.1.11] - 2025-06-26

View File

@ -1078,6 +1078,38 @@ describe.each(['Unix', 'Windows'])('Line endings: %s', (lineEndings) => {
},
])
})
it('should ignore consecutive semicolons', () => {
expect(parse(';;;')).toEqual([])
})
it('should ignore semicolons after an at-rule with a body', () => {
expect(parse('@plugin "foo" {} ;')).toEqual([
{
kind: 'at-rule',
name: '@plugin',
params: '"foo"',
nodes: [],
},
])
})
it('should ignore consecutive semicolons a declaration', () => {
expect(parse('.foo { color: red;;; }')).toEqual([
{
kind: 'rule',
selector: '.foo',
nodes: [
{
kind: 'declaration',
property: 'color',
value: 'red',
important: false,
},
],
},
])
})
})
describe('errors', () => {
@ -1163,22 +1195,6 @@ describe.each(['Unix', 'Windows'])('Line endings: %s', (lineEndings) => {
`[Error: Invalid declaration: \`bar\`]`,
)
})
it('should error when a semicolon exists after an at-rule with a body', () => {
expect(() => parse('@plugin "foo" {} ;')).toThrowErrorMatchingInlineSnapshot(
`[Error: Unexpected semicolon]`,
)
})
it('should error when consecutive semicolons exist', () => {
expect(() => parse(';;;')).toThrowErrorMatchingInlineSnapshot(`[Error: Unexpected semicolon]`)
})
it('should error when consecutive semicolons exist after a declaration', () => {
expect(() => parse('.foo { color: red;;; }')).toThrowErrorMatchingInlineSnapshot(
`[Error: Unexpected semicolon]`,
)
})
})
it('ignores BOM at the beginning of a file', () => {

View File

@ -333,7 +333,7 @@ export function parse(input: string, opts?: ParseOptions) {
) {
let declaration = parseDeclaration(buffer)
if (!declaration) {
if (buffer.length === 0) throw new Error('Unexpected semicolon')
if (buffer.length === 0) continue
throw new Error(`Invalid declaration: \`${buffer.trim()}\``)
}