Blame view

node_modules/csso/lib/compressor/restructure/utils.js 3.84 KB
aaac7fed   liuqimichale   add
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
  var hasOwnProperty = Object.prototype.hasOwnProperty;
  
  function isEqualLists(a, b) {
      var cursor1 = a.head;
      var cursor2 = b.head;
  
      while (cursor1 !== null && cursor2 !== null && cursor1.data.id === cursor2.data.id) {
          cursor1 = cursor1.next;
          cursor2 = cursor2.next;
      }
  
      return cursor1 === null && cursor2 === null;
  }
  
  function isEqualDeclarations(a, b) {
      var cursor1 = a.head;
      var cursor2 = b.head;
  
      while (cursor1 !== null && cursor2 !== null && cursor1.data.id === cursor2.data.id) {
          cursor1 = cursor1.next;
          cursor2 = cursor2.next;
      }
  
      return cursor1 === null && cursor2 === null;
  }
  
  function compareDeclarations(declarations1, declarations2) {
      var result = {
          eq: [],
          ne1: [],
          ne2: [],
          ne2overrided: []
      };
  
      var fingerprints = Object.create(null);
      var declarations2hash = Object.create(null);
  
      for (var cursor = declarations2.head; cursor; cursor = cursor.next)  {
          declarations2hash[cursor.data.id] = true;
      }
  
      for (var cursor = declarations1.head; cursor; cursor = cursor.next)  {
          var data = cursor.data;
  
          if (data.fingerprint) {
              fingerprints[data.fingerprint] = data.value.important;
          }
  
          if (declarations2hash[data.id]) {
              declarations2hash[data.id] = false;
              result.eq.push(data);
          } else {
              result.ne1.push(data);
          }
      }
  
      for (var cursor = declarations2.head; cursor; cursor = cursor.next)  {
          var data = cursor.data;
  
          if (declarations2hash[data.id]) {
              // if declarations1 has overriding declaration, this is not a difference
              // but take in account !important - prev should be equal or greater than follow
              if (hasOwnProperty.call(fingerprints, data.fingerprint) &&
                  Number(fingerprints[data.fingerprint]) >= Number(data.value.important)) {
                  result.ne2overrided.push(data);
              } else {
                  result.ne2.push(data);
              }
          }
      }
  
      return result;
  }
  
  function addSelectors(dest, source) {
      source.each(function(sourceData) {
          var newStr = sourceData.id;
          var cursor = dest.head;
  
          while (cursor) {
              var nextStr = cursor.data.id;
  
              if (nextStr === newStr) {
                  return;
              }
  
              if (nextStr > newStr) {
                  break;
              }
  
              cursor = cursor.next;
          }
  
          dest.insert(dest.createItem(sourceData), cursor);
      });
  
      return dest;
  }
  
  // check if simpleselectors has no equal specificity and element selector
  function hasSimilarSelectors(selectors1, selectors2) {
      return selectors1.some(function(a) {
          return selectors2.some(function(b) {
              return a.compareMarker === b.compareMarker;
          });
      });
  }
  
  // test node can't to be skipped
  function unsafeToSkipNode(node) {
      switch (node.type) {
          case 'Ruleset':
              // unsafe skip ruleset with selector similarities
              return hasSimilarSelectors(node.selector.selectors, this);
  
          case 'Atrule':
              // can skip at-rules with blocks
              if (node.block) {
                  // non-stylesheet blocks are safe to skip since have no selectors
                  if (node.block.type !== 'StyleSheet') {
                      return false;
                  }
  
                  // unsafe skip at-rule if block contains something unsafe to skip
                  return node.block.rules.some(unsafeToSkipNode, this);
              }
              break;
      }
  
      // unsafe by default
      return true;
  }
  
  module.exports = {
      isEqualLists: isEqualLists,
      isEqualDeclarations: isEqualDeclarations,
      compareDeclarations: compareDeclarations,
      addSelectors: addSelectors,
      hasSimilarSelectors: hasSimilarSelectors,
      unsafeToSkipNode: unsafeToSkipNode
  };