Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix ben-eb/cssnano/448 don't remove fallbacks for custom css properties #486

Merged
merged 6 commits into from Jun 15, 2018
65 changes: 65 additions & 0 deletions packages/cssnano/src/__tests__/postcss-merge-longhand.js
Expand Up @@ -154,3 +154,68 @@ test(
'h1{margin:10px 20px 30px 40px}',
'h1{margin:10px 20px 30px 40px}',
);

test(
'save fallbacks if after them goes custom css props',
processCss,
'h1{padding:1em;padding:var(--variable)}',
'h1{padding:1em;padding:var(--variable)}'
);

test(
'overwrite custom css props if after them goes same props',
processCss,
'h1{padding:var(--variable);padding:1em}',
'h1{padding:1em}'
);

test(
'overwrite custom css props if after them goes same props (2)',
processCss,
'h1{padding:var(--first);padding:var(--second)}',
'h1{padding:var(--second)}'
);

test(
'should not break unmergeable rules with custom props',
processCss,
'h1{padding:var(--variable)}',
'h1{padding:var(--variable)}'
);

test(
'shoudn\'t merge rule if it includes mixed values',
processCss,
'h1{padding-top:10px;padding-right:15px;padding-bottom:20px;padding-left:var(--variable)}',
'h1{padding-bottom:20px;padding-left:var(--variable);padding-right:15px;padding-top:10px}'
);


test(
'should merge rules with custom props',
processCss,
'h1{padding-top:var(--variable);padding-right:var(--variable);padding-bottom:var(--variable);padding-left:var(--variable)}',
'h1{padding:var(--variable)}'
);

test(
'should merge props and dont remove fallbacks',
processCss,
'h1{padding-top:10px;padding-right:15px;padding-bottom:20px;padding-left:25px;padding-top:var(--variable);padding-right:var(--variable);padding-bottom:var(--variable);padding-left:var(--variable)}',
'h1{padding:10px 15px 20px 25px;padding:var(--variable)}'
);


test(
'should merge props and overwrite',
processCss,
'h1{padding-top:var(--variable);padding-right:var(--variable);padding-bottom:var(--variable);padding-left:var(--variable);padding-top:10px;padding-right:15px;padding-bottom:20px;padding-left:25px}',
'h1{padding:10px 15px 20px 25px}'
);

test(
'should overwrite some props and save fallbacks',
processCss,
'h1{padding-top:10px;padding-right:var(--variable);padding-right:15px;padding-bottom:var(--variable);padding-bottom:20px;padding-left:25px;padding-top:var(--variable);padding-left:var(--variable)}',
'h1{padding:10px 15px 20px 25px;padding-left:var(--variable);padding-top:var(--variable)}'
);
22 changes: 22 additions & 0 deletions packages/postcss-merge-longhand/src/__tests__/borders.js
Expand Up @@ -294,3 +294,25 @@ test(
':root{--my-border-width:var(--my-border-width);--my-border-style:var(--my-border-style);--my-border-color:var(--my-border-color);}',
':root{--my-border-width:var(--my-border-width);--my-border-style:var(--my-border-style);--my-border-color:var(--my-border-color);}'
);


test(
'should overwrite some border-width props and save fallbacks',
processCss,
'h1{border-top-width:10px;border-right-width:var(--variable);border-right-width:15px;border-bottom-width:var(--variable);border-bottom-width:20px;border-left-width:25px;border-top-width:var(--variable);border-left-width:var(--variable)}',
'h1{border-width:10px 15px 20px 25px;border-top-width:var(--variable);border-left-width:var(--variable)}'
);

test(
'save fallbacks should border-style',
processCss,
'h1{border-style:dotted;border-style:var(--variable)}',
'h1{border-style:dotted;border-style:var(--variable)}'
);

test(
'save fallbacks should border-color',
processCss,
'h1{border-color:dotted;border-color:var(--variable)}',
'h1{border-color:dotted;border-color:var(--variable)}'
);
4 changes: 4 additions & 0 deletions packages/postcss-merge-longhand/src/__tests__/boxBase.js
Expand Up @@ -106,4 +106,8 @@ addTests({
message: 'should override shorthand property',
fixture: 'h1{box:10px;box-left:5px}',
expected: 'h1{box:10px 10px 10px 5px}',
}, {
message: 'should overwrite some box props and save fallbacks',
fixture: 'h1{box-top:10px;box-right:var(--variable);box-right:15px;box-bottom:var(--variable);box-bottom:20px;box-left:25px;box-top:var(--variable);box-left:var(--variable)}',
expected: 'h1{box:10px 15px 20px 25px;box-top:var(--variable);box-left:var(--variable)}',
});
7 changes: 7 additions & 0 deletions packages/postcss-merge-longhand/src/__tests__/columns.js
Expand Up @@ -66,3 +66,10 @@ test(
'section{h1{column-width:12em;column-count:auto}}',
'section{h1{columns:12em}}'
);

test(
'should save fallbacks for column-width if after goes custom css props',
processCss,
'h1{column-width:12em;column-width:var(--variable)}',
'h1{column-width:12em;column-width:var(--variable)}'
);
6 changes: 4 additions & 2 deletions packages/postcss-merge-longhand/src/lib/canMerge.js
@@ -1,11 +1,13 @@
import isCustomProp from './isCustomProp';

const important = node => node.important;
const unimportant = node => !node.important;
const hasInherit = node => ~node.value.indexOf('inherit');
const hasInitial = node => ~node.value.indexOf('initial');

export default (...props) => {
if (props.some(hasInherit) || props.some(hasInitial)) {
return props.every(hasInherit) || props.every(hasInitial);
if (props.some(hasInherit) || props.some(hasInitial) || props.some(isCustomProp)) {
return props.every(hasInherit) || props.every(hasInitial) || props.every(isCustomProp);
}
return props.every(unimportant) || props.every(important);
};
9 changes: 6 additions & 3 deletions packages/postcss-merge-longhand/src/lib/decl/borders.js
Expand Up @@ -11,6 +11,7 @@ import minifyTrbl from '../minifyTrbl';
import canMerge from '../canMerge';
import remove from '../remove';
import trbl from '../trbl';
import isCustomProp from '../isCustomProp';

const wsc = ['width', 'style', 'color'];
const defaults = ['medium', 'none', 'currentColor'];
Expand Down Expand Up @@ -172,7 +173,7 @@ function merge (rule) {
rule,
trbl.map(direction => borderProperty(direction, style)),
(rules, lastNode) => {
if (!rules.some(detect)) {
if (canMerge(...rules) && !rules.some(detect)) {
insertCloned(lastNode.parent, lastNode, {
prop,
value: minifyTrbl(rules.map(getValue).join(' ')),
Expand All @@ -183,7 +184,7 @@ function merge (rule) {
}
);
});

// border-trbl -> border-wsc
mergeRules(rule, directions, (rules, lastNode) => {
if (rules.some(detect)) {
Expand Down Expand Up @@ -408,7 +409,9 @@ function merge (rule) {
!detect(node) &&
node !== lastNode &&
node.important === lastNode.important &&
node.prop === lastNode.prop);
node.prop === lastNode.prop &&
!(!isCustomProp(node) && isCustomProp(lastNode))
);

if (duplicates.length) {
if (/hsla|rgba/.test(getColorValue(lastNode))) {
Expand Down
8 changes: 5 additions & 3 deletions packages/postcss-merge-longhand/src/lib/decl/boxBase.js
Expand Up @@ -8,6 +8,7 @@ import mergeRules from '../mergeRules';
import mergeValues from '../mergeValues';
import remove from '../remove';
import trbl from '../trbl';
import isCustomProp from '../isCustomProp';

export default prop => {
const properties = trbl.map(direction => `${prop}-${direction}`);
Expand All @@ -16,7 +17,7 @@ export default prop => {
let decls = getDecls(rule, [prop].concat(properties));
while (decls.length) {
const lastNode = decls[decls.length - 1];

// remove properties of lower precedence
const lesser = decls.filter(node =>
!detect(lastNode) &&
Expand All @@ -34,8 +35,9 @@ export default prop => {
!detect(node) &&
node !== lastNode &&
node.important === lastNode.important &&
node.prop === lastNode.prop);

node.prop === lastNode.prop &&
!(!isCustomProp(node) && isCustomProp(lastNode))
);
duplicates.forEach(remove);
decls = decls.filter(node => node !== lastNode && !~duplicates.indexOf(node));
}
Expand Down
5 changes: 4 additions & 1 deletion packages/postcss-merge-longhand/src/lib/decl/columns.js
Expand Up @@ -7,6 +7,7 @@ import getValue from '../getValue';
import mergeRules from '../mergeRules';
import insertCloned from '../insertCloned';
import remove from '../remove';
import isCustomProp from '../isCustomProp';

const properties = ['column-width', 'column-count'];
const auto = 'auto';
Expand Down Expand Up @@ -84,7 +85,9 @@ function cleanup (rule) {
!detect(node) &&
node !== lastNode &&
node.important === lastNode.important &&
node.prop === lastNode.prop);
node.prop === lastNode.prop &&
!(!isCustomProp(node) && isCustomProp(lastNode))
);

duplicates.forEach(remove);
decls = decls.filter(node => node !== lastNode && !~duplicates.indexOf(node));
Expand Down
2 changes: 2 additions & 0 deletions packages/postcss-merge-longhand/src/lib/isCustomProp.js
@@ -0,0 +1,2 @@
export default node =>
~node.value.search(/var(\s+\(|\()(\s+--|--)/i);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be simplified a bit. E.g.:

~node.value.search(/var\s*\(\s*--/i);

Last nitpick, I promise!

5 changes: 2 additions & 3 deletions packages/postcss-merge-longhand/src/lib/mergeRules.js
Expand Up @@ -8,12 +8,11 @@ export default function mergeRules (rule, properties, callback) {
const last = decls[decls.length - 1];
const props = decls.filter(node => node.important === last.important);
const rules = getRules(props, properties);

if (hasAllProps(rules, ...properties)) {
if (callback(rules, last, props)) {
decls = decls.filter(node => !~rules.indexOf(node));
decls = decls.filter(node => !~rules.indexOf(node));
}
}
}
decls = decls.filter(node => node !== last);
}
}