1// TODO: it'd be great to merge it with the other canReorder functionality
2
3var rulesOverlap = require('./rules-overlap');
4var specificitiesOverlap = require('./specificities-overlap');
5
6var FLEX_PROPERTIES = /align\-items|box\-align|box\-pack|flex|justify/;
7var BORDER_PROPERTIES = /^border\-(top|right|bottom|left|color|style|width|radius)/;
8
9function canReorder(left, right, cache) {
10  for (var i = right.length - 1; i >= 0; i--) {
11    for (var j = left.length - 1; j >= 0; j--) {
12      if (!canReorderSingle(left[j], right[i], cache))
13        return false;
14    }
15  }
16
17  return true;
18}
19
20function canReorderSingle(left, right, cache) {
21  var leftName = left[0];
22  var leftValue = left[1];
23  var leftNameRoot = left[2];
24  var leftSelector = left[5];
25  var leftInSpecificSelector = left[6];
26  var rightName = right[0];
27  var rightValue = right[1];
28  var rightNameRoot = right[2];
29  var rightSelector = right[5];
30  var rightInSpecificSelector = right[6];
31
32  if (leftName == 'font' && rightName == 'line-height' || rightName == 'font' && leftName == 'line-height')
33    return false;
34  if (FLEX_PROPERTIES.test(leftName) && FLEX_PROPERTIES.test(rightName))
35    return false;
36  if (leftNameRoot == rightNameRoot && unprefixed(leftName) == unprefixed(rightName) && (vendorPrefixed(leftName) ^ vendorPrefixed(rightName)))
37    return false;
38  if (leftNameRoot == 'border' && BORDER_PROPERTIES.test(rightNameRoot) && (leftName == 'border' || leftName == rightNameRoot || (leftValue != rightValue && sameBorderComponent(leftName, rightName))))
39    return false;
40  if (rightNameRoot == 'border' && BORDER_PROPERTIES.test(leftNameRoot) && (rightName == 'border' || rightName == leftNameRoot || (leftValue != rightValue && sameBorderComponent(leftName, rightName))))
41    return false;
42  if (leftNameRoot == 'border' && rightNameRoot == 'border' && leftName != rightName && (isSideBorder(leftName) && isStyleBorder(rightName) || isStyleBorder(leftName) && isSideBorder(rightName)))
43    return false;
44  if (leftNameRoot != rightNameRoot)
45    return true;
46  if (leftName == rightName && leftNameRoot == rightNameRoot && (leftValue == rightValue || withDifferentVendorPrefix(leftValue, rightValue)))
47    return true;
48  if (leftName != rightName && leftNameRoot == rightNameRoot && leftName != leftNameRoot && rightName != rightNameRoot)
49    return true;
50  if (leftName != rightName && leftNameRoot == rightNameRoot && leftValue == rightValue)
51    return true;
52  if (rightInSpecificSelector && leftInSpecificSelector && !inheritable(leftNameRoot) && !inheritable(rightNameRoot) && !rulesOverlap(rightSelector, leftSelector, false))
53    return true;
54  if (!specificitiesOverlap(leftSelector, rightSelector, cache))
55    return true;
56
57  return false;
58}
59
60function vendorPrefixed(name) {
61  return /^\-(?:moz|webkit|ms|o)\-/.test(name);
62}
63
64function unprefixed(name) {
65  return name.replace(/^\-(?:moz|webkit|ms|o)\-/, '');
66}
67
68function sameBorderComponent(name1, name2) {
69  return name1.split('-').pop() == name2.split('-').pop();
70}
71
72function isSideBorder(name) {
73  return name == 'border-top' || name == 'border-right' || name == 'border-bottom' || name == 'border-left';
74}
75
76function isStyleBorder(name) {
77  return name == 'border-color' || name == 'border-style' || name == 'border-width';
78}
79
80function withDifferentVendorPrefix(value1, value2) {
81  return vendorPrefixed(value1) && vendorPrefixed(value2) && value1.split('-')[1] != value2.split('-')[2];
82}
83
84function inheritable(name) {
85  // According to http://www.w3.org/TR/CSS21/propidx.html
86  // Others will be catched by other, preceeding rules
87  return name == 'font' || name == 'line-height' || name == 'list-style';
88}
89
90module.exports = {
91  canReorder: canReorder,
92  canReorderSingle: canReorderSingle
93};
94