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_feature_values::FontFeatureValuesRule;
8use crate::rules::font_palette_values::FontPaletteValuesRule;
9use crate::rules::layer::{LayerBlockRule, LayerStatementRule};
10use crate::rules::nesting::NestedDeclarationsRule;
11use crate::rules::position_try::PositionTryRule;
12use crate::rules::property::PropertyRule;
13use crate::rules::scope::ScopeRule;
14use crate::rules::starting_style::StartingStyleRule;
15use crate::rules::view_transition::ViewTransitionRule;
16use crate::rules::viewport::ViewportRule;
17
18use crate::properties::font::FamilyName;
19use crate::rules::{
20 counter_style::CounterStyleRule,
21 custom_media::CustomMediaRule,
22 document::MozDocumentRule,
23 font_face::{FontFaceDeclarationParser, FontFaceRule},
24 import::ImportRule,
25 keyframes::{KeyframeListParser, KeyframesName, KeyframesRule},
26 layer::LayerName,
27 media::MediaRule,
28 namespace::NamespaceRule,
29 nesting::NestingRule,
30 page::{PageRule, PageSelector},
31 style::StyleRule,
32 supports::{SupportsCondition, SupportsRule},
33 unknown::UnknownAtRule,
34 CssRule, CssRuleList, Location,
35};
36use crate::selector::{SelectorList, SelectorParser};
37use crate::traits::{Parse, ParseWithOptions};
38use crate::values::ident::{CustomIdent, DashedIdent};
39use crate::values::string::CowArcStr;
40use crate::vendor_prefix::VendorPrefix;
41#[cfg(feature = "visitor")]
42use crate::visitor::{Visit, VisitTypes, Visitor};
43use bitflags::bitflags;
44use cssparser::*;
45use parcel_selectors::parser::{NestingRequirement, ParseErrorRecovery};
46use std::sync::{Arc, RwLock};
47
48bitflags! {
49 #[derive(Clone, Debug, Default)]
51 #[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
52 pub struct ParserFlags: u8 {
53 const NESTING = 1 << 0;
55 const CUSTOM_MEDIA = 1 << 1;
57 const DEEP_SELECTOR_COMBINATOR = 1 << 2;
59 const SCROLL_NAVIGATION_CONTROLS = 1 << 3;
61 }
62}
63
64#[derive(Clone, Debug, Default)]
66pub struct ParserOptions<'i> {
67 pub filename: String,
69 pub css_modules: Option<crate::css_modules::Config>,
71 pub source_index: u32,
74 pub error_recovery: bool,
76 pub warnings: Option<Arc<RwLock<Vec<Error<ParserError<'i>>>>>>,
78 pub flags: ParserFlags,
80}
81
82#[cfg(feature = "into_owned")]
83impl<'i, 'any> static_self::IntoOwned<'any> for ParserOptions<'i> {
84 type Owned = ParserOptions<'any>;
85
86 fn into_owned(self) -> Self::Owned {
87 ParserOptions {
88 warnings: self.warnings.and_then(|warnings| {
89 if let Ok(errors) = warnings.read() {
90 Some(Arc::new(RwLock::new(
91 errors.iter().map(|e| e.clone().into_owned()).collect(),
92 )))
93 } else {
94 None
95 }
96 }),
97 ..self
98 }
99 }
100}
101
102impl<'i> ParserOptions<'i> {
103 #[inline]
104 pub(crate) fn warn(&self, warning: ParseError<'i, ParserError<'i>>) {
105 if let Some(warnings) = &self.warnings {
106 if let Ok(mut warnings) = warnings.write() {
107 warnings.push(Error::from(warning, self.filename.clone()));
108 }
109 }
110 }
111}
112
113#[derive(Clone, Default)]
114#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
115pub struct DefaultAtRuleParser;
116impl<'i> crate::traits::AtRuleParser<'i> for DefaultAtRuleParser {
117 type AtRule = DefaultAtRule;
118 type Error = ();
119 type Prelude = ();
120}
121
122#[derive(PartialEq, Clone, Debug)]
123#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
124#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
125pub struct DefaultAtRule;
126impl crate::traits::ToCss for DefaultAtRule {
127 fn to_css<W: std::fmt::Write>(&self, _: &mut Printer<W>) -> Result<(), PrinterError> {
128 Err(PrinterError {
129 kind: crate::error::PrinterErrorKind::FmtError,
130 loc: None,
131 })
132 }
133}
134
135#[cfg(feature = "into_owned")]
136impl<'any> static_self::IntoOwned<'any> for DefaultAtRule {
137 type Owned = Self;
138 fn into_owned(self) -> Self {
139 self
140 }
141}
142
143#[cfg(feature = "visitor")]
144#[cfg_attr(docsrs, doc(cfg(feature = "visitor")))]
145impl<'i, V: Visitor<'i, DefaultAtRule>> Visit<'i, DefaultAtRule, V> for DefaultAtRule {
146 const CHILD_TYPES: VisitTypes = VisitTypes::empty();
147 fn visit_children(&mut self, _: &mut V) -> Result<(), V::Error> {
148 Ok(())
149 }
150}
151
152#[derive(PartialEq, PartialOrd)]
153enum State {
154 Start = 1,
155 Layers = 2,
156 Imports = 3,
157 Namespaces = 4,
158 Body = 5,
159}
160
161pub struct TopLevelRuleParser<'a, 'i, T: crate::traits::AtRuleParser<'i>> {
163 pub options: &'a ParserOptions<'i>,
164 state: State,
165 at_rule_parser: &'a mut T,
166 rules: &'a mut CssRuleList<'i, T::AtRule>,
167}
168
169impl<'a, 'b, 'i, T: crate::traits::AtRuleParser<'i>> TopLevelRuleParser<'a, 'i, T> {
170 pub fn new(
171 options: &'a ParserOptions<'i>,
172 at_rule_parser: &'a mut T,
173 rules: &'a mut CssRuleList<'i, T::AtRule>,
174 ) -> Self {
175 TopLevelRuleParser {
176 options,
177 state: State::Start,
178 at_rule_parser,
179 rules,
180 }
181 }
182
183 pub fn nested<'x: 'b>(&'x mut self) -> NestedRuleParser<'x, 'i, T> {
184 NestedRuleParser {
185 options: &self.options,
186 at_rule_parser: self.at_rule_parser,
187 declarations: DeclarationList::new(),
188 important_declarations: DeclarationList::new(),
189 rules: &mut self.rules,
190 is_in_style_rule: false,
191 allow_declarations: false,
192 is_scope_body: false,
193 }
194 }
195}
196
197#[derive(Debug)]
199#[allow(dead_code)]
200pub enum AtRulePrelude<'i, T> {
201 FontFace,
203 FontFeatureValues(Vec<FamilyName<'i>>),
205 FontPaletteValues(DashedIdent<'i>),
207 CounterStyle(CustomIdent<'i>),
209 Media(MediaList<'i>),
211 CustomMedia(DashedIdent<'i>, MediaList<'i>),
213 Supports(SupportsCondition<'i>),
215 Viewport(VendorPrefix),
217 Keyframes(KeyframesName<'i>, VendorPrefix),
219 Page(Vec<PageSelector<'i>>),
221 MozDocument,
223 Import(
225 CowRcStr<'i>,
226 MediaList<'i>,
227 Option<SupportsCondition<'i>>,
228 Option<Option<LayerName<'i>>>,
229 ),
230 Namespace(Option<CowRcStr<'i>>, CowRcStr<'i>),
232 Charset,
234 Nest(SelectorList<'i>),
236 Layer(Vec<LayerName<'i>>),
238 Property(DashedIdent<'i>),
240 PositionTry(DashedIdent<'i>),
242 Container(Option<ContainerName<'i>>, Option<ContainerCondition<'i>>),
246 StartingStyle,
248 Scope(Option<SelectorList<'i>>, Option<SelectorList<'i>>),
250 ViewTransition,
252 Unknown(CowArcStr<'i>, TokenList<'i>),
254 Custom(T),
256}
257
258impl<'i, T> AtRulePrelude<'i, T> {
259 fn allowed_in_style_rule(&self) -> bool {
264 match *self {
265 Self::Media(..)
266 | Self::Supports(..)
267 | Self::Container(..)
268 | Self::MozDocument
269 | Self::Layer(..)
270 | Self::StartingStyle
271 | Self::Scope(..)
272 | Self::Nest(..)
273 | Self::Unknown(..)
274 | Self::Custom(..) => true,
275
276 Self::Namespace(..)
277 | Self::FontFace
278 | Self::FontFeatureValues(..)
279 | Self::FontPaletteValues(..)
280 | Self::CounterStyle(..)
281 | Self::Keyframes(..)
282 | Self::Page(..)
283 | Self::Property(..)
284 | Self::PositionTry(..)
285 | Self::Import(..)
286 | Self::CustomMedia(..)
287 | Self::Viewport(..)
288 | Self::Charset
289 | Self::ViewTransition => false,
290 }
291 }
292}
293
294impl<'a, 'i, T: crate::traits::AtRuleParser<'i>> AtRuleParser<'i> for TopLevelRuleParser<'a, 'i, T> {
295 type Prelude = AtRulePrelude<'i, T::Prelude>;
296 type AtRule = ();
297 type Error = ParserError<'i>;
298
299 fn parse_prelude<'t>(
300 &mut self,
301 name: CowRcStr<'i>,
302 input: &mut Parser<'i, 't>,
303 ) -> Result<Self::Prelude, ParseError<'i, Self::Error>> {
304 match_ignore_ascii_case! { &*name,
305 "import" => {
306 if self.state > State::Imports {
307 return Err(input.new_custom_error(ParserError::UnexpectedImportRule))
308 }
309
310 let url_string = input.expect_url_or_string()?.clone();
311
312 let layer = if input.try_parse(|input| input.expect_ident_matching("layer")).is_ok() {
313 Some(None)
314 } else if input.try_parse(|input| input.expect_function_matching("layer")).is_ok() {
315 let name = input.parse_nested_block(LayerName::parse).map(|name| Some(name))?;
316 Some(name)
317 } else {
318 None
319 };
320
321 let supports = if input.try_parse(|input| input.expect_function_matching("supports")).is_ok() {
322 Some(input.parse_nested_block(|input| {
323 input.try_parse(SupportsCondition::parse).or_else(|_| SupportsCondition::parse_declaration(input))
324 })?)
325 } else {
326 None
327 };
328 let media = MediaList::parse(input, &self.options)?;
329 return Ok(AtRulePrelude::Import(url_string, media, supports, layer));
330 },
331 "namespace" => {
332 if self.state > State::Namespaces {
333 return Err(input.new_custom_error(ParserError::UnexpectedNamespaceRule))
334 }
335
336 let prefix = input.try_parse(|input| input.expect_ident_cloned()).ok();
337 let namespace = input.expect_url_or_string()?;
338 let prelude = AtRulePrelude::Namespace(prefix, namespace);
339 return Ok(prelude);
340 },
341 "charset" => {
342 input.expect_string()?;
346 return Ok(AtRulePrelude::Charset)
347 },
348 "custom-media" if self.options.flags.contains(ParserFlags::CUSTOM_MEDIA) => {
349 let name = DashedIdent::parse(input)?;
350 let media = MediaList::parse(input, &self.options)?;
351 return Ok(AtRulePrelude::CustomMedia(name, media))
352 },
353 _ => {}
354 }
355
356 AtRuleParser::parse_prelude(&mut self.nested(), name, input)
357 }
358
359 #[inline]
360 fn parse_block<'t>(
361 &mut self,
362 prelude: Self::Prelude,
363 start: &ParserState,
364 input: &mut Parser<'i, 't>,
365 ) -> Result<Self::AtRule, ParseError<'i, Self::Error>> {
366 self.state = State::Body;
367 AtRuleParser::parse_block(&mut self.nested(), prelude, start, input)
368 }
369
370 #[inline]
371 fn rule_without_block(
372 &mut self,
373 prelude: AtRulePrelude<'i, T::Prelude>,
374 start: &ParserState,
375 ) -> Result<Self::AtRule, ()> {
376 let loc = start.source_location();
377 let loc = Location {
378 source_index: self.options.source_index,
379 line: loc.line,
380 column: loc.column,
381 };
382
383 match prelude {
384 AtRulePrelude::Import(url, media, supports, layer) => {
385 self.state = State::Imports;
386 self.rules.0.push(CssRule::Import(ImportRule {
387 url: url.into(),
388 layer,
389 supports,
390 media,
391 loc,
392 }));
393 Ok(())
394 }
395 AtRulePrelude::Namespace(prefix, url) => {
396 self.state = State::Namespaces;
397
398 self.rules.0.push(CssRule::Namespace(NamespaceRule {
399 prefix: prefix.map(|x| x.into()),
400 url: url.into(),
401 loc,
402 }));
403 Ok(())
404 }
405 AtRulePrelude::CustomMedia(name, query) => {
406 self.state = State::Body;
407 self.rules.0.push(CssRule::CustomMedia(CustomMediaRule { name, query, loc }));
408 Ok(())
409 }
410 AtRulePrelude::Layer(_) => {
411 if self.state <= State::Layers {
413 self.state = State::Layers;
414 } else {
415 self.state = State::Body;
416 }
417 AtRuleParser::rule_without_block(&mut self.nested(), prelude, start)
418 }
419 AtRulePrelude::Charset => Ok(()),
420 AtRulePrelude::Unknown(name, prelude) => {
421 self.rules.0.push(CssRule::Unknown(UnknownAtRule {
422 name,
423 prelude,
424 block: None,
425 loc,
426 }));
427 Ok(())
428 }
429 AtRulePrelude::Custom(_) => {
430 self.state = State::Body;
431 AtRuleParser::rule_without_block(&mut self.nested(), prelude, start)
432 }
433 _ => Err(()),
434 }
435 }
436}
437
438impl<'a, 'i, T: crate::traits::AtRuleParser<'i>> QualifiedRuleParser<'i> for TopLevelRuleParser<'a, 'i, T> {
439 type Prelude = SelectorList<'i>;
440 type QualifiedRule = ();
441 type Error = ParserError<'i>;
442
443 #[inline]
444 fn parse_prelude<'t>(
445 &mut self,
446 input: &mut Parser<'i, 't>,
447 ) -> Result<Self::Prelude, ParseError<'i, Self::Error>> {
448 self.state = State::Body;
449 QualifiedRuleParser::parse_prelude(&mut self.nested(), input)
450 }
451
452 #[inline]
453 fn parse_block<'t>(
454 &mut self,
455 prelude: Self::Prelude,
456 start: &ParserState,
457 input: &mut Parser<'i, 't>,
458 ) -> Result<Self::QualifiedRule, ParseError<'i, Self::Error>> {
459 QualifiedRuleParser::parse_block(&mut self.nested(), prelude, start, input)
460 }
461}
462
463pub struct NestedRuleParser<'a, 'i, T: crate::traits::AtRuleParser<'i>> {
464 pub options: &'a ParserOptions<'i>,
465 pub at_rule_parser: &'a mut T,
466 declarations: DeclarationList<'i>,
467 important_declarations: DeclarationList<'i>,
468 rules: &'a mut CssRuleList<'i, T::AtRule>,
469 is_in_style_rule: bool,
470 allow_declarations: bool,
471 is_scope_body: bool,
474}
475
476impl<'a, 'b, 'i, T: crate::traits::AtRuleParser<'i>> NestedRuleParser<'a, 'i, T> {
477 pub fn parse_nested<'t>(
478 &mut self,
479 input: &mut Parser<'i, 't>,
480 is_style_rule: bool,
481 ) -> Result<(DeclarationBlock<'i>, CssRuleList<'i, T::AtRule>), ParseError<'i, ParserError<'i>>> {
482 self.parse_nested_body(input, is_style_rule, false)
483 }
484
485 fn parse_nested_body<'t>(
486 &mut self,
487 input: &mut Parser<'i, 't>,
488 is_style_rule: bool,
489 is_scope_body: bool,
490 ) -> Result<(DeclarationBlock<'i>, CssRuleList<'i, T::AtRule>), ParseError<'i, ParserError<'i>>> {
491 let mut rules = CssRuleList(vec![]);
492 let mut nested_parser = NestedRuleParser {
493 options: self.options,
494 at_rule_parser: self.at_rule_parser,
495 declarations: DeclarationList::new(),
496 important_declarations: DeclarationList::new(),
497 rules: &mut rules,
498 is_in_style_rule: self.is_in_style_rule || is_style_rule,
499 allow_declarations: self.allow_declarations || self.is_in_style_rule || is_style_rule,
500 is_scope_body: is_scope_body || (self.is_scope_body && !is_style_rule),
502 };
503
504 let parse_declarations = nested_parser.parse_declarations();
505 let mut errors = Vec::new();
506 let mut iter = RuleBodyParser::new(input, &mut nested_parser);
507 while let Some(result) = iter.next() {
508 match result {
509 Ok(()) => {}
510 Err((e, _)) => {
511 if parse_declarations {
512 iter.parser.declarations.clear();
513 iter.parser.important_declarations.clear();
514 errors.push(e);
515 } else {
516 if iter.parser.options.error_recovery {
517 iter.parser.options.warn(e);
518 continue;
519 }
520 return Err(e);
521 }
522 }
523 }
524 }
525
526 if parse_declarations {
527 if !errors.is_empty() {
528 if self.options.error_recovery {
529 for err in errors {
530 self.options.warn(err);
531 }
532 } else {
533 return Err(errors.remove(0));
534 }
535 }
536 }
537
538 Ok((
539 DeclarationBlock {
540 declarations: nested_parser.declarations,
541 important_declarations: nested_parser.important_declarations,
542 },
543 rules,
544 ))
545 }
546
547 fn parse_style_block<'t>(
548 &mut self,
549 input: &mut Parser<'i, 't>,
550 ) -> Result<CssRuleList<'i, T::AtRule>, ParseError<'i, ParserError<'i>>> {
551 self.parse_block_body(input, false)
552 }
553
554 fn parse_block_body<'t>(
555 &mut self,
556 input: &mut Parser<'i, 't>,
557 is_scope_body: bool,
558 ) -> Result<CssRuleList<'i, T::AtRule>, ParseError<'i, ParserError<'i>>> {
559 let loc = input.current_source_location();
560 let loc = Location {
561 source_index: self.options.source_index,
562 line: loc.line,
563 column: loc.column,
564 };
565
566 let (declarations, mut rules) = self.parse_nested_body(input, false, is_scope_body)?;
569
570 if declarations.len() > 0 {
571 rules.0.insert(
572 0,
573 CssRule::NestedDeclarations(NestedDeclarationsRule { declarations, loc }),
574 )
575 }
576
577 Ok(rules)
578 }
579
580 fn loc(&self, start: &ParserState) -> Location {
581 let loc = start.source_location();
582 Location {
583 source_index: self.options.source_index,
584 line: loc.line,
585 column: loc.column,
586 }
587 }
588}
589
590impl<'a, 'b, 'i, T: crate::traits::AtRuleParser<'i>> AtRuleParser<'i> for NestedRuleParser<'a, 'i, T> {
591 type Prelude = AtRulePrelude<'i, T::Prelude>;
592 type AtRule = ();
593 type Error = ParserError<'i>;
594
595 fn parse_prelude<'t>(
596 &mut self,
597 name: CowRcStr<'i>,
598 input: &mut Parser<'i, 't>,
599 ) -> Result<Self::Prelude, ParseError<'i, Self::Error>> {
600 let result = match_ignore_ascii_case! { &*name,
601 "media" => {
602 let media = MediaList::parse(input, &self.options)?;
603 AtRulePrelude::Media(media)
604 },
605 "supports" => {
606 let cond = SupportsCondition::parse(input, )?;
607 AtRulePrelude::Supports(cond)
608 },
609 "font-face" => {
610 AtRulePrelude::FontFace
611 },
612 "font-feature-values" => {
621 let names = match Vec::<FamilyName>::parse(input) {
622 Ok(names) => names,
623 Err(e) => return Err(e)
624 };
625
626 AtRulePrelude::FontFeatureValues(names)
627 },
628 "font-palette-values" => {
629 let name = DashedIdent::parse(input)?;
630 AtRulePrelude::FontPaletteValues(name)
631 },
632 "counter-style" => {
633 let name = CustomIdent::parse(input)?;
634 AtRulePrelude::CounterStyle(name)
635 },
636 "viewport" | "-ms-viewport" => {
637 let prefix = if starts_with_ignore_ascii_case(&*name, "-ms") {
638 VendorPrefix::Ms
639 } else {
640 VendorPrefix::None
641 };
642 AtRulePrelude::Viewport(prefix)
643 },
644 "keyframes" | "-webkit-keyframes" | "-moz-keyframes" | "-o-keyframes" | "-ms-keyframes" => {
645 let prefix = if starts_with_ignore_ascii_case(&*name, "-webkit-") {
646 VendorPrefix::WebKit
647 } else if starts_with_ignore_ascii_case(&*name, "-moz-") {
648 VendorPrefix::Moz
649 } else if starts_with_ignore_ascii_case(&*name, "-o-") {
650 VendorPrefix::O
651 } else if starts_with_ignore_ascii_case(&*name, "-ms-") {
652 VendorPrefix::Ms
653 } else {
654 VendorPrefix::None
655 };
656
657 let name = input.try_parse(KeyframesName::parse)?;
658 AtRulePrelude::Keyframes(name, prefix)
659 },
660 "page" => {
661 let selectors = input.try_parse(|input| input.parse_comma_separated(PageSelector::parse)).unwrap_or_default();
662 AtRulePrelude::Page(selectors)
663 },
664 "-moz-document" => {
665 input.expect_function_matching("url-prefix")?;
668 input.parse_nested_block(|input| {
669 let _ = input.try_parse(|input| -> Result<(), ParseError<'i, Self::Error>> {
672 let s = input.expect_string()?;
673 if !s.is_empty() {
674 return Err(input.new_custom_error(ParserError::InvalidValue))
675 }
676 Ok(())
677 });
678 input.expect_exhausted()?;
679 Ok(())
680 })?;
681
682 AtRulePrelude::MozDocument
683 },
684 "layer" => {
685 let names = match Vec::<LayerName>::parse(input) {
686 Ok(names) => names,
687 Err(ParseError { kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput), .. }) => Vec::new(),
688 Err(e) => return Err(e)
689 };
690 AtRulePrelude::Layer(names)
691 },
692 "container" => {
693 let name = input.try_parse(ContainerName::parse).ok();
694 match input.try_parse(|input| ContainerCondition::parse_with_options(input, &self.options)) {
695 Ok(condition) => AtRulePrelude::Container(name, Some(condition)),
696 Err(e) => {
697 if name.is_some() && input.is_exhausted() {
698 AtRulePrelude::Container(name, None)
700 } else {
701 return Err(e);
703 }
704 }
705 }
706 },
707 "starting-style" => {
708 AtRulePrelude::StartingStyle
709 },
710 "scope" => {
711 let selector_parser = SelectorParser {
712 is_nesting_allowed: true,
713 options: &self.options,
714 };
715
716 let scope_start = if input.try_parse(|input| input.expect_parenthesis_block()).is_ok() {
717 Some(input.parse_nested_block(|input| {
718 SelectorList::parse_relative(&selector_parser, input, ParseErrorRecovery::IgnoreInvalidSelector, NestingRequirement::None)
721 })?)
722 } else {
723 None
724 };
725
726 let scope_end = if input.try_parse(|input| input.expect_ident_matching("to")).is_ok() {
727 input.expect_parenthesis_block()?;
728 Some(input.parse_nested_block(|input| {
729 SelectorList::parse_relative(&selector_parser, input, ParseErrorRecovery::IgnoreInvalidSelector, NestingRequirement::None)
730 })?)
731 } else {
732 None
733 };
734
735 AtRulePrelude::Scope(scope_start, scope_end)
736 },
737 "view-transition" => {
738 AtRulePrelude::ViewTransition
739 },
740 "nest" if self.is_in_style_rule => {
741 self.options.warn(input.new_custom_error(ParserError::DeprecatedNestRule));
742 let selector_parser = SelectorParser {
743 is_nesting_allowed: true,
744 options: &self.options,
745 };
746 let selectors = SelectorList::parse(&selector_parser, input, ParseErrorRecovery::DiscardList, NestingRequirement::Contained)?;
747 AtRulePrelude::Nest(selectors)
748 },
749
750 "value" if self.options.css_modules.is_some() => {
751 return Err(input.new_custom_error(ParserError::DeprecatedCssModulesValueRule));
752 },
753
754 "property" => {
755 let name = DashedIdent::parse(input)?;
756 return Ok(AtRulePrelude::Property(name))
757 },
758
759 "position-try" => {
760 let name = DashedIdent::parse(input)?;
761 return Ok(AtRulePrelude::PositionTry(name))
762 },
763
764 _ => parse_custom_at_rule_prelude(&name, input, self.options, self.at_rule_parser)?
765 };
766
767 if self.is_in_style_rule && !result.allowed_in_style_rule() {
768 return Err(input.new_error(BasicParseErrorKind::AtRuleInvalid(name.clone())));
769 }
770
771 Ok(result)
772 }
773
774 #[inline]
775 fn rule_without_block(
776 &mut self,
777 prelude: AtRulePrelude<'i, T::Prelude>,
778 start: &ParserState,
779 ) -> Result<Self::AtRule, ()> {
780 let loc = self.loc(start);
781 match prelude {
782 AtRulePrelude::Layer(names) => {
783 if self.is_in_style_rule || names.is_empty() {
784 return Err(());
785 }
786
787 self.rules.0.push(CssRule::LayerStatement(LayerStatementRule { names, loc }));
788 Ok(())
789 }
790 AtRulePrelude::Unknown(name, prelude) => {
791 self.rules.0.push(CssRule::Unknown(UnknownAtRule {
792 name,
793 prelude,
794 block: None,
795 loc,
796 }));
797 Ok(())
798 }
799 AtRulePrelude::Custom(prelude) => {
800 self.rules.0.push(parse_custom_at_rule_without_block(
801 prelude,
802 start,
803 self.options,
804 self.at_rule_parser,
805 self.is_in_style_rule,
806 )?);
807 Ok(())
808 }
809 _ => Err(()),
810 }
811 }
812
813 fn parse_block<'t>(
814 &mut self,
815 prelude: Self::Prelude,
816 start: &ParserState,
817 input: &mut Parser<'i, 't>,
818 ) -> Result<(), ParseError<'i, Self::Error>> {
819 let loc = self.loc(start);
820 match prelude {
821 AtRulePrelude::FontFace => {
822 let mut decl_parser = FontFaceDeclarationParser;
823 let mut parser = RuleBodyParser::new(input, &mut decl_parser);
824 let mut properties = vec![];
825 while let Some(decl) = parser.next() {
826 if let Ok(decl) = decl {
827 properties.push(decl);
828 }
829 }
830 self.rules.0.push(CssRule::FontFace(FontFaceRule { properties, loc }));
831 Ok(())
832 }
833 AtRulePrelude::FontPaletteValues(name) => {
850 let rule = FontPaletteValuesRule::parse(name, input, loc)?;
851 self.rules.0.push(CssRule::FontPaletteValues(rule));
852 Ok(())
853 }
854 AtRulePrelude::CounterStyle(name) => {
855 self.rules.0.push(CssRule::CounterStyle(CounterStyleRule {
856 name,
857 declarations: DeclarationBlock::parse(input, self.options)?,
858 loc,
859 }));
860 Ok(())
861 }
862 AtRulePrelude::Media(query) => {
863 let rules = self.parse_style_block(input)?;
864 self.rules.0.push(CssRule::Media(MediaRule { query, rules, loc }));
865 Ok(())
866 }
867 AtRulePrelude::Supports(condition) => {
868 let rules = self.parse_style_block(input)?;
869 self.rules.0.push(CssRule::Supports(SupportsRule { condition, rules, loc }));
870 Ok(())
871 }
872 AtRulePrelude::Container(name, condition) => {
873 let rules = self.parse_style_block(input)?;
874 self.rules.0.push(CssRule::Container(ContainerRule {
875 name,
876 condition,
877 rules,
878 loc,
879 }));
880 Ok(())
881 }
882 AtRulePrelude::Scope(scope_start, scope_end) => {
883 let rules = self.parse_block_body(input, true)?;
884 self.rules.0.push(CssRule::Scope(ScopeRule {
885 scope_start,
886 scope_end,
887 rules,
888 loc,
889 }));
890 Ok(())
891 }
892 AtRulePrelude::Viewport(vendor_prefix) => {
893 self.rules.0.push(CssRule::Viewport(ViewportRule {
894 vendor_prefix,
895 declarations: DeclarationBlock::parse(input, self.options)?,
898 loc,
899 }));
900 Ok(())
901 }
902 AtRulePrelude::Keyframes(name, vendor_prefix) => {
903 let mut parser = KeyframeListParser;
904 let iter = RuleBodyParser::new(input, &mut parser);
905 self.rules.0.push(CssRule::Keyframes(KeyframesRule {
906 name,
907 keyframes: iter.filter_map(Result::ok).collect(),
908 vendor_prefix,
909 loc,
910 }));
911 Ok(())
912 }
913 AtRulePrelude::Page(selectors) => {
914 let rule = PageRule::parse(selectors, input, loc, self.options)?;
915 self.rules.0.push(CssRule::Page(rule));
916 Ok(())
917 }
918 AtRulePrelude::MozDocument => {
919 let rules = self.parse_style_block(input)?;
920 self.rules.0.push(CssRule::MozDocument(MozDocumentRule { rules, loc }));
921 Ok(())
922 }
923 AtRulePrelude::Layer(names) => {
924 let name = if names.is_empty() {
925 None
926 } else if names.len() == 1 {
927 names.into_iter().next()
928 } else {
929 return Err(input.new_error(BasicParseErrorKind::AtRuleBodyInvalid));
930 };
931
932 let rules = self.parse_style_block(input)?;
933 self.rules.0.push(CssRule::LayerBlock(LayerBlockRule { name, rules, loc }));
934 Ok(())
935 }
936 AtRulePrelude::Property(name) => {
937 self.rules.0.push(CssRule::Property(PropertyRule::parse(name, input, loc)?));
938 Ok(())
939 }
940 AtRulePrelude::PositionTry(name) => {
941 self.rules.0.push(CssRule::PositionTry(PositionTryRule {
942 name,
943 declarations: DeclarationBlock::parse(input, self.options)?,
944 loc,
945 }));
946 Ok(())
947 }
948 AtRulePrelude::Import(..)
949 | AtRulePrelude::Namespace(..)
950 | AtRulePrelude::CustomMedia(..)
951 | AtRulePrelude::Charset => {
952 Err(input.new_unexpected_token_error(Token::CurlyBracketBlock))
954 }
955 AtRulePrelude::StartingStyle => {
956 let rules = self.parse_style_block(input)?;
957 self.rules.0.push(CssRule::StartingStyle(StartingStyleRule { rules, loc }));
958 Ok(())
959 }
960 AtRulePrelude::ViewTransition => {
961 self
962 .rules
963 .0
964 .push(CssRule::ViewTransition(ViewTransitionRule::parse(input, loc)?));
965 Ok(())
966 }
967 AtRulePrelude::Nest(selectors) => {
968 let (declarations, rules) = self.parse_nested(input, true)?;
969 self.rules.0.push(CssRule::Nesting(NestingRule {
970 style: StyleRule {
971 selectors,
972 declarations,
973 vendor_prefix: VendorPrefix::empty(),
974 rules,
975 loc,
976 },
977 loc,
978 }));
979 Ok(())
980 }
981 AtRulePrelude::FontFeatureValues(family_names) => {
982 let rule = FontFeatureValuesRule::parse(family_names, input, loc, self.options)?;
983 self.rules.0.push(CssRule::FontFeatureValues(rule));
984 Ok(())
985 }
986 AtRulePrelude::Unknown(name, prelude) => {
987 self.rules.0.push(CssRule::Unknown(UnknownAtRule {
988 name,
989 prelude,
990 block: Some(TokenList::parse(input, &self.options, 0)?),
991 loc,
992 }));
993 Ok(())
994 }
995 AtRulePrelude::Custom(prelude) => {
996 self.rules.0.push(parse_custom_at_rule_body(
997 prelude,
998 input,
999 start,
1000 self.options,
1001 self.at_rule_parser,
1002 self.is_in_style_rule,
1003 )?);
1004 Ok(())
1005 }
1006 }
1007 }
1008}
1009
1010impl<'a, 'b, 'i, T: crate::traits::AtRuleParser<'i>> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'i, T> {
1011 type Prelude = SelectorList<'i>;
1012 type QualifiedRule = ();
1013 type Error = ParserError<'i>;
1014
1015 fn parse_prelude<'t>(
1016 &mut self,
1017 input: &mut Parser<'i, 't>,
1018 ) -> Result<Self::Prelude, ParseError<'i, Self::Error>> {
1019 let selector_parser = SelectorParser {
1020 is_nesting_allowed: true,
1021 options: &self.options,
1022 };
1023 if self.is_scope_body {
1024 let lists = input.parse_comma_separated(|input| {
1028 let state = input.state();
1029 let leading_combinator = matches!(input.next(), Ok(Token::Delim('>' | '+' | '~')));
1030 input.reset(&state);
1031 if leading_combinator {
1032 SelectorList::parse_relative(
1033 &selector_parser,
1034 input,
1035 ParseErrorRecovery::DiscardList,
1036 NestingRequirement::Implicit,
1037 )
1038 } else {
1039 SelectorList::parse(
1040 &selector_parser,
1041 input,
1042 ParseErrorRecovery::DiscardList,
1043 NestingRequirement::None,
1044 )
1045 }
1046 })?;
1047 Ok(SelectorList::from_vec(
1048 lists.into_iter().flat_map(|list| list.0).collect(),
1049 ))
1050 } else if self.is_in_style_rule {
1051 SelectorList::parse_relative(
1052 &selector_parser,
1053 input,
1054 ParseErrorRecovery::DiscardList,
1055 NestingRequirement::Implicit,
1056 )
1057 } else {
1058 SelectorList::parse(
1059 &selector_parser,
1060 input,
1061 ParseErrorRecovery::DiscardList,
1062 NestingRequirement::None,
1063 )
1064 }
1065 }
1066
1067 fn parse_block<'t>(
1068 &mut self,
1069 selectors: Self::Prelude,
1070 start: &ParserState,
1071 input: &mut Parser<'i, 't>,
1072 ) -> Result<(), ParseError<'i, Self::Error>> {
1073 let loc = self.loc(start);
1074 let (declarations, rules) = self.parse_nested(input, true)?;
1075 self.rules.0.push(CssRule::Style(StyleRule {
1076 selectors,
1077 vendor_prefix: VendorPrefix::empty(),
1078 declarations,
1079 rules,
1080 loc,
1081 }));
1082 Ok(())
1083 }
1084}
1085
1086impl<'a, 'i, T: crate::traits::AtRuleParser<'i>> cssparser::DeclarationParser<'i> for NestedRuleParser<'a, 'i, T> {
1088 type Declaration = ();
1089 type Error = ParserError<'i>;
1090
1091 fn parse_value<'t>(
1092 &mut self,
1093 name: CowRcStr<'i>,
1094 input: &mut cssparser::Parser<'i, 't>,
1095 _declaration_start: &ParserState,
1096 ) -> Result<Self::Declaration, cssparser::ParseError<'i, Self::Error>> {
1097 if self.rules.0.is_empty() {
1098 parse_declaration(
1099 name,
1100 input,
1101 &mut self.declarations,
1102 &mut self.important_declarations,
1103 &self.options,
1104 )
1105 } else if let Some(CssRule::NestedDeclarations(last)) = self.rules.0.last_mut() {
1106 parse_declaration(
1107 name,
1108 input,
1109 &mut last.declarations.declarations,
1110 &mut last.declarations.important_declarations,
1111 &self.options,
1112 )
1113 } else {
1114 let loc = self.loc(&input.state());
1115 let mut nested = NestedDeclarationsRule {
1116 declarations: DeclarationBlock::new(),
1117 loc,
1118 };
1119
1120 parse_declaration(
1121 name,
1122 input,
1123 &mut nested.declarations.declarations,
1124 &mut nested.declarations.important_declarations,
1125 &self.options,
1126 )?;
1127
1128 self.rules.0.push(CssRule::NestedDeclarations(nested));
1129 Ok(())
1130 }
1131 }
1132}
1133
1134impl<'a, 'b, 'i, T: crate::traits::AtRuleParser<'i>> RuleBodyItemParser<'i, (), ParserError<'i>>
1135 for NestedRuleParser<'a, 'i, T>
1136{
1137 fn parse_qualified(&self) -> bool {
1138 true
1139 }
1140
1141 fn parse_declarations(&self) -> bool {
1142 self.allow_declarations
1143 }
1144}
1145
1146fn parse_custom_at_rule_prelude<'i, 't, T: crate::traits::AtRuleParser<'i>>(
1147 name: &CowRcStr<'i>,
1148 input: &mut Parser<'i, 't>,
1149 options: &ParserOptions<'i>,
1150 at_rule_parser: &mut T,
1151) -> Result<AtRulePrelude<'i, T::Prelude>, ParseError<'i, ParserError<'i>>> {
1152 match at_rule_parser.parse_prelude(name.clone(), input, options) {
1153 Ok(prelude) => return Ok(AtRulePrelude::Custom(prelude)),
1154 Err(ParseError {
1155 kind: ParseErrorKind::Basic(BasicParseErrorKind::AtRuleInvalid(..)),
1156 ..
1157 }) => {}
1158 Err(err) => {
1159 return Err(match &err.kind {
1160 ParseErrorKind::Basic(kind) => ParseError {
1161 kind: ParseErrorKind::Basic(kind.clone()),
1162 location: err.location,
1163 },
1164 _ => input.new_custom_error(ParserError::AtRulePreludeInvalid),
1165 })
1166 }
1167 }
1168
1169 options.warn(input.new_error(BasicParseErrorKind::AtRuleInvalid(name.clone())));
1170 input.skip_whitespace();
1171 let tokens = TokenList::parse(input, &options, 0)?;
1172 Ok(AtRulePrelude::Unknown(name.into(), tokens))
1173}
1174
1175fn parse_custom_at_rule_body<'i, 't, T: crate::traits::AtRuleParser<'i>>(
1176 prelude: T::Prelude,
1177 input: &mut Parser<'i, 't>,
1178 start: &ParserState,
1179 options: &ParserOptions<'i>,
1180 at_rule_parser: &mut T,
1181 is_nested: bool,
1182) -> Result<CssRule<'i, T::AtRule>, ParseError<'i, ParserError<'i>>> {
1183 at_rule_parser
1184 .parse_block(prelude, start, input, options, is_nested)
1185 .map(|prelude| CssRule::Custom(prelude))
1186 .map_err(|err| match &err.kind {
1187 ParseErrorKind::Basic(kind) => ParseError {
1188 kind: ParseErrorKind::Basic(kind.clone()),
1189 location: err.location,
1190 },
1191 _ => input.new_error(BasicParseErrorKind::AtRuleBodyInvalid),
1192 })
1193}
1194
1195fn parse_custom_at_rule_without_block<'i, 't, T: crate::traits::AtRuleParser<'i>>(
1196 prelude: T::Prelude,
1197 start: &ParserState,
1198 options: &ParserOptions<'i>,
1199 at_rule_parser: &mut T,
1200 is_nested: bool,
1201) -> Result<CssRule<'i, T::AtRule>, ()> {
1202 at_rule_parser
1203 .rule_without_block(prelude, start, options, is_nested)
1204 .map(|prelude| CssRule::Custom(prelude))
1205}
1206
1207pub fn parse_rule_list<'a, 'i, 't, T: crate::traits::AtRuleParser<'i>>(
1208 input: &mut Parser<'i, 't>,
1209 options: &'a ParserOptions<'i>,
1210 at_rule_parser: &mut T,
1211) -> Result<CssRuleList<'i, T::AtRule>, ParseError<'i, ParserError<'i>>> {
1212 let mut parser = NestedRuleParser {
1213 options,
1214 at_rule_parser,
1215 declarations: DeclarationList::new(),
1216 important_declarations: DeclarationList::new(),
1217 rules: &mut CssRuleList(Vec::new()),
1218 is_in_style_rule: false,
1219 allow_declarations: false,
1220 is_scope_body: false,
1221 };
1222
1223 let (_, rules) = parser.parse_nested(input, false)?;
1224 Ok(rules)
1225}
1226
1227pub fn parse_style_block<'a, 'i, 't, T: crate::traits::AtRuleParser<'i>>(
1228 input: &mut Parser<'i, 't>,
1229 options: &'a ParserOptions<'i>,
1230 at_rule_parser: &mut T,
1231 is_nested: bool,
1232) -> Result<CssRuleList<'i, T::AtRule>, ParseError<'i, ParserError<'i>>> {
1233 let mut parser = NestedRuleParser {
1234 options,
1235 at_rule_parser,
1236 declarations: DeclarationList::new(),
1237 important_declarations: DeclarationList::new(),
1238 rules: &mut CssRuleList(Vec::new()),
1239 is_in_style_rule: is_nested,
1240 allow_declarations: true,
1241 is_scope_body: false,
1242 };
1243
1244 parser.parse_style_block(input)
1245}
1246
1247#[inline]
1248pub fn starts_with_ignore_ascii_case(string: &str, prefix: &str) -> bool {
1249 string.len() >= prefix.len() && string.as_bytes()[0..prefix.len()].eq_ignore_ascii_case(prefix.as_bytes())
1250}