Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions DOM/Sources/Parser.XML.StyleSheet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ extension XMLParser.Scanner {
if let attributes = try scanNextFontFace() {
return (.atRule("font-face"), attributes)
}
if let name = scanUnknownAtRule() {
return (.atRule(name), [:])
}
let selectorTypes = try scanSelectorTypes()
guard !selectorTypes.isEmpty else { return nil }
return (.selector(selectorTypes), try scanAtttributes())
Expand All @@ -148,6 +151,25 @@ extension XMLParser.Scanner {
return try scanAtttributes()
}

/// Skips unknown @ rules (e.g. @media, @supports) including nested blocks.
/// Returns the rule name if an unknown @ rule was consumed, nil otherwise.
mutating func scanUnknownAtRule() -> String? {
guard doScanString("@") else { return nil }
guard let name = try? scanString(upTo: .init(charactersIn: "{")),
doScanString("{") else { return nil }
var depth = 1
while depth > 0 && !isEOF {
if doScanString("{") {
depth += 1
} else if doScanString("}") {
depth -= 1
} else {
_ = try? scanString(upTo: .init(charactersIn: "{}"))
}
}
return name.trimmingCharacters(in: .whitespacesAndNewlines)
}

private mutating func scanNextElement() throws -> String? {
do {
return try scanSelectorName()
Expand Down
41 changes: 41 additions & 0 deletions DOM/Tests/Parser.XML.StyleSheetTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,47 @@ struct ParserXMLStyleSheetTests {
)
}

@Test
func skipsMediaQueries() throws {
let entries = try XMLParser.parseSelectorEntries(
"""
g { fill: #000; }

@media (prefers-color-scheme: dark) {
g { fill: #fff; }
}
"""
)

#expect(
entries == [
.element("g"): ["fill": "#000"]
]
)
}

@Test
func skipsNestedAtRules() throws {
let entries = try XMLParser.parseSelectorEntries(
"""
.a { fill: red; }
@supports (display: grid) {
@media (min-width: 600px) {
.b { fill: blue; }
}
}
.c { stroke: green; }
"""
)

#expect(
entries == [
.class("a"): ["fill": "red"],
.class("c"): ["stroke": "green"]
]
)
}

@Test
func parsesFontFaceEntries() throws {
let entries = try XMLParser.parseFontFaceEntries(
Expand Down