Skip to content

Commit e66d99c

Browse files
committed
Ensure fallback rules for logical properties are before nested rules
Fixes parcel-bundler#175 Also ensures that nested rules use a different compilation context from parents so that logical rules are not merged.
1 parent 11f4179 commit e66d99c

File tree

6 files changed

+78
-7
lines changed

6 files changed

+78
-7
lines changed

src/context.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ impl<'i, 'o> PropertyHandlerContext<'i, 'o> {
5050
}
5151
}
5252

53+
pub fn child(&self, context: DeclarationContext) -> Self {
54+
PropertyHandlerContext {
55+
targets: self.targets,
56+
is_important: false,
57+
supports: Vec::new(),
58+
ltr: Vec::new(),
59+
rtl: Vec::new(),
60+
context,
61+
unused_symbols: self.unused_symbols
62+
}
63+
}
64+
5365
pub fn should_compile_logical(&self, feature: Feature) -> bool {
5466
// Don't convert logical properties in style attributes because
5567
// our fallbacks rely on extra rules to define --ltr and --rtl.

src/lib.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9525,6 +9525,39 @@ mod tests {
95259525
..Browsers::default()
95269526
},
95279527
);
9528+
9529+
nesting_test_with_targets(
9530+
r#"
9531+
.foo {
9532+
padding-inline-start: 3px;
9533+
9534+
.bar {
9535+
padding-inline-start: 5px;
9536+
}
9537+
}
9538+
"#,
9539+
indoc! {r#"
9540+
.foo:not(:lang(ae, ar, arc, bcc, bqi, ckb, dv, fa, glk, he, ku, mzn, nqo, pnb, ps, sd, ug, ur, yi)) {
9541+
padding-left: 3px;
9542+
}
9543+
9544+
.foo:lang(ae, ar, arc, bcc, bqi, ckb, dv, fa, glk, he, ku, mzn, nqo, pnb, ps, sd, ug, ur, yi) {
9545+
padding-right: 3px;
9546+
}
9547+
9548+
.foo .bar:not(:lang(ae, ar, arc, bcc, bqi, ckb, dv, fa, glk, he, ku, mzn, nqo, pnb, ps, sd, ug, ur, yi)) {
9549+
padding-left: 5px;
9550+
}
9551+
9552+
.foo .bar:lang(ae, ar, arc, bcc, bqi, ckb, dv, fa, glk, he, ku, mzn, nqo, pnb, ps, sd, ug, ur, yi) {
9553+
padding-right: 5px;
9554+
}
9555+
"#},
9556+
Browsers {
9557+
safari: Some(12 << 16),
9558+
..Browsers::default()
9559+
}.into(),
9560+
);
95289561
}
95299562

95309563
#[test]

src/rules/keyframes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ impl<'i> KeyframesRule<'i> {
119119
for keyframe in &mut self.keyframes {
120120
keyframe
121121
.declarations
122-
.minify(context.handler, context.important_handler, context.handler_context)
122+
.minify(context.handler, context.important_handler, &mut context.handler_context)
123123
}
124124

125125
context.handler_context.context = DeclarationContext::None;

src/rules/mod.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ use self::font_palette_values::FontPaletteValuesRule;
5959
use self::layer::{LayerBlockRule, LayerStatementRule};
6060
use self::property::PropertyRule;
6161
use crate::context::PropertyHandlerContext;
62-
use crate::declaration::DeclarationHandler;
62+
use crate::declaration::{DeclarationHandler, DeclarationBlock};
6363
use crate::dependencies::{Dependency, ImportDependency};
6464
use crate::error::{MinifyError, ParserError, PrinterError, PrinterErrorKind};
6565
use crate::parser::{
@@ -466,7 +466,7 @@ pub(crate) struct MinifyContext<'a, 'i> {
466466
pub targets: &'a Targets,
467467
pub handler: &'a mut DeclarationHandler<'i>,
468468
pub important_handler: &'a mut DeclarationHandler<'i>,
469-
pub handler_context: &'a mut PropertyHandlerContext<'i, 'a>,
469+
pub handler_context: PropertyHandlerContext<'i, 'a>,
470470
pub unused_symbols: &'a HashSet<String>,
471471
pub custom_media: Option<HashMap<CowArcStr<'i>, CustomMediaRule<'i>>>,
472472
pub css_modules: bool,
@@ -668,6 +668,24 @@ impl<'i, T: Clone> CssRuleList<'i, T> {
668668
.collect::<Vec<_>>();
669669

670670
context.handler_context.reset();
671+
672+
// If the rule has nested rules, and we have extra rules to insert such as for logical properties,
673+
// we need to split the rule in two so we can insert the extra rules in between the declarations from
674+
// the main rule and the nested rules.
675+
let nested_rule = if !style.rules.0.is_empty() && (!logical.is_empty() || !supports.is_empty() || !incompatible_rules.is_empty()) {
676+
let mut rules = CssRuleList(vec![]);
677+
std::mem::swap(&mut style.rules, &mut rules);
678+
Some(StyleRule {
679+
selectors: style.selectors.clone(),
680+
declarations: DeclarationBlock::default(),
681+
rules,
682+
vendor_prefix: style.vendor_prefix,
683+
loc: style.loc
684+
})
685+
} else {
686+
None
687+
};
688+
671689
if !merged && !style.is_empty() {
672690
let source_index = style.loc.source_index;
673691
let has_no_rules = style.rules.0.is_empty();
@@ -714,6 +732,11 @@ impl<'i, T: Clone> CssRuleList<'i, T> {
714732
}
715733
rules.extend(supports);
716734
}
735+
736+
if let Some(nested_rule) = nested_rule {
737+
rules.push(CssRule::Style(nested_rule));
738+
}
739+
717740
continue;
718741
}
719742
CssRule::CounterStyle(counter_style) => {
@@ -777,7 +800,7 @@ fn merge_style_rules<'i, T>(
777800
.extend(style.declarations.important_declarations.drain(..));
778801
last_style_rule
779802
.declarations
780-
.minify(context.handler, context.important_handler, context.handler_context);
803+
.minify(context.handler, context.important_handler, &mut context.handler_context);
781804
return true;
782805
} else if style.declarations == last_style_rule.declarations
783806
&& style.rules.0.is_empty()

src/rules/style.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,14 @@ impl<'i, T: Clone> StyleRule<'i, T> {
7171
context.handler_context.context = DeclarationContext::StyleRule;
7272
self
7373
.declarations
74-
.minify(context.handler, context.important_handler, context.handler_context);
74+
.minify(context.handler, context.important_handler, &mut context.handler_context);
7575
context.handler_context.context = DeclarationContext::None;
7676

7777
if !self.rules.0.is_empty() {
78+
let mut handler_context = context.handler_context.child(DeclarationContext::StyleRule);
79+
std::mem::swap(&mut context.handler_context, &mut handler_context);
7880
self.rules.minify(context, unused)?;
81+
context.handler_context = handler_context;
7982
if unused && self.rules.0.is_empty() {
8083
return Ok(true);
8184
}

src/stylesheet.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ where
188188

189189
/// Minify and transform the style sheet for the provided browser targets.
190190
pub fn minify(&mut self, options: MinifyOptions) -> Result<(), Error<MinifyErrorKind>> {
191-
let mut context = PropertyHandlerContext::new(options.targets, &options.unused_symbols);
191+
let context = PropertyHandlerContext::new(options.targets, &options.unused_symbols);
192192
let mut handler = DeclarationHandler::default();
193193
let mut important_handler = DeclarationHandler::default();
194194

@@ -212,7 +212,7 @@ where
212212
targets: &options.targets,
213213
handler: &mut handler,
214214
important_handler: &mut important_handler,
215-
handler_context: &mut context,
215+
handler_context: context,
216216
unused_symbols: &options.unused_symbols,
217217
custom_media,
218218
css_modules: self.options.css_modules.is_some(),

0 commit comments

Comments
 (0)