Skip to content

Commit 46cca00

Browse files
committed
Improve border shorthand minification
Fixes parcel-bundler#35
1 parent 718efba commit 46cca00

File tree

2 files changed

+262
-41
lines changed

2 files changed

+262
-41
lines changed

src/lib.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,160 @@ mod tests {
423423
"#
424424
});
425425

426+
test(r#"
427+
.foo {
428+
border: 1px solid black;
429+
border-width: 1px 1px 0 0;
430+
}
431+
"#, indoc! {r#"
432+
.foo {
433+
border: 1px solid #000;
434+
border-width: 1px 1px 0 0;
435+
}
436+
"#});
437+
438+
test(r#"
439+
.foo {
440+
border-top: 1px solid black;
441+
border-bottom: 1px solid black;
442+
border-left: 2px solid black;
443+
border-right: 2px solid black;
444+
}
445+
"#, indoc! {r#"
446+
.foo {
447+
border: 1px solid #000;
448+
border-width: 1px 2px;
449+
}
450+
"#});
451+
452+
test(r#"
453+
.foo {
454+
border-top: 1px solid black;
455+
border-bottom: 1px solid black;
456+
border-left: 2px solid black;
457+
border-right: 1px solid black;
458+
}
459+
"#, indoc! {r#"
460+
.foo {
461+
border: 1px solid #000;
462+
border-left-width: 2px;
463+
}
464+
"#});
465+
466+
test(r#"
467+
.foo {
468+
border-top: 1px solid black;
469+
border-bottom: 1px solid black;
470+
border-left: 1px solid red;
471+
border-right: 1px solid red;
472+
}
473+
"#, indoc! {r#"
474+
.foo {
475+
border: 1px solid #000;
476+
border-color: #000 red;
477+
}
478+
"#});
479+
480+
test(r#"
481+
.foo {
482+
border-block-start: 1px solid black;
483+
border-block-end: 1px solid black;
484+
border-inline-start: 1px solid red;
485+
border-inline-end: 1px solid red;
486+
}
487+
"#, indoc! {r#"
488+
.foo {
489+
border: 1px solid #000;
490+
border-inline-color: red;
491+
}
492+
"#});
493+
494+
test(r#"
495+
.foo {
496+
border-block-start: 1px solid black;
497+
border-block-end: 1px solid black;
498+
border-inline-start: 2px solid black;
499+
border-inline-end: 2px solid black;
500+
}
501+
"#, indoc! {r#"
502+
.foo {
503+
border: 1px solid #000;
504+
border-inline-width: 2px;
505+
}
506+
"#});
507+
508+
test(r#"
509+
.foo {
510+
border-block-start: 1px solid black;
511+
border-block-end: 1px solid black;
512+
border-inline-start: 2px solid red;
513+
border-inline-end: 2px solid red;
514+
}
515+
"#, indoc! {r#"
516+
.foo {
517+
border: 1px solid #000;
518+
border-inline: 2px solid red;
519+
}
520+
"#});
521+
522+
test(r#"
523+
.foo {
524+
border-block-start: 1px solid black;
525+
border-block-end: 1px solid black;
526+
border-inline-start: 2px solid red;
527+
border-inline-end: 3px solid red;
528+
}
529+
"#, indoc! {r#"
530+
.foo {
531+
border: 1px solid #000;
532+
border-inline-start: 2px solid red;
533+
border-inline-end: 3px solid red;
534+
}
535+
"#});
536+
537+
test(r#"
538+
.foo {
539+
border-block-start: 2px solid black;
540+
border-block-end: 1px solid black;
541+
border-inline-start: 2px solid red;
542+
border-inline-end: 2px solid red;
543+
}
544+
"#, indoc! {r#"
545+
.foo {
546+
border: 2px solid red;
547+
border-block-start-color: #000;
548+
border-block-end: 1px solid #000;
549+
}
550+
"#});
551+
552+
test(r#"
553+
.foo {
554+
border-block-start: 2px solid red;
555+
border-block-end: 1px solid red;
556+
border-inline-start: 2px solid red;
557+
border-inline-end: 2px solid red;
558+
}
559+
"#, indoc! {r#"
560+
.foo {
561+
border: 2px solid red;
562+
border-block-end-width: 1px;
563+
}
564+
"#});
565+
566+
test(r#"
567+
.foo {
568+
border-block-start: 2px solid red;
569+
border-block-end: 2px solid red;
570+
border-inline-start: 2px solid red;
571+
border-inline-end: 1px solid red;
572+
}
573+
"#, indoc! {r#"
574+
.foo {
575+
border: 2px solid red;
576+
border-inline-end-width: 1px;
577+
}
578+
"#});
579+
426580
prefix_test(r#"
427581
.foo {
428582
border-block: 2px solid red;

src/properties/border.rs

Lines changed: 108 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,34 @@ impl<'i> BorderHandler<'i> {
600600
$inline_end: expr,
601601
$is_logical: expr
602602
) => {
603+
macro_rules! shorthand {
604+
($prop: ident, $key: ident) => {{
605+
let has_prop = $block_start.$key.is_some() && $block_end.$key.is_some() && $inline_start.$key.is_some() && $inline_end.$key.is_some();
606+
if has_prop {
607+
if !$is_logical || ($block_start.$key == $block_end.$key && $block_end.$key == $inline_start.$key && $inline_start.$key == $inline_end.$key) {
608+
let rect = Rect::new(
609+
std::mem::take(&mut $block_start.$key).unwrap(),
610+
std::mem::take(&mut $inline_end.$key).unwrap(),
611+
std::mem::take(&mut $block_end.$key).unwrap(),
612+
std::mem::take(&mut $inline_start.$key).unwrap()
613+
);
614+
prop!($prop => rect);
615+
}
616+
}
617+
}};
618+
}
619+
620+
macro_rules! logical_shorthand {
621+
($prop: ident, $key: ident, $start: expr, $end: expr) => {{
622+
let has_prop = $start.$key.is_some() && $start.$key == $end.$key;
623+
if has_prop {
624+
prop!($prop => std::mem::take(&mut $start.$key).unwrap());
625+
$end.$key = None;
626+
}
627+
has_prop
628+
}};
629+
}
630+
603631
if $block_start.is_valid() && $block_end.is_valid() && $inline_start.is_valid() && $inline_end.is_valid() {
604632
let top_eq_bottom = $block_start == $block_end;
605633
let left_eq_right = $inline_start == $inline_end;
@@ -608,6 +636,34 @@ impl<'i> BorderHandler<'i> {
608636
let bottom_eq_left = $block_end == $inline_start;
609637
let bottom_eq_right = $block_end == $inline_end;
610638

639+
macro_rules! is_eq {
640+
($key: ident) => {
641+
$block_start.$key == $block_end.$key &&
642+
$inline_start.$key == $inline_end.$key &&
643+
$inline_start.$key == $block_start.$key
644+
};
645+
}
646+
647+
macro_rules! prop_diff {
648+
($border: expr, $fallback: expr, $border_fallback: literal) => {
649+
if !$is_logical && is_eq!(color) && is_eq!(style) {
650+
dest.push(Property::Border($border.to_border()));
651+
shorthand!(BorderWidth, width);
652+
} else if !$is_logical && is_eq!(width) && is_eq!(style) {
653+
dest.push(Property::Border($border.to_border()));
654+
shorthand!(BorderColor, color);
655+
} else if !$is_logical && is_eq!(width) && is_eq!(color) {
656+
dest.push(Property::Border($border.to_border()));
657+
shorthand!(BorderStyle, style);
658+
} else {
659+
if $border_fallback {
660+
dest.push(Property::Border($border.to_border()));
661+
}
662+
$fallback
663+
}
664+
};
665+
}
666+
611667
macro_rules! side_diff {
612668
($border: expr, $other: expr, $prop: ident, $width: ident, $style: ident, $color: ident) => {
613669
let eq_width = $border.width == $other.width;
@@ -643,52 +699,63 @@ impl<'i> BorderHandler<'i> {
643699
dest.push(Property::Border($inline_start.to_border()));
644700
side_diff!($inline_start, $block_end, $block_end_prop, $block_end_width, $block_end_style, $block_end_color);
645701
} else if top_eq_bottom {
646-
dest.push(Property::Border($block_start.to_border()));
647-
side_diff!($block_start, $inline_start, $inline_start_prop, $inline_start_width, $inline_start_style, $inline_start_color);
648-
side_diff!($block_start, $inline_end, $inline_end_prop, $inline_end_width, $inline_end_style, $inline_end_color);
649-
} else if left_eq_right {
650-
dest.push(Property::Border($inline_start.to_border()));
651-
side_diff!($inline_start, $block_start, $block_start_prop, $block_start_width, $block_start_style, $block_start_color);
652-
side_diff!($inline_start, $block_end, $block_end_prop, $block_end_width, $block_end_style, $block_end_color);
653-
} else if bottom_eq_right {
654-
dest.push(Property::Border($block_end.to_border()));
655-
side_diff!($block_end, $block_start, $block_start_prop, $block_start_width, $block_start_style, $block_start_color);
656-
side_diff!($block_end, $inline_start, $inline_start_prop, $inline_start_width, $inline_start_style, $inline_start_color);
657-
} else {
658-
prop!($block_start_prop => $block_start.to_border());
659-
prop!($block_end_prop => $block_end.to_border());
660-
prop!($inline_start_prop => $inline_start.to_border());
661-
prop!($inline_end_prop => $inline_end.to_border());
662-
}
663-
} else {
664-
macro_rules! shorthand {
665-
($prop: ident, $key: ident) => {{
666-
let has_prop = $block_start.$key.is_some() && $block_end.$key.is_some() && $inline_start.$key.is_some() && $inline_end.$key.is_some();
667-
if has_prop {
668-
if !$is_logical || ($block_start.$key == $block_end.$key && $block_end.$key == $inline_start.$key && $inline_start.$key == $inline_end.$key) {
669-
let rect = Rect::new(
670-
std::mem::take(&mut $block_start.$key).unwrap(),
671-
std::mem::take(&mut $inline_end.$key).unwrap(),
672-
std::mem::take(&mut $block_end.$key).unwrap(),
673-
std::mem::take(&mut $inline_start.$key).unwrap()
674-
);
675-
prop!($prop => rect);
702+
prop_diff!($block_start, {
703+
// Try to use border-inline shorthands for the opposide direction if possible.
704+
let mut handled = false;
705+
if $is_logical {
706+
let mut diff = 0;
707+
if $inline_start.width != $block_start.width || $inline_end.width != $block_start.width {
708+
diff += 1;
709+
}
710+
if $inline_start.style != $block_start.style || $inline_end.style != $block_start.style {
711+
diff += 1;
712+
}
713+
if $inline_start.color != $block_start.color || $inline_end.color != $block_start.color {
714+
diff += 1;
715+
}
716+
717+
if diff == 1 {
718+
if $inline_start.width != $block_start.width && $inline_start.width == $inline_end.width {
719+
prop!(BorderInlineWidth => $inline_start.width.clone().unwrap());
720+
handled = true;
721+
} else if $inline_start.style != $block_start.style && $inline_start.style == $inline_end.style {
722+
prop!(BorderInlineStyle => $inline_start.style.clone().unwrap());
723+
handled = true;
724+
} else if $inline_start.color != $block_start.color && $inline_start.color == $inline_end.color {
725+
prop!(BorderInlineColor => $inline_start.color.clone().unwrap());
726+
handled = true;
727+
}
728+
} else if diff > 1 && $inline_start.width == $inline_end.width && $inline_start.style == $inline_end.style && $inline_start.color == $inline_end.color {
729+
prop!(BorderInline => $inline_start.to_border());
730+
handled = true;
676731
}
677732
}
678-
}};
679-
}
680733

681-
macro_rules! logical_shorthand {
682-
($prop: ident, $key: ident, $start: expr, $end: expr) => {{
683-
let has_prop = $start.$key.is_some() && $start.$key == $end.$key;
684-
if has_prop {
685-
prop!($prop => std::mem::take(&mut $start.$key).unwrap());
686-
$end.$key = None;
734+
if !handled {
735+
side_diff!($block_start, $inline_start, $inline_start_prop, $inline_start_width, $inline_start_style, $inline_start_color);
736+
side_diff!($block_start, $inline_end, $inline_end_prop, $inline_end_width, $inline_end_style, $inline_end_color);
687737
}
688-
has_prop
689-
}};
738+
}, true);
739+
} else if left_eq_right {
740+
prop_diff!($inline_start, {
741+
// We know already that top != bottom, so no need to try to use border-block.
742+
side_diff!($inline_start, $block_start, $block_start_prop, $block_start_width, $block_start_style, $block_start_color);
743+
side_diff!($inline_start, $block_end, $block_end_prop, $block_end_width, $block_end_style, $block_end_color);
744+
}, true);
745+
} else if bottom_eq_right {
746+
prop_diff!($block_end, {
747+
side_diff!($block_end, $block_start, $block_start_prop, $block_start_width, $block_start_style, $block_start_color);
748+
side_diff!($block_end, $inline_start, $inline_start_prop, $inline_start_width, $inline_start_style, $inline_start_color);
749+
}, true);
750+
} else {
751+
prop_diff!($block_start, {
752+
prop!($block_start_prop => $block_start.to_border());
753+
prop!($block_end_prop => $block_end.to_border());
754+
prop!($inline_start_prop => $inline_start.to_border());
755+
prop!($inline_end_prop => $inline_end.to_border());
756+
}, false);
690757
}
691-
758+
} else {
692759
shorthand!(BorderStyle, style);
693760
shorthand!(BorderWidth, width);
694761
shorthand!(BorderColor, color);

0 commit comments

Comments
 (0)