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 }
193 }
194}
195
196#[derive(Debug)]
198#[allow(dead_code)]
199pub enum AtRulePrelude<'i, T> {
200 FontFace,
202 FontFeatureValues(Vec<FamilyName<'i>>),
204 FontPaletteValues(DashedIdent<'i>),
206 CounterStyle(CustomIdent<'i>),
208 Media(MediaList<'i>),
210 CustomMedia(DashedIdent<'i>, MediaList<'i>),
212 Supports(SupportsCondition<'i>),
214 Viewport(VendorPrefix),
216 Keyframes(KeyframesName<'i>, VendorPrefix),
218 Page(Vec<PageSelector<'i>>),
220 MozDocument,
222 Import(
224 CowRcStr<'i>,
225 MediaList<'i>,
226 Option<SupportsCondition<'i>>,
227 Option<Option<LayerName<'i>>>,
228 ),
229 Namespace(Option<CowRcStr<'i>>, CowRcStr<'i>),
231 Charset,
233 Nest(SelectorList<'i>),
235 Layer(Vec<LayerName<'i>>),
237 Property(DashedIdent<'i>),
239 PositionTry(DashedIdent<'i>),
241 Container(Option<ContainerName<'i>>, Option<ContainerCondition<'i>>),
245 StartingStyle,
247 Scope(Option<SelectorList<'i>>, Option<SelectorList<'i>>),
249 ViewTransition,
251 Unknown(CowArcStr<'i>, TokenList<'i>),
253 Custom(T),
255}
256
257impl<'i, T> AtRulePrelude<'i, T> {
258 fn allowed_in_style_rule(&self) -> bool {
263 match *self {
264 Self::Media(..)
265 | Self::Supports(..)
266 | Self::Container(..)
267 | Self::MozDocument
268 | Self::Layer(..)
269 | Self::StartingStyle
270 | Self::Scope(..)
271 | Self::Nest(..)
272 | Self::Unknown(..)
273 | Self::Custom(..) => true,
274
275 Self::Namespace(..)
276 | Self::FontFace
277 | Self::FontFeatureValues(..)
278 | Self::FontPaletteValues(..)
279 | Self::CounterStyle(..)
280 | Self::Keyframes(..)
281 | Self::Page(..)
282 | Self::Property(..)
283 | Self::PositionTry(..)
284 | Self::Import(..)
285 | Self::CustomMedia(..)
286 | Self::Viewport(..)
287 | Self::Charset
288 | Self::ViewTransition => false,
289 }
290 }
291}
292
293impl<'a, 'i, T: crate::traits::AtRuleParser<'i>> AtRuleParser<'i> for TopLevelRuleParser<'a, 'i, T> {
294 type Prelude = AtRulePrelude<'i, T::Prelude>;
295 type AtRule = ();
296 type Error = ParserError<'i>;
297
298 fn parse_prelude<'t>(
299 &mut self,
300 name: CowRcStr<'i>,
301 input: &mut Parser<'i, 't>,
302 ) -> Result<Self::Prelude, ParseError<'i, Self::Error>> {
303 match_ignore_ascii_case! { &*name,
304 "import" => {
305 if self.state > State::Imports {
306 return Err(input.new_custom_error(ParserError::UnexpectedImportRule))
307 }
308
309 let url_string = input.expect_url_or_string()?.clone();
310
311 let layer = if input.try_parse(|input| input.expect_ident_matching("layer")).is_ok() {
312 Some(None)
313 } else if input.try_parse(|input| input.expect_function_matching("layer")).is_ok() {
314 let name = input.parse_nested_block(LayerName::parse).map(|name| Some(name))?;
315 Some(name)
316 } else {
317 None
318 };
319
320 let supports = if input.try_parse(|input| input.expect_function_matching("supports")).is_ok() {
321 Some(input.parse_nested_block(|input| {
322 input.try_parse(SupportsCondition::parse).or_else(|_| SupportsCondition::parse_declaration(input))
323 })?)
324 } else {
325 None
326 };
327 let media = MediaList::parse(input, &self.options)?;
328 return Ok(AtRulePrelude::Import(url_string, media, supports, layer));
329 },
330 "namespace" => {
331 if self.state > State::Namespaces {
332 return Err(input.new_custom_error(ParserError::UnexpectedNamespaceRule))
333 }
334
335 let prefix = input.try_parse(|input| input.expect_ident_cloned()).ok();
336 let namespace = input.expect_url_or_string()?;
337 let prelude = AtRulePrelude::Namespace(prefix, namespace);
338 return Ok(prelude);
339 },
340 "charset" => {
341 input.expect_string()?;
345 return Ok(AtRulePrelude::Charset)
346 },
347 "custom-media" if self.options.flags.contains(ParserFlags::CUSTOM_MEDIA) => {
348 let name = DashedIdent::parse(input)?;
349 let media = MediaList::parse(input, &self.options)?;
350 return Ok(AtRulePrelude::CustomMedia(name, media))
351 },
352 _ => {}
353 }
354
355 AtRuleParser::parse_prelude(&mut self.nested(), name, input)
356 }
357
358 #[inline]
359 fn parse_block<'t>(
360 &mut self,
361 prelude: Self::Prelude,
362 start: &ParserState,
363 input: &mut Parser<'i, 't>,
364 ) -> Result<Self::AtRule, ParseError<'i, Self::Error>> {
365 self.state = State::Body;
366 AtRuleParser::parse_block(&mut self.nested(), prelude, start, input)
367 }
368
369 #[inline]
370 fn rule_without_block(
371 &mut self,
372 prelude: AtRulePrelude<'i, T::Prelude>,
373 start: &ParserState,
374 ) -> Result<Self::AtRule, ()> {
375 let loc = start.source_location();
376 let loc = Location {
377 source_index: self.options.source_index,
378 line: loc.line,
379 column: loc.column,
380 };
381
382 match prelude {
383 AtRulePrelude::Import(url, media, supports, layer) => {
384 self.state = State::Imports;
385 self.rules.0.push(CssRule::Import(ImportRule {
386 url: url.into(),
387 layer,
388 supports,
389 media,
390 loc,
391 }));
392 Ok(())
393 }
394 AtRulePrelude::Namespace(prefix, url) => {
395 self.state = State::Namespaces;
396
397 self.rules.0.push(CssRule::Namespace(NamespaceRule {
398 prefix: prefix.map(|x| x.into()),
399 url: url.into(),
400 loc,
401 }));
402 Ok(())
403 }
404 AtRulePrelude::CustomMedia(name, query) => {
405 self.state = State::Body;
406 self.rules.0.push(CssRule::CustomMedia(CustomMediaRule { name, query, loc }));
407 Ok(())
408 }
409 AtRulePrelude::Layer(_) => {
410 if self.state <= State::Layers {
412 self.state = State::Layers;
413 } else {
414 self.state = State::Body;
415 }
416 AtRuleParser::rule_without_block(&mut self.nested(), prelude, start)
417 }
418 AtRulePrelude::Charset => Ok(()),
419 AtRulePrelude::Unknown(name, prelude) => {
420 self.rules.0.push(CssRule::Unknown(UnknownAtRule {
421 name,
422 prelude,
423 block: None,
424 loc,
425 }));
426 Ok(())
427 }
428 AtRulePrelude::Custom(_) => {
429 self.state = State::Body;
430 AtRuleParser::rule_without_block(&mut self.nested(), prelude, start)
431 }
432 _ => Err(()),
433 }
434 }
435}
436
437impl<'a, 'i, T: crate::traits::AtRuleParser<'i>> QualifiedRuleParser<'i> for TopLevelRuleParser<'a, 'i, T> {
438 type Prelude = SelectorList<'i>;
439 type QualifiedRule = ();
440 type Error = ParserError<'i>;
441
442 #[inline]
443 fn parse_prelude<'t>(
444 &mut self,
445 input: &mut Parser<'i, 't>,
446 ) -> Result<Self::Prelude, ParseError<'i, Self::Error>> {
447 self.state = State::Body;
448 QualifiedRuleParser::parse_prelude(&mut self.nested(), input)
449 }
450
451 #[inline]
452 fn parse_block<'t>(
453 &mut self,
454 prelude: Self::Prelude,
455 start: &ParserState,
456 input: &mut Parser<'i, 't>,
457 ) -> Result<Self::QualifiedRule, ParseError<'i, Self::Error>> {
458 QualifiedRuleParser::parse_block(&mut self.nested(), prelude, start, input)
459 }
460}
461
462pub struct NestedRuleParser<'a, 'i, T: crate::traits::AtRuleParser<'i>> {
463 pub options: &'a ParserOptions<'i>,
464 pub at_rule_parser: &'a mut T,
465 declarations: DeclarationList<'i>,
466 important_declarations: DeclarationList<'i>,
467 rules: &'a mut CssRuleList<'i, T::AtRule>,
468 is_in_style_rule: bool,
469 allow_declarations: bool,
470}
471
472impl<'a, 'b, 'i, T: crate::traits::AtRuleParser<'i>> NestedRuleParser<'a, 'i, T> {
473 pub fn parse_nested<'t>(
474 &mut self,
475 input: &mut Parser<'i, 't>,
476 is_style_rule: bool,
477 ) -> Result<(DeclarationBlock<'i>, CssRuleList<'i, T::AtRule>), ParseError<'i, ParserError<'i>>> {
478 let mut rules = CssRuleList(vec![]);
479 let mut nested_parser = NestedRuleParser {
480 options: self.options,
481 at_rule_parser: self.at_rule_parser,
482 declarations: DeclarationList::new(),
483 important_declarations: DeclarationList::new(),
484 rules: &mut rules,
485 is_in_style_rule: self.is_in_style_rule || is_style_rule,
486 allow_declarations: self.allow_declarations || self.is_in_style_rule || is_style_rule,
487 };
488
489 let parse_declarations = nested_parser.parse_declarations();
490 let mut errors = Vec::new();
491 let mut iter = RuleBodyParser::new(input, &mut nested_parser);
492 while let Some(result) = iter.next() {
493 match result {
494 Ok(()) => {}
495 Err((e, _)) => {
496 if parse_declarations {
497 iter.parser.declarations.clear();
498 iter.parser.important_declarations.clear();
499 errors.push(e);
500 } else {
501 if iter.parser.options.error_recovery {
502 iter.parser.options.warn(e);
503 continue;
504 }
505 return Err(e);
506 }
507 }
508 }
509 }
510
511 if parse_declarations {
512 if !errors.is_empty() {
513 if self.options.error_recovery {
514 for err in errors {
515 self.options.warn(err);
516 }
517 } else {
518 return Err(errors.remove(0));
519 }
520 }
521 }
522
523 Ok((
524 DeclarationBlock {
525 declarations: nested_parser.declarations,
526 important_declarations: nested_parser.important_declarations,
527 },
528 rules,
529 ))
530 }
531
532 fn parse_style_block<'t>(
533 &mut self,
534 input: &mut Parser<'i, 't>,
535 ) -> Result<CssRuleList<'i, T::AtRule>, ParseError<'i, ParserError<'i>>> {
536 let loc = input.current_source_location();
537 let loc = Location {
538 source_index: self.options.source_index,
539 line: loc.line,
540 column: loc.column,
541 };
542
543 let (declarations, mut rules) = self.parse_nested(input, false)?;
546
547 if declarations.len() > 0 {
548 rules.0.insert(
549 0,
550 CssRule::NestedDeclarations(NestedDeclarationsRule { declarations, loc }),
551 )
552 }
553
554 Ok(rules)
555 }
556
557 fn loc(&self, start: &ParserState) -> Location {
558 let loc = start.source_location();
559 Location {
560 source_index: self.options.source_index,
561 line: loc.line,
562 column: loc.column,
563 }
564 }
565}
566
567impl<'a, 'b, 'i, T: crate::traits::AtRuleParser<'i>> AtRuleParser<'i> for NestedRuleParser<'a, 'i, T> {
568 type Prelude = AtRulePrelude<'i, T::Prelude>;
569 type AtRule = ();
570 type Error = ParserError<'i>;
571
572 fn parse_prelude<'t>(
573 &mut self,
574 name: CowRcStr<'i>,
575 input: &mut Parser<'i, 't>,
576 ) -> Result<Self::Prelude, ParseError<'i, Self::Error>> {
577 let result = match_ignore_ascii_case! { &*name,
578 "media" => {
579 let media = MediaList::parse(input, &self.options)?;
580 AtRulePrelude::Media(media)
581 },
582 "supports" => {
583 let cond = SupportsCondition::parse(input, )?;
584 AtRulePrelude::Supports(cond)
585 },
586 "font-face" => {
587 AtRulePrelude::FontFace
588 },
589 "font-feature-values" => {
598 let names = match Vec::<FamilyName>::parse(input) {
599 Ok(names) => names,
600 Err(e) => return Err(e)
601 };
602
603 AtRulePrelude::FontFeatureValues(names)
604 },
605 "font-palette-values" => {
606 let name = DashedIdent::parse(input)?;
607 AtRulePrelude::FontPaletteValues(name)
608 },
609 "counter-style" => {
610 let name = CustomIdent::parse(input)?;
611 AtRulePrelude::CounterStyle(name)
612 },
613 "viewport" | "-ms-viewport" => {
614 let prefix = if starts_with_ignore_ascii_case(&*name, "-ms") {
615 VendorPrefix::Ms
616 } else {
617 VendorPrefix::None
618 };
619 AtRulePrelude::Viewport(prefix)
620 },
621 "keyframes" | "-webkit-keyframes" | "-moz-keyframes" | "-o-keyframes" | "-ms-keyframes" => {
622 let prefix = if starts_with_ignore_ascii_case(&*name, "-webkit-") {
623 VendorPrefix::WebKit
624 } else if starts_with_ignore_ascii_case(&*name, "-moz-") {
625 VendorPrefix::Moz
626 } else if starts_with_ignore_ascii_case(&*name, "-o-") {
627 VendorPrefix::O
628 } else if starts_with_ignore_ascii_case(&*name, "-ms-") {
629 VendorPrefix::Ms
630 } else {
631 VendorPrefix::None
632 };
633
634 let name = input.try_parse(KeyframesName::parse)?;
635 AtRulePrelude::Keyframes(name, prefix)
636 },
637 "page" => {
638 let selectors = input.try_parse(|input| input.parse_comma_separated(PageSelector::parse)).unwrap_or_default();
639 AtRulePrelude::Page(selectors)
640 },
641 "-moz-document" => {
642 input.expect_function_matching("url-prefix")?;
645 input.parse_nested_block(|input| {
646 let _ = input.try_parse(|input| -> Result<(), ParseError<'i, Self::Error>> {
649 let s = input.expect_string()?;
650 if !s.is_empty() {
651 return Err(input.new_custom_error(ParserError::InvalidValue))
652 }
653 Ok(())
654 });
655 input.expect_exhausted()?;
656 Ok(())
657 })?;
658
659 AtRulePrelude::MozDocument
660 },
661 "layer" => {
662 let names = match Vec::<LayerName>::parse(input) {
663 Ok(names) => names,
664 Err(ParseError { kind: ParseErrorKind::Basic(BasicParseErrorKind::EndOfInput), .. }) => Vec::new(),
665 Err(e) => return Err(e)
666 };
667 AtRulePrelude::Layer(names)
668 },
669 "container" => {
670 let name = input.try_parse(ContainerName::parse).ok();
671 match input.try_parse(|input| ContainerCondition::parse_with_options(input, &self.options)) {
672 Ok(condition) => AtRulePrelude::Container(name, Some(condition)),
673 Err(e) => {
674 if name.is_some() && input.is_exhausted() {
675 AtRulePrelude::Container(name, None)
677 } else {
678 return Err(e);
680 }
681 }
682 }
683 },
684 "starting-style" => {
685 AtRulePrelude::StartingStyle
686 },
687 "scope" => {
688 let selector_parser = SelectorParser {
689 is_nesting_allowed: true,
690 options: &self.options,
691 };
692
693 let scope_start = if input.try_parse(|input| input.expect_parenthesis_block()).is_ok() {
694 Some(input.parse_nested_block(|input| {
695 SelectorList::parse_relative(&selector_parser, input, ParseErrorRecovery::IgnoreInvalidSelector, NestingRequirement::None)
698 })?)
699 } else {
700 None
701 };
702
703 let scope_end = if input.try_parse(|input| input.expect_ident_matching("to")).is_ok() {
704 input.expect_parenthesis_block()?;
705 Some(input.parse_nested_block(|input| {
706 SelectorList::parse_relative(&selector_parser, input, ParseErrorRecovery::IgnoreInvalidSelector, NestingRequirement::None)
707 })?)
708 } else {
709 None
710 };
711
712 AtRulePrelude::Scope(scope_start, scope_end)
713 },
714 "view-transition" => {
715 AtRulePrelude::ViewTransition
716 },
717 "nest" if self.is_in_style_rule => {
718 self.options.warn(input.new_custom_error(ParserError::DeprecatedNestRule));
719 let selector_parser = SelectorParser {
720 is_nesting_allowed: true,
721 options: &self.options,
722 };
723 let selectors = SelectorList::parse(&selector_parser, input, ParseErrorRecovery::DiscardList, NestingRequirement::Contained)?;
724 AtRulePrelude::Nest(selectors)
725 },
726
727 "value" if self.options.css_modules.is_some() => {
728 return Err(input.new_custom_error(ParserError::DeprecatedCssModulesValueRule));
729 },
730
731 "property" => {
732 let name = DashedIdent::parse(input)?;
733 return Ok(AtRulePrelude::Property(name))
734 },
735
736 "position-try" => {
737 let name = DashedIdent::parse(input)?;
738 return Ok(AtRulePrelude::PositionTry(name))
739 },
740
741 _ => parse_custom_at_rule_prelude(&name, input, self.options, self.at_rule_parser)?
742 };
743
744 if self.is_in_style_rule && !result.allowed_in_style_rule() {
745 return Err(input.new_error(BasicParseErrorKind::AtRuleInvalid(name.clone())));
746 }
747
748 Ok(result)
749 }
750
751 #[inline]
752 fn rule_without_block(
753 &mut self,
754 prelude: AtRulePrelude<'i, T::Prelude>,
755 start: &ParserState,
756 ) -> Result<Self::AtRule, ()> {
757 let loc = self.loc(start);
758 match prelude {
759 AtRulePrelude::Layer(names) => {
760 if self.is_in_style_rule || names.is_empty() {
761 return Err(());
762 }
763
764 self.rules.0.push(CssRule::LayerStatement(LayerStatementRule { names, loc }));
765 Ok(())
766 }
767 AtRulePrelude::Unknown(name, prelude) => {
768 self.rules.0.push(CssRule::Unknown(UnknownAtRule {
769 name,
770 prelude,
771 block: None,
772 loc,
773 }));
774 Ok(())
775 }
776 AtRulePrelude::Custom(prelude) => {
777 self.rules.0.push(parse_custom_at_rule_without_block(
778 prelude,
779 start,
780 self.options,
781 self.at_rule_parser,
782 self.is_in_style_rule,
783 )?);
784 Ok(())
785 }
786 _ => Err(()),
787 }
788 }
789
790 fn parse_block<'t>(
791 &mut self,
792 prelude: Self::Prelude,
793 start: &ParserState,
794 input: &mut Parser<'i, 't>,
795 ) -> Result<(), ParseError<'i, Self::Error>> {
796 let loc = self.loc(start);
797 match prelude {
798 AtRulePrelude::FontFace => {
799 let mut decl_parser = FontFaceDeclarationParser;
800 let mut parser = RuleBodyParser::new(input, &mut decl_parser);
801 let mut properties = vec![];
802 while let Some(decl) = parser.next() {
803 if let Ok(decl) = decl {
804 properties.push(decl);
805 }
806 }
807 self.rules.0.push(CssRule::FontFace(FontFaceRule { properties, loc }));
808 Ok(())
809 }
810 AtRulePrelude::FontPaletteValues(name) => {
827 let rule = FontPaletteValuesRule::parse(name, input, loc)?;
828 self.rules.0.push(CssRule::FontPaletteValues(rule));
829 Ok(())
830 }
831 AtRulePrelude::CounterStyle(name) => {
832 self.rules.0.push(CssRule::CounterStyle(CounterStyleRule {
833 name,
834 declarations: DeclarationBlock::parse(input, self.options)?,
835 loc,
836 }));
837 Ok(())
838 }
839 AtRulePrelude::Media(query) => {
840 let rules = self.parse_style_block(input)?;
841 self.rules.0.push(CssRule::Media(MediaRule { query, rules, loc }));
842 Ok(())
843 }
844 AtRulePrelude::Supports(condition) => {
845 let rules = self.parse_style_block(input)?;
846 self.rules.0.push(CssRule::Supports(SupportsRule { condition, rules, loc }));
847 Ok(())
848 }
849 AtRulePrelude::Container(name, condition) => {
850 let rules = self.parse_style_block(input)?;
851 self.rules.0.push(CssRule::Container(ContainerRule {
852 name,
853 condition,
854 rules,
855 loc,
856 }));
857 Ok(())
858 }
859 AtRulePrelude::Scope(scope_start, scope_end) => {
860 let rules = self.parse_style_block(input)?;
861 self.rules.0.push(CssRule::Scope(ScopeRule {
862 scope_start,
863 scope_end,
864 rules,
865 loc,
866 }));
867 Ok(())
868 }
869 AtRulePrelude::Viewport(vendor_prefix) => {
870 self.rules.0.push(CssRule::Viewport(ViewportRule {
871 vendor_prefix,
872 declarations: DeclarationBlock::parse(input, self.options)?,
875 loc,
876 }));
877 Ok(())
878 }
879 AtRulePrelude::Keyframes(name, vendor_prefix) => {
880 let mut parser = KeyframeListParser;
881 let iter = RuleBodyParser::new(input, &mut parser);
882 self.rules.0.push(CssRule::Keyframes(KeyframesRule {
883 name,
884 keyframes: iter.filter_map(Result::ok).collect(),
885 vendor_prefix,
886 loc,
887 }));
888 Ok(())
889 }
890 AtRulePrelude::Page(selectors) => {
891 let rule = PageRule::parse(selectors, input, loc, self.options)?;
892 self.rules.0.push(CssRule::Page(rule));
893 Ok(())
894 }
895 AtRulePrelude::MozDocument => {
896 let rules = self.parse_style_block(input)?;
897 self.rules.0.push(CssRule::MozDocument(MozDocumentRule { rules, loc }));
898 Ok(())
899 }
900 AtRulePrelude::Layer(names) => {
901 let name = if names.is_empty() {
902 None
903 } else if names.len() == 1 {
904 names.into_iter().next()
905 } else {
906 return Err(input.new_error(BasicParseErrorKind::AtRuleBodyInvalid));
907 };
908
909 let rules = self.parse_style_block(input)?;
910 self.rules.0.push(CssRule::LayerBlock(LayerBlockRule { name, rules, loc }));
911 Ok(())
912 }
913 AtRulePrelude::Property(name) => {
914 self.rules.0.push(CssRule::Property(PropertyRule::parse(name, input, loc)?));
915 Ok(())
916 }
917 AtRulePrelude::PositionTry(name) => {
918 self.rules.0.push(CssRule::PositionTry(PositionTryRule {
919 name,
920 declarations: DeclarationBlock::parse(input, self.options)?,
921 loc,
922 }));
923 Ok(())
924 }
925 AtRulePrelude::Import(..)
926 | AtRulePrelude::Namespace(..)
927 | AtRulePrelude::CustomMedia(..)
928 | AtRulePrelude::Charset => {
929 Err(input.new_unexpected_token_error(Token::CurlyBracketBlock))
931 }
932 AtRulePrelude::StartingStyle => {
933 let rules = self.parse_style_block(input)?;
934 self.rules.0.push(CssRule::StartingStyle(StartingStyleRule { rules, loc }));
935 Ok(())
936 }
937 AtRulePrelude::ViewTransition => {
938 self
939 .rules
940 .0
941 .push(CssRule::ViewTransition(ViewTransitionRule::parse(input, loc)?));
942 Ok(())
943 }
944 AtRulePrelude::Nest(selectors) => {
945 let (declarations, rules) = self.parse_nested(input, true)?;
946 self.rules.0.push(CssRule::Nesting(NestingRule {
947 style: StyleRule {
948 selectors,
949 declarations,
950 vendor_prefix: VendorPrefix::empty(),
951 rules,
952 loc,
953 },
954 loc,
955 }));
956 Ok(())
957 }
958 AtRulePrelude::FontFeatureValues(family_names) => {
959 let rule = FontFeatureValuesRule::parse(family_names, input, loc, self.options)?;
960 self.rules.0.push(CssRule::FontFeatureValues(rule));
961 Ok(())
962 }
963 AtRulePrelude::Unknown(name, prelude) => {
964 self.rules.0.push(CssRule::Unknown(UnknownAtRule {
965 name,
966 prelude,
967 block: Some(TokenList::parse(input, &self.options, 0)?),
968 loc,
969 }));
970 Ok(())
971 }
972 AtRulePrelude::Custom(prelude) => {
973 self.rules.0.push(parse_custom_at_rule_body(
974 prelude,
975 input,
976 start,
977 self.options,
978 self.at_rule_parser,
979 self.is_in_style_rule,
980 )?);
981 Ok(())
982 }
983 }
984 }
985}
986
987impl<'a, 'b, 'i, T: crate::traits::AtRuleParser<'i>> QualifiedRuleParser<'i> for NestedRuleParser<'a, 'i, T> {
988 type Prelude = SelectorList<'i>;
989 type QualifiedRule = ();
990 type Error = ParserError<'i>;
991
992 fn parse_prelude<'t>(
993 &mut self,
994 input: &mut Parser<'i, 't>,
995 ) -> Result<Self::Prelude, ParseError<'i, Self::Error>> {
996 let selector_parser = SelectorParser {
997 is_nesting_allowed: true,
998 options: &self.options,
999 };
1000 if self.is_in_style_rule {
1001 SelectorList::parse_relative(
1002 &selector_parser,
1003 input,
1004 ParseErrorRecovery::DiscardList,
1005 NestingRequirement::Implicit,
1006 )
1007 } else {
1008 SelectorList::parse(
1009 &selector_parser,
1010 input,
1011 ParseErrorRecovery::DiscardList,
1012 NestingRequirement::None,
1013 )
1014 }
1015 }
1016
1017 fn parse_block<'t>(
1018 &mut self,
1019 selectors: Self::Prelude,
1020 start: &ParserState,
1021 input: &mut Parser<'i, 't>,
1022 ) -> Result<(), ParseError<'i, Self::Error>> {
1023 let loc = self.loc(start);
1024 let (declarations, rules) = self.parse_nested(input, true)?;
1025 self.rules.0.push(CssRule::Style(StyleRule {
1026 selectors,
1027 vendor_prefix: VendorPrefix::empty(),
1028 declarations,
1029 rules,
1030 loc,
1031 }));
1032 Ok(())
1033 }
1034}
1035
1036impl<'a, 'i, T: crate::traits::AtRuleParser<'i>> cssparser::DeclarationParser<'i> for NestedRuleParser<'a, 'i, T> {
1038 type Declaration = ();
1039 type Error = ParserError<'i>;
1040
1041 fn parse_value<'t>(
1042 &mut self,
1043 name: CowRcStr<'i>,
1044 input: &mut cssparser::Parser<'i, 't>,
1045 _declaration_start: &ParserState,
1046 ) -> Result<Self::Declaration, cssparser::ParseError<'i, Self::Error>> {
1047 if self.rules.0.is_empty() {
1048 parse_declaration(
1049 name,
1050 input,
1051 &mut self.declarations,
1052 &mut self.important_declarations,
1053 &self.options,
1054 )
1055 } else if let Some(CssRule::NestedDeclarations(last)) = self.rules.0.last_mut() {
1056 parse_declaration(
1057 name,
1058 input,
1059 &mut last.declarations.declarations,
1060 &mut last.declarations.important_declarations,
1061 &self.options,
1062 )
1063 } else {
1064 let loc = self.loc(&input.state());
1065 let mut nested = NestedDeclarationsRule {
1066 declarations: DeclarationBlock::new(),
1067 loc,
1068 };
1069
1070 parse_declaration(
1071 name,
1072 input,
1073 &mut nested.declarations.declarations,
1074 &mut nested.declarations.important_declarations,
1075 &self.options,
1076 )?;
1077
1078 self.rules.0.push(CssRule::NestedDeclarations(nested));
1079 Ok(())
1080 }
1081 }
1082}
1083
1084impl<'a, 'b, 'i, T: crate::traits::AtRuleParser<'i>> RuleBodyItemParser<'i, (), ParserError<'i>>
1085 for NestedRuleParser<'a, 'i, T>
1086{
1087 fn parse_qualified(&self) -> bool {
1088 true
1089 }
1090
1091 fn parse_declarations(&self) -> bool {
1092 self.allow_declarations
1093 }
1094}
1095
1096fn parse_custom_at_rule_prelude<'i, 't, T: crate::traits::AtRuleParser<'i>>(
1097 name: &CowRcStr<'i>,
1098 input: &mut Parser<'i, 't>,
1099 options: &ParserOptions<'i>,
1100 at_rule_parser: &mut T,
1101) -> Result<AtRulePrelude<'i, T::Prelude>, ParseError<'i, ParserError<'i>>> {
1102 match at_rule_parser.parse_prelude(name.clone(), input, options) {
1103 Ok(prelude) => return Ok(AtRulePrelude::Custom(prelude)),
1104 Err(ParseError {
1105 kind: ParseErrorKind::Basic(BasicParseErrorKind::AtRuleInvalid(..)),
1106 ..
1107 }) => {}
1108 Err(err) => {
1109 return Err(match &err.kind {
1110 ParseErrorKind::Basic(kind) => ParseError {
1111 kind: ParseErrorKind::Basic(kind.clone()),
1112 location: err.location,
1113 },
1114 _ => input.new_custom_error(ParserError::AtRulePreludeInvalid),
1115 })
1116 }
1117 }
1118
1119 options.warn(input.new_error(BasicParseErrorKind::AtRuleInvalid(name.clone())));
1120 input.skip_whitespace();
1121 let tokens = TokenList::parse(input, &options, 0)?;
1122 Ok(AtRulePrelude::Unknown(name.into(), tokens))
1123}
1124
1125fn parse_custom_at_rule_body<'i, 't, T: crate::traits::AtRuleParser<'i>>(
1126 prelude: T::Prelude,
1127 input: &mut Parser<'i, 't>,
1128 start: &ParserState,
1129 options: &ParserOptions<'i>,
1130 at_rule_parser: &mut T,
1131 is_nested: bool,
1132) -> Result<CssRule<'i, T::AtRule>, ParseError<'i, ParserError<'i>>> {
1133 at_rule_parser
1134 .parse_block(prelude, start, input, options, is_nested)
1135 .map(|prelude| CssRule::Custom(prelude))
1136 .map_err(|err| match &err.kind {
1137 ParseErrorKind::Basic(kind) => ParseError {
1138 kind: ParseErrorKind::Basic(kind.clone()),
1139 location: err.location,
1140 },
1141 _ => input.new_error(BasicParseErrorKind::AtRuleBodyInvalid),
1142 })
1143}
1144
1145fn parse_custom_at_rule_without_block<'i, 't, T: crate::traits::AtRuleParser<'i>>(
1146 prelude: T::Prelude,
1147 start: &ParserState,
1148 options: &ParserOptions<'i>,
1149 at_rule_parser: &mut T,
1150 is_nested: bool,
1151) -> Result<CssRule<'i, T::AtRule>, ()> {
1152 at_rule_parser
1153 .rule_without_block(prelude, start, options, is_nested)
1154 .map(|prelude| CssRule::Custom(prelude))
1155}
1156
1157pub fn parse_rule_list<'a, 'i, 't, T: crate::traits::AtRuleParser<'i>>(
1158 input: &mut Parser<'i, 't>,
1159 options: &'a ParserOptions<'i>,
1160 at_rule_parser: &mut T,
1161) -> Result<CssRuleList<'i, T::AtRule>, ParseError<'i, ParserError<'i>>> {
1162 let mut parser = NestedRuleParser {
1163 options,
1164 at_rule_parser,
1165 declarations: DeclarationList::new(),
1166 important_declarations: DeclarationList::new(),
1167 rules: &mut CssRuleList(Vec::new()),
1168 is_in_style_rule: false,
1169 allow_declarations: false,
1170 };
1171
1172 let (_, rules) = parser.parse_nested(input, false)?;
1173 Ok(rules)
1174}
1175
1176pub fn parse_style_block<'a, 'i, 't, T: crate::traits::AtRuleParser<'i>>(
1177 input: &mut Parser<'i, 't>,
1178 options: &'a ParserOptions<'i>,
1179 at_rule_parser: &mut T,
1180 is_nested: bool,
1181) -> Result<CssRuleList<'i, T::AtRule>, ParseError<'i, ParserError<'i>>> {
1182 let mut parser = NestedRuleParser {
1183 options,
1184 at_rule_parser,
1185 declarations: DeclarationList::new(),
1186 important_declarations: DeclarationList::new(),
1187 rules: &mut CssRuleList(Vec::new()),
1188 is_in_style_rule: is_nested,
1189 allow_declarations: true,
1190 };
1191
1192 parser.parse_style_block(input)
1193}
1194
1195#[inline]
1196pub fn starts_with_ignore_ascii_case(string: &str, prefix: &str) -> bool {
1197 string.len() >= prefix.len() && string.as_bytes()[0..prefix.len()].eq_ignore_ascii_case(prefix.as_bytes())
1198}