1use crate::declaration::{parse_declaration, DeclarationBlock, DeclarationList};
2use crate::error::{Error, ParserError, PrinterError};
3use crate::media_query::*;
4use crate::printer::Printer;
5use crate::properties::custom::TokenList;
6use crate::rules::container::{ContainerCondition, ContainerName, ContainerRule};
7use crate::rules::font_palette_values::FontPaletteValuesRule;
8use crate::rules::layer::{LayerBlockRule, LayerStatementRule};
9use crate::rules::property::PropertyRule;
10use crate::rules::scope::ScopeRule;
11use crate::rules::starting_style::StartingStyleRule;
12use crate::rules::viewport::ViewportRule;
13
14use crate::rules::{
15 counter_style::CounterStyleRule,
16 custom_media::CustomMediaRule,
17 document::MozDocumentRule,
18 font_face::{FontFaceDeclarationParser, FontFaceRule},
19 import::ImportRule,
20 keyframes::{KeyframeListParser, KeyframesName, KeyframesRule},
21 layer::LayerName,
22 media::MediaRule,
23 namespace::NamespaceRule,
24 nesting::NestingRule,
25 page::{PageRule, PageSelector},
26 style::StyleRule,
27 supports::{SupportsCondition, SupportsRule},
28 unknown::UnknownAtRule,
29 CssRule, CssRuleList, Location,
30};
31use crate::selector::{Component, SelectorList, SelectorParser};
32use crate::traits::Parse;
33use crate::values::ident::{CustomIdent, DashedIdent};
34use crate::values::string::CowArcStr;
35use crate::vendor_prefix::VendorPrefix;
36#[cfg(feature = "visitor")]
37use crate::visitor::{Visit, VisitTypes, Visitor};
38use bitflags::bitflags;
39use cssparser::*;
40use parcel_selectors::parser::{NestingRequirement, ParseErrorRecovery};
41use std::sync::{Arc, RwLock};
42
43bitflags! {
44 #[derive(Clone, Debug, Default)]
46 pub struct ParserFlags: u8 {
47 const NESTING = 1 << 0;
49 const CUSTOM_MEDIA = 1 << 1;
51 const DEEP_SELECTOR_COMBINATOR = 1 << 2;
53 }
54}
55
56#[derive(Clone, Debug, Default)]
58pub struct ParserOptions<'o, 'i> {
59 pub filename: String,
61 pub css_modules: Option<crate::css_modules::Config<'o>>,
63 pub source_index: u32,
66 pub error_recovery: bool,
68 pub warnings: Option<Arc<RwLock<Vec<Error<ParserError<'i>>>>>>,
70 pub flags: ParserFlags,
72}
73
74impl<'o, 'i> ParserOptions<'o, 'i> {
75 #[inline]
76 pub(crate) fn warn(&self, warning: ParseError<'i, ParserError<'i>>) {
77 if let Some(warnings) = &self.warnings {
78 if let Ok(mut warnings) = warnings.write() {
79 warnings.push(Error::from(warning, self.filename.clone()));
80 }
81 }
82 }
83}
84
85#[derive(Clone, Default)]
86#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
87pub struct DefaultAtRuleParser;
88impl<'i> crate::traits::AtRuleParser<'i> for DefaultAtRuleParser {
89 type AtRule = DefaultAtRule;
90 type Error = ();
91 type Prelude = ();
92}
93
94#[derive(PartialEq, Clone, Debug)]
95#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
96#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
97pub struct DefaultAtRule;
98impl crate::traits::ToCss for DefaultAtRule {
99 fn to_css<W: std::fmt::Write>(&self, _: &mut Printer<W>) -> Result<(), PrinterError> {
100 Err(PrinterError {
101 kind: crate::error::PrinterErrorKind::FmtError,
102 loc: None,
103 })
104 }
105}
106
107#[cfg(feature = "into_owned")]
108impl<'any> static_self::IntoOwned<'any> for DefaultAtRule {
109 type Owned = Self;
110 fn into_owned(self) -> Self {
111 self
112 }
113}
114
115#[cfg(feature = "visitor")]
116#[cfg_attr(docsrs, doc(cfg(feature = "visitor")))]
117impl<'i, V: Visitor<'i, DefaultAtRule>> Visit<'i, DefaultAtRule, V> for DefaultAtRule {
118 const CHILD_TYPES: VisitTypes = VisitTypes::empty();
119 fn visit_children(&mut self, _: &mut V) -> Result<(), V::Error> {
120 Ok(())
121 }
122}
123
124#[derive(PartialEq, PartialOrd)]
125enum State {
126 Start = 1,
127 Layers = 2,
128 Imports = 3,
129 Namespaces = 4,
130 Body = 5,
131}
132
133pub struct TopLevelRuleParser<'a, 'o, 'i, T: crate::traits::AtRuleParser<'i>> {
135 pub options: &'a ParserOptions<'o, 'i>,
136 state: State,
137 at_rule_parser: &'a mut T,
138 rules: &'a mut CssRuleList<'i, T::AtRule>,
139}
140
141impl<'a, 'o, 'b, 'i, T: crate::traits::AtRuleParser<'i>> TopLevelRuleParser<'a, 'o, 'i, T> {
142 pub fn new(
143 options: &'a ParserOptions<'o, 'i>,
144 at_rule_parser: &'a mut T,
145 rules: &'a mut CssRuleList<'i, T::AtRule>,
146 ) -> Self {
147 TopLevelRuleParser {
148 options,
149 state: State::Start,
150 at_rule_parser,
151 rules,
152 }
153 }
154
155 pub fn nested<'x: 'b>(&'x mut self) -> NestedRuleParser<'_, 'o, 'i, T> {
156 NestedRuleParser {
157 options: &self.options,
158 at_rule_parser: self.at_rule_parser,
159 declarations: DeclarationList::new(),
160 important_declarations: DeclarationList::new(),
161 rules: &mut self.rules,
162 is_in_style_rule: false,
163 allow_declarations: false,
164 }
165 }
166}
167
168#[derive(Debug)]
170#[allow(dead_code)]
171pub enum AtRulePrelude<'i, T> {
172 FontFace,
174 FontFeatureValues, FontPaletteValues(DashedIdent<'i>),
178 CounterStyle(CustomIdent<'i>),
180 Media(MediaList<'i>),
182 CustomMedia(DashedIdent<'i>, MediaList<'i>),
184 Supports(SupportsCondition<'i>),
186 Viewport(VendorPrefix),
188 Keyframes(KeyframesName<'i>, VendorPrefix),
190 Page(Vec<PageSelector<'i>>),
192 MozDocument,
194 Import(
196 CowRcStr<'i>,
197 MediaList<'i>,
198 Option<SupportsCondition<'i>>,
199 Option<Option<LayerName<'i>>>,
200 ),
201 Namespace(Option<CowRcStr<'i>>, CowRcStr<'i>),
203 Charset,
205 Nest(SelectorList<'i>),
207 Layer(Vec<LayerName<'i>>),
209 Property(DashedIdent<'i>),
211 Container(Option<ContainerName<'i>>, ContainerCondition<'i>),
213 StartingStyle,
215 Scope(Option<SelectorList<'i>>, Option<SelectorList<'i>>),
217 Unknown(CowArcStr<'i>, TokenList<'i>),
219 Custom(T),
221}
222
223impl<'i, T> AtRulePrelude<'i, T> {
224 fn allowed_in_style_rule(&self) -> bool {
229 match *self {
230 Self::Media(..)
231 | Self::Supports(..)
232 | Self::Container(..)
233 | Self::MozDocument
234 | Self::Layer(..)
235 | Self::StartingStyle
236 | Self::Scope(..)
237 | Self::Nest(..)
238 | Self::Unknown(..)
239 | Self::Custom(..) => true,
240
241 Self::Namespace(..)
242 | Self::FontFace
243 | Self::FontFeatureValues
244 | Self::FontPaletteValues(..)
245 | Self::CounterStyle(..)
246 | Self::Keyframes(..)
247 | Self::Page(..)
248 | Self::Property(..)
249 | Self::Import(..)
250 | Self::CustomMedia(..)
251 | Self::Viewport(..)
252 | Self::Charset => false,
253 }
254 }
255}
256
257impl<'a, 'o, 'i, T: crate::traits::AtRuleParser<'i>> AtRuleParser<'i> for TopLevelRuleParser<'a, 'o, 'i, T> {
258 type Prelude = AtRulePrelude<'i, T::Prelude>;
259 type AtRule = ();
260 type Error = ParserError<'i>;
261
262 fn parse_prelude<'t>(
263 &mut self,
264 name: CowRcStr<'i>,
265 input: &mut Parser<'i, 't>,
266 ) -> Result<Self::Prelude, ParseError<'i, Self::Error>> {
267 match_ignore_ascii_case! { &*name,
268 "import" => {
269 if self.state > State::Imports {
270 return Err(input.new_custom_error(ParserError::UnexpectedImportRule))
271 }
272
273 let url_string = input.expect_url_or_string()?.clone();
274
275 let layer = if input.try_parse(|input| input.expect_ident_matching("layer")).is_ok() {
276 Some(None)
277 } else if input.try_parse(|input| input.expect_function_matching("layer")).is_ok() {
278 let name = input.parse_nested_block(LayerName::parse).map(|name| Some(name))?;
279 Some(name)
280 } else {
281 None
282 };
283
284 let supports = if input.try_parse(|input| input.expect_function_matching("supports")).is_ok() {
285 Some(input.parse_nested_block(|input| {
286 input.try_parse(SupportsCondition::parse).or_else(|_| SupportsCondition::parse_declaration(input))
287 })?)
288 } else {
289 None
290 };
291 let media = MediaList::parse(input)?;
292 return Ok(AtRulePrelude::Import(url_string, media, supports, layer));
293 },
294 "namespace" => {
295 if self.state > State::Namespaces {
296 return Err(input.new_custom_error(ParserError::UnexpectedNamespaceRule))
297 }
298
299 let prefix = input.try_parse(|input| input.expect_ident_cloned()).ok();
300 let namespace = input.expect_url_or_string()?;
301 let prelude = AtRulePrelude::Namespace(prefix, namespace);
302 return Ok(prelude);
303 },
304 "charset" => {
305 input.expect_string()?;
309 return Ok(AtRulePrelude::Charset)
310 },
311 "custom-media" if self.options.flags.contains(ParserFlags::CUSTOM_MEDIA) => {
312 let name = DashedIdent::parse(input)?;
313 let media = MediaList::parse(input)?;
314 return Ok(AtRulePrelude::CustomMedia(name, media))
315 },
316 "property" => {
317 let name = DashedIdent::parse(input)?;
318 return Ok(AtRulePrelude::Property(name))
319 },
320 _ => {}
321 }
322
323 AtRuleParser::parse_prelude(&mut self.nested(), name, input)
324 }
325
326 #[inline]
327 fn parse_block<'t>(
328 &mut self,
329 prelude: Self::Prelude,
330 start: &ParserState,
331 input: &mut Parser<'i, 't>,
332 ) -> Result<Self::AtRule, ParseError<'i, Self::Error>> {
333 self.state = State::Body;
334 AtRuleParser::parse_block(&mut self.nested(), prelude, start, input)
335 }
336
337 #[inline]
338 fn rule_without_block(
339 &mut self,
340 prelude: AtRulePrelude<'i, T::Prelude>,
341 start: &ParserState,
342 ) -> Result<Self::AtRule, ()> {
343 let loc = start.source_location();
344 let loc = Location {
345 source_index: self.options.source_index,
346 line: loc.line,
347 column: loc.column,
348 };
349
350 match prelude {
351 AtRulePrelude::Import(url, media, supports, layer) => {
352 self.state = State::Imports;
353 self.rules.0.push(CssRule::Import(ImportRule {
354 url: url.into(),
355 layer,
356 supports,
357 media,
358 loc,
359 }));
360 Ok(())
361 }
362 AtRulePrelude::Namespace(prefix, url) => {
363 self.state = State::Namespaces;
364
365 self.rules.0.push(CssRule::Namespace(NamespaceRule {
366 prefix: prefix.map(|x| x.into()),
367 url: url.into(),
368 loc,
369 }));
370 Ok(())
371 }
372 AtRulePrelude::CustomMedia(name, query) => {
373 self.state = State::Body;
374 self.rules.0.push(CssRule::CustomMedia(CustomMediaRule { name, query, loc }));
375 Ok(())
376 }
377 AtRulePrelude::Layer(_) => {
378 if self.state <= State::Layers {
380 self.state = State::Layers;
381 } else {
382 self.state = State::Body;
383 }
384 AtRuleParser::rule_without_block(&mut self.nested(), prelude, start)
385 }
386 AtRulePrelude::Charset => Ok(()),
387 AtRulePrelude::Unknown(name, prelude) => {
388 self.rules.0.push(CssRule::Unknown(UnknownAtRule {
389 name,
390 prelude,
391 block: None,
392 loc,
393 }));
394 Ok(())
395 }
396 AtRulePrelude::Custom(_) => {
397 self.state = State::Body;
398 AtRuleParser::rule_without_block(&mut self.nested(), prelude, start)
399 }
400 _ => Err(()),
401 }
402 }
403}
404
405impl<'a, 'o, 'i, T: crate::traits::AtRuleParser<'i>> QualifiedRuleParser<'i>
406 for TopLevelRuleParser<'a, 'o, 'i, T>
407{
408 type Prelude = SelectorList<'i>;
409 type QualifiedRule = ();
410 type Error = ParserError<'i>;
411
412 #[inline]
413 fn parse_prelude<'t>(
414 &mut self,
415 input: &mut Parser<'i, 't>,
416 ) -> Result<Self::Prelude, ParseError<'i, Self::Error>> {
417 self.state = State::Body;
418 QualifiedRuleParser::parse_prelude(&mut self.nested(), input)
419 }
420
421 #[inline]
422 fn parse_block<'t>(
423 &mut self,
424 prelude: Self::Prelude,
425 start: &ParserState,
426 input: &mut Parser<'i, 't>,
427 ) -> Result<Self::QualifiedRule, ParseError<'i, Self::Error>> {
428 QualifiedRuleParser::parse_block(&mut self.nested(), prelude, start, input)
429 }
430}
431
432pub struct NestedRuleParser<'a, 'o, 'i, T: crate::traits::AtRuleParser<'i>> {
433 pub options: &'a ParserOptions<'o, 'i>,
434 pub at_rule_parser: &'a mut T,
435 declarations: DeclarationList<'i>,
436 important_declarations: DeclarationList<'i>,
437 rules: &'a mut CssRuleList<'i, T::AtRule>,
438 is_in_style_rule: bool,
439 allow_declarations: bool,
440}
441
442impl<'a, 'o, 'b, 'i, T: crate::traits::AtRuleParser<'i>> NestedRuleParser<'a, 'o, 'i, T> {
443 pub fn parse_nested<'t>(
444 &mut self,
445 input: &mut Parser<'i, 't>,
446 is_style_rule: bool,
447 ) -> Result<(DeclarationBlock<'i>, CssRuleList<'i, T::AtRule>), ParseError<'i, ParserError<'i>>> {
448 let mut rules = CssRuleList(vec![]);
449 let mut nested_parser = NestedRuleParser {
450 options: self.options,
451 at_rule_parser: self.at_rule_parser,
452 declarations: DeclarationList::new(),
453 important_declarations: DeclarationList::new(),
454 rules: &mut rules,
455 is_in_style_rule: self.is_in_style_rule || is_style_rule,
456 allow_declarations: self.allow_declarations || self.is_in_style_rule || is_style_rule,
457 };
458
459 let parse_declarations = nested_parser.parse_declarations();
460 let mut errors = Vec::new();
461 let mut iter = RuleBodyParser::new(input, &mut nested_parser);
462 while let Some(result) = iter.next() {
463 match result {
464 Ok(()) => {}
465 Err((e, _)) => {
466 if parse_declarations {
467 iter.parser.declarations.clear();
468 iter.parser.important_declarations.clear();
469 errors.push(e);
470 } else {
471 if iter.parser.options.error_recovery {
472 iter.parser.options.warn(e);
473 continue;
474 }
475 return Err(e);
476 }
477 }
478 }
479 }
480
481 if parse_declarations {
482 if !errors.is_empty() {
483 if self.options.error_recovery {
484 for err in errors {
485 self.options.warn(err);
486 }
487 } else {
488 return Err(errors.remove(0));
489 }
490 }
491 }
492
493 Ok((
494 DeclarationBlock {
495 declarations: nested_parser.declarations,
496 important_declarations: nested_parser.important_declarations,
497 },
498 rules,
499 ))
500 }
501
502 fn parse_style_block<'t>(
503 &mut self,
504 input: &mut Parser<'i, 't>,
505 ) -> Result<CssRuleList<'i, T::AtRule>, ParseError<'i, ParserError<'i>>> {
506 let loc = input.current_source_location();
507 let loc = Location {
508 source_index: self.options.source_index,
509 line: loc.line,
510 column: loc.column,
511 };
512
513 let (declarations, mut rules) = self.parse_nested(input, false)?;
516
517 if declarations.len() > 0 {
518 rules.0.insert(
519 0,
520 CssRule::Style(StyleRule {
521 selectors: Component::Nesting.into(),
522 declarations,
523 vendor_prefix: VendorPrefix::empty(),
524 rules: CssRuleList(vec![]),
525 loc,
526 }),
527 )
528 }
529
530 Ok(rules)
531 }
532
533 fn loc(&self, start: &ParserState) -> Location {
534 let loc = start.source_location();
535 Location {
536 source_index: self.options.source_index,
537 line: loc.line,
538 column: loc.column,
539 }
540 }
541}
542
543impl<'a, 'o, 'b, 'i, T: crate::traits::AtRuleParser<'i>> AtRuleParser<'i> for NestedRuleParser<'a, 'o, 'i, T> {
544 type Prelude = AtRulePrelude<'i, T::Prelude>;
545 type AtRule = ();
546 type Error = ParserError<'i>;
547
548 fn parse_prelude<'t>(
549 &mut self,
550 name: CowRcStr<'i>,
551 input: &mut Parser<'i, 't>,
552 ) -> Result<Self::Prelude, ParseError<'i, Self::Error>> {
553 let result = match_ignore_ascii_case! { &*name,
554 "media" => {
555 let media = MediaList::parse(input)?;
556 AtRulePrelude::Media(media)
557 },
558 "supports" => {
559 let cond = SupportsCondition::parse(input)?;
560 AtRulePrelude::Supports(cond)
561 },
562 "font-face" => {
563 AtRulePrelude::FontFace
564 },
565 "font-palette-values" => {
574 let name = DashedIdent::parse(input)?;
575 AtRulePrelude::FontPaletteValues(name)
576 },
577 "counter-style" => {
578 let name = CustomIdent::parse(input)?;
579 AtRulePrelude::CounterStyle(name)
580 },
581 "viewport" | "-ms-viewport" => {
582 let prefix = if starts_with_ignore_ascii_case(&*name, "-ms") {
583 VendorPrefix::Ms
584 } else {
585 VendorPrefix::None
586 };
587 AtRulePrelude::Viewport(prefix)
588 },
589 "keyframes" | "-webkit-keyframes" | "-moz-keyframes" | "-o-keyframes" | "-ms-keyframes" => {
590 let prefix = if starts_with_ignore_ascii_case(&*name, "-webkit-") {
591 VendorPrefix::WebKit
592 } else if starts_with_ignore_ascii_case(&*name, "-moz-") {
593 VendorPrefix::Moz
594 } else if starts_with_ignore_ascii_case(&*name, "-o-") {
595 VendorPrefix::O
596 } else if starts_with_ignore_ascii_case(&*name, "-ms-") {
597 VendorPrefix::Ms
598 } else {
599 VendorPrefix::None
600 };
601
602 let name = input.try_parse(KeyframesName::parse)?;
603 AtRulePrelude::Keyframes(name, prefix)
604 },
605 "page" => {
606 let selectors = input.try_parse(|input| input.parse_comma_separated(PageSelector::parse)).unwrap_or_default();
607 AtRulePrelude::Page(selectors)
608 },
609 "-moz-document" => {
610 input.expect_function_matching("url-prefix")?;
613 input.parse_nested_block(|input| {
614 let _ = input.try_parse(|input| -> Result<(), ParseError<'i, Self::Error>> {
617 let s = input.expect_string()?;
618 if !s.is_empty() {
619 return Err(input.new_custom_error(ParserError::InvalidValue))
620 }
621 Ok(())
622 });
623 input.expect_exhausted()?;
624 Ok(())
625 })?;
626
627 AtRulePrelude::MozDocument
628 },
629 "layer" => {
630 let names = match Vec::<LayerName>::parse(input) {
631 Ok(names) => names,
632 Err(ParseError { kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput), .. }) => Vec::new(),
633 Err(e) => return Err(e)
634 };
635 AtRulePrelude::Layer(names)
636 },
637 "container" => {
638 let name = input.try_parse(ContainerName::parse).ok();
639 let condition = ContainerCondition::parse(input)?;
640 AtRulePrelude::Container(name, condition)
641 },
642 "starting-style" => {
643 AtRulePrelude::StartingStyle
644 },
645 "scope" => {
646 let selector_parser = SelectorParser {
647 is_nesting_allowed: true,
648 options: &self.options,
649 };
650
651 let scope_start = if input.try_parse(|input| input.expect_parenthesis_block()).is_ok() {
652 Some(input.parse_nested_block(|input| {
653 SelectorList::parse_relative(&selector_parser, input, ParseErrorRecovery::IgnoreInvalidSelector, NestingRequirement::None)
656 })?)
657 } else {
658 None
659 };
660
661 let scope_end = if input.try_parse(|input| input.expect_ident_matching("to")).is_ok() {
662 input.expect_parenthesis_block()?;
663 Some(input.parse_nested_block(|input| {
664 SelectorList::parse_relative(&selector_parser, input, ParseErrorRecovery::IgnoreInvalidSelector, NestingRequirement::None)
665 })?)
666 } else {
667 None
668 };
669
670 AtRulePrelude::Scope(scope_start, scope_end)
671 },
672 "nest" if self.is_in_style_rule => {
673 self.options.warn(input.new_custom_error(ParserError::DeprecatedNestRule));
674 let selector_parser = SelectorParser {
675 is_nesting_allowed: true,
676 options: &self.options,
677 };
678 let selectors = SelectorList::parse(&selector_parser, input, ParseErrorRecovery::DiscardList, NestingRequirement::Contained)?;
679 AtRulePrelude::Nest(selectors)
680 },
681 _ => parse_custom_at_rule_prelude(&name, input, self.options, self.at_rule_parser)?
682 };
683
684 if self.is_in_style_rule && !result.allowed_in_style_rule() {
685 return Err(input.new_error(BasicParseErrorKind::AtRuleInvalid(name.clone())));
686 }
687
688 Ok(result)
689 }
690
691 fn parse_block<'t>(
692 &mut self,
693 prelude: Self::Prelude,
694 start: &ParserState,
695 input: &mut Parser<'i, 't>,
696 ) -> Result<(), ParseError<'i, Self::Error>> {
697 let loc = self.loc(start);
698 match prelude {
699 AtRulePrelude::FontFace => {
700 let mut decl_parser = FontFaceDeclarationParser;
701 let mut parser = RuleBodyParser::new(input, &mut decl_parser);
702 let mut properties = vec![];
703 while let Some(decl) = parser.next() {
704 if let Ok(decl) = decl {
705 properties.push(decl);
706 }
707 }
708 self.rules.0.push(CssRule::FontFace(FontFaceRule { properties, loc }));
709 Ok(())
710 }
711 AtRulePrelude::FontPaletteValues(name) => {
728 let rule = FontPaletteValuesRule::parse(name, input, loc)?;
729 self.rules.0.push(CssRule::FontPaletteValues(rule));
730 Ok(())
731 }
732 AtRulePrelude::CounterStyle(name) => {
733 self.rules.0.push(CssRule::CounterStyle(CounterStyleRule {
734 name,
735 declarations: DeclarationBlock::parse(input, self.options)?,
736 loc,
737 }));
738 Ok(())
739 }
740 AtRulePrelude::Media(query) => {
741 let rules = self.parse_style_block(input)?;
742 self.rules.0.push(CssRule::Media(MediaRule { query, rules, loc }));
743 Ok(())
744 }
745 AtRulePrelude::Supports(condition) => {
746 let rules = self.parse_style_block(input)?;
747 self.rules.0.push(CssRule::Supports(SupportsRule { condition, rules, loc }));
748 Ok(())
749 }
750 AtRulePrelude::Container(name, condition) => {
751 let rules = self.parse_style_block(input)?;
752 self.rules.0.push(CssRule::Container(ContainerRule {
753 name,
754 condition,
755 rules,
756 loc,
757 }));
758 Ok(())
759 }
760 AtRulePrelude::Scope(scope_start, scope_end) => {
761 let rules = self.parse_style_block(input)?;
762 self.rules.0.push(CssRule::Scope(ScopeRule {
763 scope_start,
764 scope_end,
765 rules,
766 loc,
767 }));
768 Ok(())
769 }
770 AtRulePrelude::Viewport(vendor_prefix) => {
771 self.rules.0.push(CssRule::Viewport(ViewportRule {
772 vendor_prefix,
773 declarations: DeclarationBlock::parse(input, self.options)?,
776 loc,
777 }));
778 Ok(())
779 }
780 AtRulePrelude::Keyframes(name, vendor_prefix) => {
781 let mut parser = KeyframeListParser;
782 let iter = RuleBodyParser::new(input, &mut parser);
783 self.rules.0.push(CssRule::Keyframes(KeyframesRule {
784 name,
785 keyframes: iter.filter_map(Result::ok).collect(),
786 vendor_prefix,
787 loc,
788 }));
789 Ok(())
790 }
791 AtRulePrelude::Page(selectors) => {
792 let rule = PageRule::parse(selectors, input, loc, self.options)?;
793 self.rules.0.push(CssRule::Page(rule));
794 Ok(())
795 }
796 AtRulePrelude::MozDocument => {
797 let rules = self.parse_style_block(input)?;
798 self.rules.0.push(CssRule::MozDocument(MozDocumentRule { rules, loc }));
799 Ok(())
800 }
801 AtRulePrelude::Layer(names) => {
802 let name = if names.is_empty() {
803 None
804 } else if names.len() == 1 {
805 names.into_iter().next()
806 } else {
807 return Err(input.new_error(BasicParseErrorKind::AtRuleBodyInvalid));
808 };
809
810 let rules = self.parse_style_block(input)?;
811 self.rules.0.push(CssRule::LayerBlock(LayerBlockRule { name, rules, loc }));
812 Ok(())
813 }
814 AtRulePrelude::Property(name) => {
815 self.rules.0.push(CssRule::Property(PropertyRule::parse(name, input, loc)?));
816 Ok(())
817 }
818 AtRulePrelude::Import(..)
819 | AtRulePrelude::Namespace(..)
820 | AtRulePrelude::CustomMedia(..)
821 | AtRulePrelude::Charset => {
822 Err(input.new_unexpected_token_error(Token::CurlyBracketBlock))
824 }
825 AtRulePrelude::StartingStyle => {
826 let rules = self.parse_style_block(input)?;
827 self.rules.0.push(CssRule::StartingStyle(StartingStyleRule { rules, loc }));
828 Ok(())
829 }
830 AtRulePrelude::Nest(selectors) => {
831 let (declarations, rules) = self.parse_nested(input, true)?;
832 self.rules.0.push(CssRule::Nesting(NestingRule {
833 style: StyleRule {
834 selectors,
835 declarations,
836 vendor_prefix: VendorPrefix::empty(),
837 rules,
838 loc,
839 },
840 loc,
841 }));
842 Ok(())
843 }
844 AtRulePrelude::FontFeatureValues => unreachable!(),
845 AtRulePrelude::Unknown(name, prelude) => {
846 self.rules.0.push(CssRule::Unknown(UnknownAtRule {
847 name,
848 prelude,
849 block: Some(TokenList::parse(input, &self.options, 0)?),
850 loc,
851 }));
852 Ok(())
853 }
854 AtRulePrelude::Custom(prelude) => {
855 self.rules.0.push(parse_custom_at_rule_body(
856 prelude,
857 input,
858 start,
859 self.options,
860 self.at_rule_parser,
861 self.is_in_style_rule,
862 )?);
863 Ok(())
864 }
865 }
866 }
867
868 #[inline]
869 fn rule_without_block(
870 &mut self,
871 prelude: AtRulePrelude<'i, T::Prelude>,
872 start: &ParserState,
873 ) -> Result<Self::AtRule, ()> {
874 let loc = self.loc(start);
875 match prelude {
876 AtRulePrelude::Layer(names) => {
877 if self.is_in_style_rule || names.is_empty() {
878 return Err(());
879 }
880
881 self.rules.0.push(CssRule::LayerStatement(LayerStatementRule { names, loc }));
882 Ok(())
883 }
884 AtRulePrelude::Unknown(name, prelude) => {
885 self.rules.0.push(CssRule::Unknown(UnknownAtRule {
886 name,
887 prelude,
888 block: None,
889 loc,
890 }));
891 Ok(())
892 }
893 AtRulePrelude::Custom(prelude) => {
894 self.rules.0.push(parse_custom_at_rule_without_block(
895 prelude,
896 start,
897 self.options,
898 self.at_rule_parser,
899 self.is_in_style_rule,
900 )?);
901 Ok(())
902 }
903 _ => Err(()),
904 }
905 }
906}
907
908impl<'a, 'o, 'b, 'i, T: crate::traits::AtRuleParser<'i>> QualifiedRuleParser<'i>
909 for NestedRuleParser<'a, 'o, 'i, T>
910{
911 type Prelude = SelectorList<'i>;
912 type QualifiedRule = ();
913 type Error = ParserError<'i>;
914
915 fn parse_prelude<'t>(
916 &mut self,
917 input: &mut Parser<'i, 't>,
918 ) -> Result<Self::Prelude, ParseError<'i, Self::Error>> {
919 let selector_parser = SelectorParser {
920 is_nesting_allowed: true,
921 options: &self.options,
922 };
923 if self.is_in_style_rule {
924 SelectorList::parse_relative(
925 &selector_parser,
926 input,
927 ParseErrorRecovery::DiscardList,
928 NestingRequirement::Implicit,
929 )
930 } else {
931 SelectorList::parse(
932 &selector_parser,
933 input,
934 ParseErrorRecovery::DiscardList,
935 NestingRequirement::None,
936 )
937 }
938 }
939
940 fn parse_block<'t>(
941 &mut self,
942 selectors: Self::Prelude,
943 start: &ParserState,
944 input: &mut Parser<'i, 't>,
945 ) -> Result<(), ParseError<'i, Self::Error>> {
946 let loc = self.loc(start);
947 let (declarations, rules) = self.parse_nested(input, true)?;
948 self.rules.0.push(CssRule::Style(StyleRule {
949 selectors,
950 vendor_prefix: VendorPrefix::empty(),
951 declarations,
952 rules,
953 loc,
954 }));
955 Ok(())
956 }
957}
958
959impl<'a, 'o, 'i, T: crate::traits::AtRuleParser<'i>> cssparser::DeclarationParser<'i>
961 for NestedRuleParser<'a, 'o, 'i, T>
962{
963 type Declaration = ();
964 type Error = ParserError<'i>;
965
966 fn parse_value<'t>(
967 &mut self,
968 name: CowRcStr<'i>,
969 input: &mut cssparser::Parser<'i, 't>,
970 ) -> Result<Self::Declaration, cssparser::ParseError<'i, Self::Error>> {
971 parse_declaration(
972 name,
973 input,
974 &mut self.declarations,
975 &mut self.important_declarations,
976 &self.options,
977 )
978 }
979}
980
981impl<'a, 'o, 'b, 'i, T: crate::traits::AtRuleParser<'i>> RuleBodyItemParser<'i, (), ParserError<'i>>
982 for NestedRuleParser<'a, 'o, 'i, T>
983{
984 fn parse_qualified(&self) -> bool {
985 true
986 }
987
988 fn parse_declarations(&self) -> bool {
989 self.allow_declarations
990 }
991}
992
993fn parse_custom_at_rule_prelude<'i, 't, T: crate::traits::AtRuleParser<'i>>(
994 name: &CowRcStr<'i>,
995 input: &mut Parser<'i, 't>,
996 options: &ParserOptions<'_, 'i>,
997 at_rule_parser: &mut T,
998) -> Result<AtRulePrelude<'i, T::Prelude>, ParseError<'i, ParserError<'i>>> {
999 match at_rule_parser.parse_prelude(name.clone(), input, options) {
1000 Ok(prelude) => return Ok(AtRulePrelude::Custom(prelude)),
1001 Err(ParseError {
1002 kind: ParseErrorKind::Basic(BasicParseErrorKind::AtRuleInvalid(..)),
1003 ..
1004 }) => {}
1005 Err(err) => {
1006 return Err(match &err.kind {
1007 ParseErrorKind::Basic(kind) => ParseError {
1008 kind: ParseErrorKind::Basic(kind.clone()),
1009 location: err.location,
1010 },
1011 _ => input.new_custom_error(ParserError::AtRulePreludeInvalid),
1012 })
1013 }
1014 }
1015
1016 options.warn(input.new_error(BasicParseErrorKind::AtRuleInvalid(name.clone())));
1017 input.skip_whitespace();
1018 let tokens = TokenList::parse(input, &options, 0)?;
1019 Ok(AtRulePrelude::Unknown(name.into(), tokens))
1020}
1021
1022fn parse_custom_at_rule_body<'i, 't, T: crate::traits::AtRuleParser<'i>>(
1023 prelude: T::Prelude,
1024 input: &mut Parser<'i, 't>,
1025 start: &ParserState,
1026 options: &ParserOptions<'_, 'i>,
1027 at_rule_parser: &mut T,
1028 is_nested: bool,
1029) -> Result<CssRule<'i, T::AtRule>, ParseError<'i, ParserError<'i>>> {
1030 at_rule_parser
1031 .parse_block(prelude, start, input, options, is_nested)
1032 .map(|prelude| CssRule::Custom(prelude))
1033 .map_err(|err| match &err.kind {
1034 ParseErrorKind::Basic(kind) => ParseError {
1035 kind: ParseErrorKind::Basic(kind.clone()),
1036 location: err.location,
1037 },
1038 _ => input.new_error(BasicParseErrorKind::AtRuleBodyInvalid),
1039 })
1040}
1041
1042fn parse_custom_at_rule_without_block<'i, 't, T: crate::traits::AtRuleParser<'i>>(
1043 prelude: T::Prelude,
1044 start: &ParserState,
1045 options: &ParserOptions<'_, 'i>,
1046 at_rule_parser: &mut T,
1047 is_nested: bool,
1048) -> Result<CssRule<'i, T::AtRule>, ()> {
1049 at_rule_parser
1050 .rule_without_block(prelude, start, options, is_nested)
1051 .map(|prelude| CssRule::Custom(prelude))
1052}
1053
1054pub fn parse_rule_list<'a, 'o, 'i, 't, T: crate::traits::AtRuleParser<'i>>(
1055 input: &mut Parser<'i, 't>,
1056 options: &'a ParserOptions<'o, 'i>,
1057 at_rule_parser: &mut T,
1058) -> Result<CssRuleList<'i, T::AtRule>, ParseError<'i, ParserError<'i>>> {
1059 let mut parser = NestedRuleParser {
1060 options,
1061 at_rule_parser,
1062 declarations: DeclarationList::new(),
1063 important_declarations: DeclarationList::new(),
1064 rules: &mut CssRuleList(Vec::new()),
1065 is_in_style_rule: false,
1066 allow_declarations: false,
1067 };
1068
1069 let (_, rules) = parser.parse_nested(input, false)?;
1070 Ok(rules)
1071}
1072
1073pub fn parse_style_block<'a, 'o, 'i, 't, T: crate::traits::AtRuleParser<'i>>(
1074 input: &mut Parser<'i, 't>,
1075 options: &'a ParserOptions<'o, 'i>,
1076 at_rule_parser: &mut T,
1077 is_nested: bool,
1078) -> Result<CssRuleList<'i, T::AtRule>, ParseError<'i, ParserError<'i>>> {
1079 let mut parser = NestedRuleParser {
1080 options,
1081 at_rule_parser,
1082 declarations: DeclarationList::new(),
1083 important_declarations: DeclarationList::new(),
1084 rules: &mut CssRuleList(Vec::new()),
1085 is_in_style_rule: is_nested,
1086 allow_declarations: true,
1087 };
1088
1089 parser.parse_style_block(input)
1090}
1091
1092#[inline]
1093pub fn starts_with_ignore_ascii_case(string: &str, prefix: &str) -> bool {
1094 string.len() >= prefix.len() && string.as_bytes()[0..prefix.len()].eq_ignore_ascii_case(prefix.as_bytes())
1095}