css: handle top-level semicolons in parser

This commit is contained in:
Adrià Arrufat
2026-03-14 20:11:30 +09:00
parent bc19079dad
commit 66a86541d1
2 changed files with 27 additions and 6 deletions

View File

@@ -318,12 +318,6 @@ pub const RulesIterator = struct {
var selector_start: ?usize = null;
var selector_end: ?usize = null;
// Skip leading trivia
while (self.stream.peek()) |peeked| {
if (!isWhitespaceOrComment(peeked.token)) break;
_ = self.stream.next();
}
while (true) {
const peeked = self.stream.peek() orelse return null;
@@ -370,6 +364,11 @@ pub const RulesIterator = struct {
continue;
}
if (selector_start == null and (isWhitespaceOrComment(peeked.token) or isSemicolon(peeked.token))) {
_ = self.stream.next();
continue;
}
const span = self.stream.next() orelse return null;
if (!isWhitespaceOrComment(span.token)) {
if (selector_start == null) selector_start = span.start;
@@ -470,3 +469,13 @@ test "RulesIterator: comments and whitespace" {
try testing.expectEqualStrings(" /* comment */ color: red; ", rule.block);
try testing.expectEqual(@as(?Rule, null), it.next());
}
test "RulesIterator: top-level semicolons" {
var it = RulesIterator.init("*{}; ; p{}");
var rule = it.next() orelse return error.MissingRule;
try testing.expectEqualStrings("*", rule.selector);
rule = it.next() orelse return error.MissingRule;
try testing.expectEqualStrings("p", rule.selector);
try testing.expectEqual(@as(?Rule, null), it.next());
}

View File

@@ -468,6 +468,18 @@
}
</script>
<script id="CSSStyleSheet_insertRule_semicolon">
{
const style = document.createElement('style');
document.head.appendChild(style);
const sheet = style.sheet;
// Should not throw even with trailing semicolon
sheet.insertRule('*{};');
testing.expectEqual(1, sheet.cssRules.length);
}
</script>
<script id="CSSStyleSheet_replaceSync">
{
const sheet = new CSSStyleSheet();