merge-non-adjacent-by-selector.js 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. var canReorder = require('./reorderable').canReorder;
  2. var extractProperties = require('./extract-properties');
  3. var optimizeProperties = require('./properties/optimize');
  4. var serializeRules = require('../../writer/one-time').rules;
  5. var Token = require('../../tokenizer/token');
  6. function mergeNonAdjacentBySelector(tokens, context) {
  7. var specificityCache = context.cache.specificity;
  8. var allSelectors = {};
  9. var repeatedSelectors = [];
  10. var i;
  11. for (i = tokens.length - 1; i >= 0; i--) {
  12. if (tokens[i][0] != Token.RULE) { continue; }
  13. if (tokens[i][2].length === 0) { continue; }
  14. var selector = serializeRules(tokens[i][1]);
  15. allSelectors[selector] = [i].concat(allSelectors[selector] || []);
  16. if (allSelectors[selector].length == 2) { repeatedSelectors.push(selector); }
  17. }
  18. for (i = repeatedSelectors.length - 1; i >= 0; i--) {
  19. var positions = allSelectors[repeatedSelectors[i]];
  20. selectorIterator:
  21. for (var j = positions.length - 1; j > 0; j--) {
  22. var positionOne = positions[j - 1];
  23. var tokenOne = tokens[positionOne];
  24. var positionTwo = positions[j];
  25. var tokenTwo = tokens[positionTwo];
  26. directionIterator:
  27. for (var direction = 1; direction >= -1; direction -= 2) {
  28. var topToBottom = direction == 1;
  29. var from = topToBottom ? positionOne + 1 : positionTwo - 1;
  30. var to = topToBottom ? positionTwo : positionOne;
  31. var delta = topToBottom ? 1 : -1;
  32. var moved = topToBottom ? tokenOne : tokenTwo;
  33. var target = topToBottom ? tokenTwo : tokenOne;
  34. var movedProperties = extractProperties(moved);
  35. while (from != to) {
  36. var traversedProperties = extractProperties(tokens[from]);
  37. from += delta;
  38. // traversed then moved as we move selectors towards the start
  39. var reorderable = topToBottom
  40. ? canReorder(movedProperties, traversedProperties, specificityCache)
  41. : canReorder(traversedProperties, movedProperties, specificityCache);
  42. if (!reorderable && !topToBottom) { continue selectorIterator; }
  43. if (!reorderable && topToBottom) { continue directionIterator; }
  44. }
  45. if (topToBottom) {
  46. Array.prototype.push.apply(moved[2], target[2]);
  47. target[2] = moved[2];
  48. } else {
  49. Array.prototype.push.apply(target[2], moved[2]);
  50. }
  51. optimizeProperties(target[2], true, true, context);
  52. moved[2] = [];
  53. }
  54. }
  55. }
  56. }
  57. module.exports = mergeNonAdjacentBySelector;