Blame view

node_modules/clean-css/lib/optimizer/level-2/merge-non-adjacent-by-body.js 2.86 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
  var isMergeable = require('./is-mergeable');
  
  var sortSelectors = require('../level-1/sort-selectors');
  var tidyRules = require('../level-1/tidy-rules');
  
  var OptimizationLevel = require('../../options/optimization-level').OptimizationLevel;
  
  var serializeBody = require('../../writer/one-time').body;
  var serializeRules = require('../../writer/one-time').rules;
  
  var Token = require('../../tokenizer/token');
  
  function unsafeSelector(value) {
    return /\.|\*| :/.test(value);
  }
  
  function isBemElement(token) {
    var asString = serializeRules(token[1]);
    return asString.indexOf('__') > -1 || asString.indexOf('--') > -1;
  }
  
  function withoutModifier(selector) {
    return selector.replace(/--[^ ,>\+~:]+/g, '');
  }
  
  function removeAnyUnsafeElements(left, candidates) {
    var leftSelector = withoutModifier(serializeRules(left[1]));
  
    for (var body in candidates) {
      var right = candidates[body];
      var rightSelector = withoutModifier(serializeRules(right[1]));
  
      if (rightSelector.indexOf(leftSelector) > -1 || leftSelector.indexOf(rightSelector) > -1)
        delete candidates[body];
    }
  }
  
  function mergeNonAdjacentByBody(tokens, context) {
    var options = context.options;
    var mergeSemantically = options.level[OptimizationLevel.Two].mergeSemantically;
    var adjacentSpace = options.compatibility.selectors.adjacentSpace;
    var selectorsSortingMethod = options.level[OptimizationLevel.One].selectorsSortingMethod;
    var mergeablePseudoClasses = options.compatibility.selectors.mergeablePseudoClasses;
    var mergeablePseudoElements = options.compatibility.selectors.mergeablePseudoElements;
    var multiplePseudoMerging = options.compatibility.selectors.multiplePseudoMerging;
    var candidates = {};
  
    for (var i = tokens.length - 1; i >= 0; i--) {
      var token = tokens[i];
      if (token[0] != Token.RULE)
        continue;
  
      if (token[2].length > 0 && (!mergeSemantically && unsafeSelector(serializeRules(token[1]))))
        candidates = {};
  
      if (token[2].length > 0 && mergeSemantically && isBemElement(token))
        removeAnyUnsafeElements(token, candidates);
  
      var candidateBody = serializeBody(token[2]);
      var oldToken = candidates[candidateBody];
      if (oldToken &&
          isMergeable(serializeRules(token[1]), mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging) &&
          isMergeable(serializeRules(oldToken[1]), mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging)) {
  
        if (token[2].length > 0) {
          token[1] = tidyRules(oldToken[1].concat(token[1]), false, adjacentSpace, false, context.warnings);
          token[1] = token[1].length > 1 ? sortSelectors(token[1], selectorsSortingMethod) : token[1];
        } else {
          token[1] = oldToken[1].concat(token[1]);
        }
  
        oldToken[2] = [];
        candidates[candidateBody] = null;
      }
  
      candidates[serializeBody(token[2])] = token;
    }
  }
  
  module.exports = mergeNonAdjacentByBody;