'use strict'; exports.__esModule = true; var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _postcss = require('postcss'); var _stylehacks = require('stylehacks'); var _objectAssign = require('object-assign'); var _objectAssign2 = _interopRequireDefault(_objectAssign); var _clone = require('../clone'); var _clone2 = _interopRequireDefault(_clone); var _insertCloned = require('../insertCloned'); var _insertCloned2 = _interopRequireDefault(_insertCloned); var _parseTrbl = require('../parseTrbl'); var _parseTrbl2 = _interopRequireDefault(_parseTrbl); var _hasAllProps = require('../hasAllProps'); var _hasAllProps2 = _interopRequireDefault(_hasAllProps); var _getDecls = require('../getDecls'); var _getDecls2 = _interopRequireDefault(_getDecls); var _getRules = require('../getRules'); var _getRules2 = _interopRequireDefault(_getRules); var _getValue = require('../getValue'); var _getValue2 = _interopRequireDefault(_getValue); var _mergeRules = require('../mergeRules'); var _mergeRules2 = _interopRequireDefault(_mergeRules); var _minifyTrbl = require('../minifyTrbl'); var _minifyTrbl2 = _interopRequireDefault(_minifyTrbl); var _canMerge = require('../canMerge'); var _canMerge2 = _interopRequireDefault(_canMerge); var _remove = require('../remove'); var _remove2 = _interopRequireDefault(_remove); var _trbl = require('../trbl'); var _trbl2 = _interopRequireDefault(_trbl); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var wsc = ['width', 'style', 'color']; var defaults = ['medium', 'none', 'currentColor']; function borderProperty() { for (var _len = arguments.length, parts = Array(_len), _key = 0; _key < _len; _key++) { parts[_key] = arguments[_key]; } return 'border-' + parts.join('-'); } function mapBorderProperty(value) { return borderProperty(value); } var directions = _trbl2.default.map(mapBorderProperty); var properties = wsc.map(mapBorderProperty); var directionalProperties = directions.reduce(function (prev, curr) { return prev.concat(wsc.map(function (prop) { return curr + '-' + prop; })); }, []); var precedence = [['border'], directions.concat(properties), directionalProperties]; var allProperties = precedence.reduce(function (a, b) { return a.concat(b); }); function getLevel(prop) { for (var i = 0; i < precedence.length; i++) { if (!!~precedence[i].indexOf(prop)) { return i; } } } function getColorValue(decl) { var values = _postcss.list.space(decl.value); if (decl.prop === 'border') { return values[2]; } if (!!~directions.indexOf(decl.prop)) { return values[2]; } if (decl.prop.substr(-5) === 'color') { return decl.value; } return null; } function mergeRedundant(_ref) { var values = _ref.values, nextValues = _ref.nextValues, decl = _ref.decl, nextDecl = _ref.nextDecl, index = _ref.index, position = _ref.position, prop = _ref.prop; if ((0, _stylehacks.detect)(decl) || (0, _stylehacks.detect)(nextDecl)) { return; } var props = (0, _parseTrbl2.default)(values[position]); props[index] = nextValues[position]; values.splice(position, 1); var borderValue = values.join(' '); var propertyValue = (0, _minifyTrbl2.default)(props); var origLength = (decl.value + nextDecl.prop + nextDecl.value).length; var newLength = borderValue.length + 12 + propertyValue.length; if (newLength < origLength) { decl.value = borderValue; nextDecl.prop = prop; nextDecl.value = propertyValue; } } function isCloseEnough(mapped) { return mapped[0] === mapped[1] && mapped[1] === mapped[2] || mapped[1] === mapped[2] && mapped[2] === mapped[3] || mapped[2] === mapped[3] && mapped[3] === mapped[0] || mapped[3] === mapped[0] && mapped[0] === mapped[1]; } function getDistinctShorthands(mapped) { return mapped.reduce(function (a, b) { a = Array.isArray(a) ? a : [a]; if (!~a.indexOf(b)) { a.push(b); } return a; }); } function explode(rule) { rule.walkDecls(/^border/, function (decl) { // Don't explode inherit values as they cannot be merged together if (decl.value === 'inherit') { return; } if ((0, _stylehacks.detect)(decl)) { return; } var prop = decl.prop; // border -> border-trbl if (prop === 'border') { directions.forEach(function (direction) { (0, _insertCloned2.default)(decl.parent, decl, { prop: direction }); }); return decl.remove(); } // border-trbl -> border-trbl-wsc if (directions.some(function (direction) { return prop === direction; })) { var values = _postcss.list.space(decl.value); wsc.forEach(function (d, i) { (0, _insertCloned2.default)(decl.parent, decl, { prop: prop + '-' + d, value: values[i] || defaults[i] }); }); return decl.remove(); } // border-wsc -> border-trbl-wsc wsc.some(function (style) { if (prop !== borderProperty(style)) { return false; } (0, _parseTrbl2.default)(decl.value).forEach(function (value, i) { (0, _insertCloned2.default)(decl.parent, decl, { prop: borderProperty(_trbl2.default[i], style), value: value }); }); return decl.remove(); }); }); } function merge(rule) { // border-trbl-wsc -> border-trbl _trbl2.default.forEach(function (direction) { var prop = borderProperty(direction); (0, _mergeRules2.default)(rule, wsc.map(function (style) { return borderProperty(direction, style); }), function (rules, lastNode) { if (_canMerge2.default.apply(undefined, rules) && !rules.some(_stylehacks.detect)) { (0, _insertCloned2.default)(lastNode.parent, lastNode, { prop: prop, value: rules.map(_getValue2.default).join(' ') }); rules.forEach(_remove2.default); return true; } }); }); // border-trbl-wsc -> border-wsc wsc.forEach(function (style) { var prop = borderProperty(style); (0, _mergeRules2.default)(rule, _trbl2.default.map(function (direction) { return borderProperty(direction, style); }), function (rules, lastNode) { if (!rules.some(_stylehacks.detect)) { (0, _insertCloned2.default)(lastNode.parent, lastNode, { prop: prop, value: (0, _minifyTrbl2.default)(rules.map(_getValue2.default).join(' ')) }); rules.forEach(_remove2.default); return true; } }); }); // border-trbl -> border-wsc (0, _mergeRules2.default)(rule, directions, function (rules, lastNode) { if (rules.some(_stylehacks.detect)) { return; } wsc.forEach(function (d, i) { (0, _insertCloned2.default)(lastNode.parent, lastNode, { prop: borderProperty(d), value: (0, _minifyTrbl2.default)(rules.map(function (node) { return _postcss.list.space(node.value)[i]; })) }); }); rules.forEach(_remove2.default); return true; }); // border-wsc -> border // border-wsc -> border + border-color // border-wsc -> border + border-dir (0, _mergeRules2.default)(rule, properties, function (rules, lastNode) { if (rules.some(_stylehacks.detect)) { return; } var width = rules[0], style = rules[1], color = rules[2]; var values = rules.map(function (node) { return (0, _parseTrbl2.default)(node.value); }); var mapped = [0, 1, 2, 3].map(function (i) { return [values[0][i], values[1][i], values[2][i]].join(' '); }); var reduced = getDistinctShorthands(mapped); if (isCloseEnough(mapped) && _canMerge2.default.apply(undefined, rules)) { var first = mapped.indexOf(reduced[0]) !== mapped.lastIndexOf(reduced[0]); var border = (0, _insertCloned2.default)(lastNode.parent, lastNode, { prop: 'border', value: first ? reduced[0] : reduced[1] }); if (reduced[1]) { var value = first ? reduced[1] : reduced[0]; var prop = borderProperty(_trbl2.default[mapped.indexOf(value)]); rule.insertAfter(border, (0, _objectAssign2.default)((0, _clone2.default)(lastNode), { prop: prop, value: value })); } rules.forEach(_remove2.default); return true; } else if (reduced.length === 1) { rule.insertBefore(color, (0, _objectAssign2.default)((0, _clone2.default)(lastNode), { prop: 'border', value: [width, style].map(_getValue2.default).join(' ') })); rules.filter(function (node) { return node.prop !== properties[2]; }).forEach(_remove2.default); return true; } }); // border-wsc -> border + border-trbl (0, _mergeRules2.default)(rule, properties, function (rules, lastNode) { if (rules.some(_stylehacks.detect)) { return; } var values = rules.map(function (node) { return (0, _parseTrbl2.default)(node.value); }); var mapped = [0, 1, 2, 3].map(function (i) { return [values[0][i], values[1][i], values[2][i]].join(' '); }); var reduced = getDistinctShorthands(mapped); var none = 'none none currentColor'; if (reduced.length === 2 && reduced[0] === none || reduced[1] === none) { var noOfNones = mapped.filter(function (value) { return value === none; }).length; rule.insertBefore(lastNode, (0, _objectAssign2.default)((0, _clone2.default)(lastNode), { prop: 'border', value: noOfNones > 2 ? 'none' : mapped.filter(function (value) { return value !== none; })[0] })); directions.forEach(function (dir, i) { if (noOfNones > 2 && mapped[i] !== none) { rule.insertBefore(lastNode, (0, _objectAssign2.default)((0, _clone2.default)(lastNode), { prop: dir, value: mapped[i] })); } if (noOfNones <= 2 && mapped[i] === none) { rule.insertBefore(lastNode, (0, _objectAssign2.default)((0, _clone2.default)(lastNode), { prop: dir, value: 'none' })); } }); rules.forEach(_remove2.default); return true; } }); // optimize border-trbl var decls = (0, _getDecls2.default)(rule, directions); var _loop = function _loop() { var lastNode = decls[decls.length - 1]; wsc.forEach(function (d, i) { var names = directions.filter(function (name) { return name !== lastNode.prop; }).map(function (name) { return name + '-' + d; }); var props = rule.nodes.filter(function (node) { return node.prop && ~names.indexOf(node.prop) && node.important === lastNode.important; }); var rules = (0, _getRules2.default)(props, names); if (_hasAllProps2.default.apply(undefined, [rules].concat(names)) && !rules.some(_stylehacks.detect)) { var values = rules.map(function (node) { return node ? node.value : null; }); var filteredValues = values.filter(Boolean); var lastNodeValue = _postcss.list.space(lastNode.value)[i]; values[directions.indexOf(lastNode.prop)] = lastNodeValue; var value = (0, _minifyTrbl2.default)(values.join(' ')); if (filteredValues[0] === filteredValues[1] && filteredValues[1] === filteredValues[2]) { value = filteredValues[0]; } var refNode = props[props.length - 1]; if (value === lastNodeValue) { refNode = lastNode; var valueArray = _postcss.list.space(lastNode.value); valueArray.splice(i, 1); lastNode.value = valueArray.join(' '); } (0, _insertCloned2.default)(refNode.parent, refNode, { prop: borderProperty(d), value: value }); decls = decls.filter(function (node) { return !~rules.indexOf(node); }); rules.forEach(_remove2.default); } }); decls = decls.filter(function (node) { return node !== lastNode; }); }; while (decls.length) { _loop(); } rule.walkDecls('border', function (decl) { var nextDecl = decl.next(); if (!nextDecl || nextDecl.type !== 'decl') { return; } var index = directions.indexOf(nextDecl.prop); if (!~index) { return; } var values = _postcss.list.space(decl.value); var nextValues = _postcss.list.space(nextDecl.value); var config = { values: values, nextValues: nextValues, decl: decl, nextDecl: nextDecl, index: index }; if (values[0] === nextValues[0] && values[2] === nextValues[2]) { return mergeRedundant(_extends({}, config, { position: 1, prop: 'border-style' })); } if (values[1] === nextValues[1] && values[2] === nextValues[2]) { return mergeRedundant(_extends({}, config, { position: 0, prop: 'border-width' })); } if (values[0] === nextValues[0] && values[1] === nextValues[1] && values[2] && nextValues[2]) { return mergeRedundant(_extends({}, config, { position: 2, prop: 'border-color' })); } }); // clean-up values rule.walkDecls(/^border($|-(top|right|bottom|left))/, function (decl) { var value = [].concat(_postcss.list.space(decl.value), ['']).reduceRight(function (prev, cur, i) { if (prev === '' && cur === defaults[i]) { return prev; } return cur + ' ' + prev; }).trim() || defaults[0]; decl.value = (0, _minifyTrbl2.default)(value); }); // clean-up rules decls = (0, _getDecls2.default)(rule, allProperties); var _loop2 = function _loop2() { var lastNode = decls[decls.length - 1]; // remove properties of lower precedence var lesser = decls.filter(function (node) { return !(0, _stylehacks.detect)(lastNode) && !(0, _stylehacks.detect)(node) && node !== lastNode && node.important === lastNode.important && getLevel(node.prop) > getLevel(lastNode.prop); }); lesser.forEach(_remove2.default); decls = decls.filter(function (node) { return !~lesser.indexOf(node); }); // get duplicate properties var duplicates = decls.filter(function (node) { return !(0, _stylehacks.detect)(lastNode) && !(0, _stylehacks.detect)(node) && node !== lastNode && node.important === lastNode.important && node.prop === lastNode.prop; }); if (duplicates.length) { if (/hsla|rgba/.test(getColorValue(lastNode))) { var preserve = duplicates.filter(function (node) { return !/hsla|rgba/.test(getColorValue(node)); }).pop(); duplicates = duplicates.filter(function (node) { return node !== preserve; }); } duplicates.forEach(_remove2.default); } decls = decls.filter(function (node) { return node !== lastNode && !~duplicates.indexOf(node); }); }; while (decls.length) { _loop2(); } } exports.default = { explode: explode, merge: merge }; module.exports = exports['default'];