1use std::borrow::Cow;
4use std::ops::Range;
5
6use crate::context::{DeclarationContext, PropertyHandlerContext};
7use crate::error::{ParserError, PrinterError, PrinterErrorKind};
8use crate::parser::ParserOptions;
9use crate::printer::Printer;
10use crate::properties::box_shadow::BoxShadowHandler;
11use crate::properties::custom::{CustomProperty, CustomPropertyName};
12use crate::properties::masking::MaskHandler;
13use crate::properties::text::{Direction, UnicodeBidi};
14use crate::properties::{
15 align::AlignHandler,
16 animation::AnimationHandler,
17 background::BackgroundHandler,
18 border::BorderHandler,
19 contain::ContainerHandler,
20 display::DisplayHandler,
21 flex::FlexHandler,
22 font::FontHandler,
23 grid::GridHandler,
24 list::ListStyleHandler,
25 margin_padding::*,
26 outline::OutlineHandler,
27 overflow::OverflowHandler,
28 position::PositionHandler,
29 prefix_handler::{FallbackHandler, PrefixHandler},
30 size::SizeHandler,
31 text::TextDecorationHandler,
32 transform::TransformHandler,
33 transition::TransitionHandler,
34 ui::ColorSchemeHandler,
35};
36use crate::properties::{Property, PropertyId};
37use crate::selector::SelectorList;
38use crate::traits::{PropertyHandler, ToCss};
39use crate::values::ident::DashedIdent;
40use crate::values::string::CowArcStr;
41#[cfg(feature = "visitor")]
42use crate::visitor::Visit;
43use cssparser::*;
44use indexmap::IndexMap;
45use smallvec::SmallVec;
46
47#[derive(Debug, PartialEq, Clone, Default)]
53#[cfg_attr(feature = "visitor", derive(Visit), visit(visit_declaration_block, PROPERTIES))]
54#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
55#[cfg_attr(
56 feature = "serde",
57 derive(serde::Serialize, serde::Deserialize),
58 serde(rename_all = "camelCase")
59)]
60#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
61pub struct DeclarationBlock<'i> {
62 #[cfg_attr(feature = "serde", serde(borrow, default))]
64 pub important_declarations: Vec<Property<'i>>,
65 #[cfg_attr(feature = "serde", serde(default))]
67 pub declarations: Vec<Property<'i>>,
68}
69
70impl<'i> DeclarationBlock<'i> {
71 pub fn parse<'a, 't>(
73 input: &mut Parser<'i, 't>,
74 options: &'a ParserOptions<'i>,
75 ) -> Result<Self, ParseError<'i, ParserError<'i>>> {
76 let mut important_declarations = DeclarationList::new();
77 let mut declarations = DeclarationList::new();
78 let mut decl_parser = PropertyDeclarationParser {
79 important_declarations: &mut important_declarations,
80 declarations: &mut declarations,
81 options,
82 };
83 let mut parser = RuleBodyParser::new(input, &mut decl_parser);
84 while let Some(res) = parser.next() {
85 if let Err((err, _)) = res {
86 if options.error_recovery {
87 options.warn(err);
88 continue;
89 }
90 return Err(err);
91 }
92 }
93
94 Ok(DeclarationBlock {
95 important_declarations,
96 declarations,
97 })
98 }
99
100 pub fn parse_string<'o>(
102 input: &'i str,
103 options: ParserOptions<'i>,
104 ) -> Result<Self, ParseError<'i, ParserError<'i>>> {
105 let mut input = ParserInput::new(input);
106 let mut parser = Parser::new(&mut input);
107 let result = Self::parse(&mut parser, &options)?;
108 parser.expect_exhausted()?;
109 Ok(result)
110 }
111
112 pub fn new() -> Self {
114 Self {
115 declarations: vec![],
116 important_declarations: vec![],
117 }
118 }
119
120 pub fn len(&self) -> usize {
122 self.declarations.len() + self.important_declarations.len()
123 }
124}
125
126impl<'i> ToCss for DeclarationBlock<'i> {
127 fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
128 where
129 W: std::fmt::Write,
130 {
131 let len = self.declarations.len() + self.important_declarations.len();
132 let mut i = 0;
133
134 macro_rules! write {
135 ($decls: expr, $important: literal) => {
136 for decl in &$decls {
137 decl.to_css(dest, $important)?;
138 if i != len - 1 {
139 dest.write_char(';')?;
140 dest.whitespace()?;
141 }
142 i += 1;
143 }
144 };
145 }
146
147 write!(self.declarations, false);
148 write!(self.important_declarations, true);
149 Ok(())
150 }
151}
152
153impl<'i> DeclarationBlock<'i> {
154 pub fn to_css_block<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
156 where
157 W: std::fmt::Write,
158 {
159 dest.whitespace()?;
160 dest.write_char('{')?;
161 dest.indent();
162 dest.newline()?;
163
164 self.to_css_declarations(dest, false, &parcel_selectors::SelectorList(SmallVec::new()), 0)?;
165
166 dest.dedent();
167 dest.newline()?;
168 dest.write_char('}')
169 }
170
171 pub(crate) fn has_printable_declarations(&self) -> bool {
172 if self.len() > 1 {
173 return true;
174 }
175
176 if self.declarations.len() == 1 {
177 !matches!(self.declarations[0], crate::properties::Property::Composes(_))
178 } else if self.important_declarations.len() == 1 {
179 !matches!(self.important_declarations[0], crate::properties::Property::Composes(_))
180 } else {
181 false
182 }
183 }
184
185 pub fn to_css_declarations<W>(
187 &self,
188 dest: &mut Printer<W>,
189 has_nested_rules: bool,
190 selectors: &SelectorList,
191 source_index: u32,
192 ) -> Result<(), PrinterError>
193 where
194 W: std::fmt::Write,
195 {
196 let mut i = 0;
197 let len = self.len();
198
199 macro_rules! write {
200 ($decls: expr, $important: literal) => {
201 for decl in &$decls {
202 if let crate::properties::Property::Composes(composes) = &decl {
205 if dest.is_nested() && dest.css_module.is_some() {
206 return Err(dest.error(PrinterErrorKind::InvalidComposesNesting, composes.loc));
207 }
208
209 if let Some(css_module) = &mut dest.css_module {
210 css_module
211 .handle_composes(&selectors, &composes, source_index)
212 .map_err(|e| dest.error(e, composes.loc))?;
213 continue;
214 }
215 }
216
217 if i > 0 {
218 dest.newline()?;
219 }
220
221 decl.to_css(dest, $important)?;
222 if i != len - 1 || !dest.minify || has_nested_rules {
223 dest.write_char(';')?;
224 }
225
226 i += 1;
227 }
228 };
229 }
230
231 write!(self.declarations, false);
232 write!(self.important_declarations, true);
233 Ok(())
234 }
235}
236
237impl<'i> DeclarationBlock<'i> {
238 pub(crate) fn minify(
239 &mut self,
240 handler: &mut DeclarationHandler<'i>,
241 important_handler: &mut DeclarationHandler<'i>,
242 context: &mut PropertyHandlerContext<'i, '_>,
243 ) {
244 macro_rules! handle {
245 ($decls: expr, $handler: expr, $important: literal) => {
246 for decl in $decls.iter() {
247 context.is_important = $important;
248 let handled = $handler.handle_property(decl, context);
249
250 if !handled {
251 $handler.decls.push(decl.clone());
252 }
253 }
254 };
255 }
256
257 handle!(self.important_declarations, important_handler, true);
258 handle!(self.declarations, handler, false);
259
260 handler.finalize(context);
261 important_handler.finalize(context);
262 self.important_declarations = std::mem::take(&mut important_handler.decls);
263 self.declarations = std::mem::take(&mut handler.decls);
264 }
265
266 pub fn is_empty(&self) -> bool {
268 return self.declarations.is_empty() && self.important_declarations.is_empty();
269 }
270
271 pub(crate) fn property_location<'t>(
272 &self,
273 input: &mut Parser<'i, 't>,
274 index: usize,
275 ) -> Result<(Range<SourceLocation>, Range<SourceLocation>), ParseError<'i, ParserError<'i>>> {
276 for _ in 0..index {
278 input.expect_ident()?;
279 input.expect_colon()?;
280 input.parse_until_after(Delimiter::Semicolon, |parser| {
281 while parser.next().is_ok() {}
282 Ok(())
283 })?;
284 }
285
286 input.skip_whitespace();
288 let key_start = input.current_source_location();
289 input.expect_ident()?;
290 let key_end = input.current_source_location();
291 let key_range = key_start..key_end;
292
293 input.expect_colon()?;
294 input.skip_whitespace();
295
296 let val_start = input.current_source_location();
298 input.parse_until_before(Delimiter::Semicolon, |parser| {
299 while parser.next().is_ok() {}
300 Ok(())
301 })?;
302 let val_end = input.current_source_location();
303 let val_range = val_start..val_end;
304
305 Ok((key_range, val_range))
306 }
307}
308
309impl<'i> DeclarationBlock<'i> {
310 pub fn iter(&self) -> impl std::iter::DoubleEndedIterator<Item = (&Property<'i>, bool)> {
312 self
313 .declarations
314 .iter()
315 .map(|property| (property, false))
316 .chain(self.important_declarations.iter().map(|property| (property, true)))
317 }
318
319 pub fn iter_mut(&mut self) -> impl std::iter::DoubleEndedIterator<Item = &mut Property<'i>> {
321 self.declarations.iter_mut().chain(self.important_declarations.iter_mut())
322 }
323
324 pub fn get<'a>(&'a self, property_id: &PropertyId) -> Option<(Cow<'a, Property<'i>>, bool)> {
330 if property_id.is_shorthand() {
331 if let Some((shorthand, important)) = property_id.shorthand_value(&self) {
332 return Some((Cow::Owned(shorthand), important));
333 }
334 } else {
335 for (property, important) in self.iter().rev() {
336 if property.property_id() == *property_id {
337 return Some((Cow::Borrowed(property), important));
338 }
339
340 if let Some(val) = property.longhand(&property_id) {
341 return Some((Cow::Owned(val), important));
342 }
343 }
344 }
345
346 None
347 }
348
349 pub fn set(&mut self, property: Property<'i>, important: bool) {
355 let property_id = property.property_id();
356 let declarations = if important {
357 self.declarations.retain(|decl| decl.property_id() != property_id);
359 &mut self.important_declarations
360 } else {
361 self.important_declarations.retain(|decl| decl.property_id() != property_id);
363 &mut self.declarations
364 };
365
366 let longhands = property_id.longhands().unwrap_or_else(|| vec![property.property_id()]);
367
368 for decl in declarations.iter_mut().rev() {
369 {
370 let id = decl.property_id();
374 let id_longhands = id.longhands().unwrap_or_else(|| vec![id]);
375 if longhands.iter().any(|longhand| {
376 let logical_group = longhand.logical_group();
377 let category = longhand.category();
378
379 logical_group.is_some()
380 && id_longhands.iter().any(|id_longhand| {
381 logical_group == id_longhand.logical_group() && category != id_longhand.category()
382 })
383 }) {
384 break;
385 }
386 }
387
388 if decl.property_id() == property_id {
389 *decl = property;
390 return;
391 }
392
393 if decl.set_longhand(&property).is_ok() {
395 return;
396 }
397 }
398
399 declarations.push(property)
400 }
401
402 pub fn remove(&mut self, property_id: &PropertyId) {
408 fn remove<'i, 'a>(declarations: &mut Vec<Property<'i>>, property_id: &PropertyId<'a>) {
409 let longhands = property_id.longhands().unwrap_or(vec![]);
410 let mut i = 0;
411 while i < declarations.len() {
412 let replacement = {
413 let property = &declarations[i];
414 let id = property.property_id();
415 if id == *property_id || longhands.contains(&id) {
416 None
419 } else if longhands.is_empty() && id.longhands().unwrap_or(vec![]).contains(&property_id) {
420 Some(
423 id.longhands()
424 .unwrap()
425 .iter()
426 .filter_map(|longhand| {
427 if *longhand == *property_id {
428 None
429 } else {
430 property.longhand(longhand)
431 }
432 })
433 .collect::<Vec<Property>>(),
434 )
435 } else {
436 i += 1;
437 continue;
438 }
439 };
440
441 match replacement {
442 Some(properties) => {
443 let count = properties.len();
444 declarations.splice(i..i + 1, properties);
445 i += count;
446 }
447 None => {
448 declarations.remove(i);
449 }
450 }
451 }
452 }
453
454 remove(&mut self.declarations, property_id);
455 remove(&mut self.important_declarations, property_id);
456 }
457}
458
459struct PropertyDeclarationParser<'a, 'i> {
460 important_declarations: &'a mut Vec<Property<'i>>,
461 declarations: &'a mut Vec<Property<'i>>,
462 options: &'a ParserOptions<'i>,
463}
464
465impl<'a, 'i> cssparser::DeclarationParser<'i> for PropertyDeclarationParser<'a, 'i> {
467 type Declaration = ();
468 type Error = ParserError<'i>;
469
470 fn parse_value<'t>(
471 &mut self,
472 name: CowRcStr<'i>,
473 input: &mut cssparser::Parser<'i, 't>,
474 _declaration_start: &ParserState,
475 ) -> Result<Self::Declaration, cssparser::ParseError<'i, Self::Error>> {
476 parse_declaration(
477 name,
478 input,
479 &mut self.declarations,
480 &mut self.important_declarations,
481 &self.options,
482 )
483 }
484}
485
486impl<'a, 'i> AtRuleParser<'i> for PropertyDeclarationParser<'a, 'i> {
488 type Prelude = ();
489 type AtRule = ();
490 type Error = ParserError<'i>;
491}
492
493impl<'a, 'i> QualifiedRuleParser<'i> for PropertyDeclarationParser<'a, 'i> {
494 type Prelude = ();
495 type QualifiedRule = ();
496 type Error = ParserError<'i>;
497}
498
499impl<'a, 'i> RuleBodyItemParser<'i, (), ParserError<'i>> for PropertyDeclarationParser<'a, 'i> {
500 fn parse_qualified(&self) -> bool {
501 false
502 }
503
504 fn parse_declarations(&self) -> bool {
505 true
506 }
507}
508
509pub(crate) fn parse_declaration<'i, 't>(
510 name: CowRcStr<'i>,
511 input: &mut cssparser::Parser<'i, 't>,
512 declarations: &mut DeclarationList<'i>,
513 important_declarations: &mut DeclarationList<'i>,
514 options: &ParserOptions<'i>,
515) -> Result<(), cssparser::ParseError<'i, ParserError<'i>>> {
516 let property_id = PropertyId::from(CowArcStr::from(name));
520 let mut delimiters = Delimiter::Bang;
521 if !matches!(property_id, PropertyId::Custom(CustomPropertyName::Custom(..))) {
522 delimiters = delimiters | Delimiter::CurlyBracketBlock;
523 }
524 let property = input.parse_until_before(delimiters, |input| Property::parse(property_id, input, options))?;
525 let important = input
526 .try_parse(|input| {
527 input.expect_delim('!')?;
528 input.expect_ident_matching("important")
529 })
530 .is_ok();
531 input.expect_exhausted()?;
532 if important {
533 important_declarations.push(property);
534 } else {
535 declarations.push(property);
536 }
537 Ok(())
538}
539
540pub(crate) type DeclarationList<'i> = Vec<Property<'i>>;
541
542#[derive(Default)]
543pub(crate) struct DeclarationHandler<'i> {
544 background: BackgroundHandler<'i>,
545 border: BorderHandler<'i>,
546 outline: OutlineHandler,
547 flex: FlexHandler,
548 grid: GridHandler<'i>,
549 align: AlignHandler,
550 size: SizeHandler,
551 margin: MarginHandler<'i>,
552 padding: PaddingHandler<'i>,
553 scroll_margin: ScrollMarginHandler<'i>,
554 scroll_padding: ScrollPaddingHandler<'i>,
555 font: FontHandler<'i>,
556 text: TextDecorationHandler<'i>,
557 list: ListStyleHandler<'i>,
558 transition: TransitionHandler<'i>,
559 animation: AnimationHandler<'i>,
560 display: DisplayHandler<'i>,
561 position: PositionHandler,
562 inset: InsetHandler<'i>,
563 overflow: OverflowHandler,
564 transform: TransformHandler,
565 box_shadow: BoxShadowHandler,
566 mask: MaskHandler<'i>,
567 container: ContainerHandler<'i>,
568 color_scheme: ColorSchemeHandler,
569 fallback: FallbackHandler,
570 prefix: PrefixHandler,
571 direction: Option<Direction>,
572 unicode_bidi: Option<UnicodeBidi>,
573 custom_properties: IndexMap<DashedIdent<'i>, usize>,
574 decls: DeclarationList<'i>,
575}
576
577impl<'i> DeclarationHandler<'i> {
578 pub fn handle_property(
579 &mut self,
580 property: &Property<'i>,
581 context: &mut PropertyHandlerContext<'i, '_>,
582 ) -> bool {
583 self.background.handle_property(property, &mut self.decls, context)
584 || self.border.handle_property(property, &mut self.decls, context)
585 || self.outline.handle_property(property, &mut self.decls, context)
586 || self.flex.handle_property(property, &mut self.decls, context)
587 || self.grid.handle_property(property, &mut self.decls, context)
588 || self.align.handle_property(property, &mut self.decls, context)
589 || self.size.handle_property(property, &mut self.decls, context)
590 || self.margin.handle_property(property, &mut self.decls, context)
591 || self.padding.handle_property(property, &mut self.decls, context)
592 || self.scroll_margin.handle_property(property, &mut self.decls, context)
593 || self.scroll_padding.handle_property(property, &mut self.decls, context)
594 || self.font.handle_property(property, &mut self.decls, context)
595 || self.text.handle_property(property, &mut self.decls, context)
596 || self.list.handle_property(property, &mut self.decls, context)
597 || self.transition.handle_property(property, &mut self.decls, context)
598 || self.animation.handle_property(property, &mut self.decls, context)
599 || self.display.handle_property(property, &mut self.decls, context)
600 || self.position.handle_property(property, &mut self.decls, context)
601 || self.inset.handle_property(property, &mut self.decls, context)
602 || self.overflow.handle_property(property, &mut self.decls, context)
603 || self.transform.handle_property(property, &mut self.decls, context)
604 || self.box_shadow.handle_property(property, &mut self.decls, context)
605 || self.mask.handle_property(property, &mut self.decls, context)
606 || self.container.handle_property(property, &mut self.decls, context)
607 || self.color_scheme.handle_property(property, &mut self.decls, context)
608 || self.fallback.handle_property(property, &mut self.decls, context)
609 || self.prefix.handle_property(property, &mut self.decls, context)
610 || self.handle_all(property)
611 || self.handle_custom_property(property, context)
612 }
613
614 fn handle_custom_property(
615 &mut self,
616 property: &Property<'i>,
617 context: &mut PropertyHandlerContext<'i, '_>,
618 ) -> bool {
619 if let Property::Custom(custom) = property {
620 if context.unused_symbols.contains(custom.name.as_ref()) {
621 return true;
622 }
623
624 if let CustomPropertyName::Custom(name) = &custom.name {
625 if let Some(index) = self.custom_properties.get(name) {
626 if self.decls[*index] == *property {
627 return true;
628 }
629 let mut custom = custom.clone();
630 self.add_conditional_fallbacks(&mut custom, context);
631 self.decls[*index] = Property::Custom(custom);
632 } else {
633 self.custom_properties.insert(name.clone(), self.decls.len());
634 let mut custom = custom.clone();
635 self.add_conditional_fallbacks(&mut custom, context);
636 self.decls.push(Property::Custom(custom));
637 }
638
639 return true;
640 }
641 }
642
643 false
644 }
645
646 fn handle_all(&mut self, property: &Property<'i>) -> bool {
647 match property {
650 Property::UnicodeBidi(bidi) => {
651 self.unicode_bidi = Some(*bidi);
652 true
653 }
654 Property::Direction(direction) => {
655 self.direction = Some(*direction);
656 true
657 }
658 Property::All(keyword) => {
659 let mut handler = DeclarationHandler {
660 unicode_bidi: self.unicode_bidi.clone(),
661 direction: self.direction.clone(),
662 ..Default::default()
663 };
664 for (key, index) in self.custom_properties.drain(..) {
665 handler.custom_properties.insert(key, handler.decls.len());
666 handler.decls.push(self.decls[index].clone());
667 }
668 handler.decls.push(Property::All(keyword.clone()));
669 *self = handler;
670 true
671 }
672 _ => false,
673 }
674 }
675
676 fn add_conditional_fallbacks(
677 &self,
678 custom: &mut CustomProperty<'i>,
679 context: &mut PropertyHandlerContext<'i, '_>,
680 ) {
681 if context.context != DeclarationContext::Keyframes {
682 let fallbacks = custom.value.get_fallbacks(context.targets);
683 for (condition, fallback) in fallbacks {
684 context.add_conditional_property(
685 condition,
686 Property::Custom(CustomProperty {
687 name: custom.name.clone(),
688 value: fallback,
689 }),
690 );
691 }
692 }
693 }
694
695 pub fn finalize(&mut self, context: &mut PropertyHandlerContext<'i, '_>) {
696 if let Some(direction) = std::mem::take(&mut self.direction) {
697 self.decls.push(Property::Direction(direction));
698 }
699 if let Some(unicode_bidi) = std::mem::take(&mut self.unicode_bidi) {
700 self.decls.push(Property::UnicodeBidi(unicode_bidi));
701 }
702
703 self.background.finalize(&mut self.decls, context);
704 self.border.finalize(&mut self.decls, context);
705 self.outline.finalize(&mut self.decls, context);
706 self.flex.finalize(&mut self.decls, context);
707 self.grid.finalize(&mut self.decls, context);
708 self.align.finalize(&mut self.decls, context);
709 self.size.finalize(&mut self.decls, context);
710 self.margin.finalize(&mut self.decls, context);
711 self.padding.finalize(&mut self.decls, context);
712 self.scroll_margin.finalize(&mut self.decls, context);
713 self.scroll_padding.finalize(&mut self.decls, context);
714 self.font.finalize(&mut self.decls, context);
715 self.text.finalize(&mut self.decls, context);
716 self.list.finalize(&mut self.decls, context);
717 self.transition.finalize(&mut self.decls, context);
718 self.animation.finalize(&mut self.decls, context);
719 self.display.finalize(&mut self.decls, context);
720 self.position.finalize(&mut self.decls, context);
721 self.inset.finalize(&mut self.decls, context);
722 self.overflow.finalize(&mut self.decls, context);
723 self.transform.finalize(&mut self.decls, context);
724 self.box_shadow.finalize(&mut self.decls, context);
725 self.mask.finalize(&mut self.decls, context);
726 self.container.finalize(&mut self.decls, context);
727 self.color_scheme.finalize(&mut self.decls, context);
728 self.fallback.finalize(&mut self.decls, context);
729 self.prefix.finalize(&mut self.decls, context);
730 self.custom_properties.clear();
731 }
732}