optimization-level.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. var roundingPrecisionFrom = require('./rounding-precision').roundingPrecisionFrom;
  2. var override = require('../utils/override');
  3. var OptimizationLevel = {
  4. Zero: '0',
  5. One: '1',
  6. Two: '2'
  7. };
  8. var DEFAULTS = {};
  9. DEFAULTS[OptimizationLevel.Zero] = {};
  10. DEFAULTS[OptimizationLevel.One] = {
  11. cleanupCharsets: true,
  12. normalizeUrls: true,
  13. optimizeBackground: true,
  14. optimizeBorderRadius: true,
  15. optimizeFilter: true,
  16. optimizeFont: true,
  17. optimizeFontWeight: true,
  18. optimizeOutline: true,
  19. removeNegativePaddings: true,
  20. removeQuotes: true,
  21. removeWhitespace: true,
  22. replaceMultipleZeros: true,
  23. replaceTimeUnits: true,
  24. replaceZeroUnits: true,
  25. roundingPrecision: roundingPrecisionFrom(undefined),
  26. selectorsSortingMethod: 'standard',
  27. specialComments: 'all',
  28. tidyAtRules: true,
  29. tidyBlockScopes: true,
  30. tidySelectors: true,
  31. transform: noop
  32. };
  33. DEFAULTS[OptimizationLevel.Two] = {
  34. mergeAdjacentRules: true,
  35. mergeIntoShorthands: true,
  36. mergeMedia: true,
  37. mergeNonAdjacentRules: true,
  38. mergeSemantically: false,
  39. overrideProperties: true,
  40. reduceNonAdjacentRules: true,
  41. removeDuplicateFontRules: true,
  42. removeDuplicateMediaBlocks: true,
  43. removeDuplicateRules: true,
  44. restructureRules: false
  45. };
  46. var ALL_KEYWORD_1 = '*';
  47. var ALL_KEYWORD_2 = 'all';
  48. var FALSE_KEYWORD_1 = 'false';
  49. var FALSE_KEYWORD_2 = 'off';
  50. var TRUE_KEYWORD_1 = 'true';
  51. var TRUE_KEYWORD_2 = 'on';
  52. var OPTION_SEPARATOR = ';';
  53. var OPTION_VALUE_SEPARATOR = ':';
  54. function noop() {}
  55. function optimizationLevelFrom(source) {
  56. var level = override(DEFAULTS, {});
  57. var Zero = OptimizationLevel.Zero;
  58. var One = OptimizationLevel.One;
  59. var Two = OptimizationLevel.Two;
  60. if (undefined === source) {
  61. delete level[Two];
  62. return level;
  63. }
  64. if (typeof source == 'string') {
  65. source = parseInt(source);
  66. }
  67. if (typeof source == 'number' && source === parseInt(Two)) {
  68. return level;
  69. }
  70. if (typeof source == 'number' && source === parseInt(One)) {
  71. delete level[Two];
  72. return level;
  73. }
  74. if (typeof source == 'number' && source === parseInt(Zero)) {
  75. delete level[Two];
  76. delete level[One];
  77. return level;
  78. }
  79. if (typeof source == 'object') {
  80. source = covertValuesToHashes(source);
  81. }
  82. if (One in source && 'roundingPrecision' in source[One]) {
  83. source[One].roundingPrecision = roundingPrecisionFrom(source[One].roundingPrecision);
  84. }
  85. if (Zero in source || One in source || Two in source) {
  86. level[Zero] = override(level[Zero], source[Zero]);
  87. }
  88. if (One in source && ALL_KEYWORD_1 in source[One]) {
  89. level[One] = override(level[One], defaults(One, normalizeValue(source[One][ALL_KEYWORD_1])));
  90. delete source[One][ALL_KEYWORD_1];
  91. }
  92. if (One in source && ALL_KEYWORD_2 in source[One]) {
  93. level[One] = override(level[One], defaults(One, normalizeValue(source[One][ALL_KEYWORD_2])));
  94. delete source[One][ALL_KEYWORD_2];
  95. }
  96. if (One in source || Two in source) {
  97. level[One] = override(level[One], source[One]);
  98. } else {
  99. delete level[One];
  100. }
  101. if (Two in source && ALL_KEYWORD_1 in source[Two]) {
  102. level[Two] = override(level[Two], defaults(Two, normalizeValue(source[Two][ALL_KEYWORD_1])));
  103. delete source[Two][ALL_KEYWORD_1];
  104. }
  105. if (Two in source && ALL_KEYWORD_2 in source[Two]) {
  106. level[Two] = override(level[Two], defaults(Two, normalizeValue(source[Two][ALL_KEYWORD_2])));
  107. delete source[Two][ALL_KEYWORD_2];
  108. }
  109. if (Two in source) {
  110. level[Two] = override(level[Two], source[Two]);
  111. } else {
  112. delete level[Two];
  113. }
  114. return level;
  115. }
  116. function defaults(level, value) {
  117. var options = override(DEFAULTS[level], {});
  118. var key;
  119. for (key in options) {
  120. if (typeof options[key] == 'boolean') {
  121. options[key] = value;
  122. }
  123. }
  124. return options;
  125. }
  126. function normalizeValue(value) {
  127. switch (value) {
  128. case FALSE_KEYWORD_1:
  129. case FALSE_KEYWORD_2:
  130. return false;
  131. case TRUE_KEYWORD_1:
  132. case TRUE_KEYWORD_2:
  133. return true;
  134. default:
  135. return value;
  136. }
  137. }
  138. function covertValuesToHashes(source) {
  139. var clonedSource = override(source, {});
  140. var level;
  141. var i;
  142. for (i = 0; i <= 2; i++) {
  143. level = '' + i;
  144. if (level in clonedSource && (clonedSource[level] === undefined || clonedSource[level] === false)) {
  145. delete clonedSource[level];
  146. }
  147. if (level in clonedSource && clonedSource[level] === true) {
  148. clonedSource[level] = {};
  149. }
  150. if (level in clonedSource && typeof clonedSource[level] == 'string') {
  151. clonedSource[level] = covertToHash(clonedSource[level], level);
  152. }
  153. }
  154. return clonedSource;
  155. }
  156. function covertToHash(asString, level) {
  157. return asString
  158. .split(OPTION_SEPARATOR)
  159. .reduce(function (accumulator, directive) {
  160. var parts = directive.split(OPTION_VALUE_SEPARATOR);
  161. var name = parts[0];
  162. var value = parts[1];
  163. var normalizedValue = normalizeValue(value);
  164. if (ALL_KEYWORD_1 == name || ALL_KEYWORD_2 == name) {
  165. accumulator = override(accumulator, defaults(level, normalizedValue));
  166. } else {
  167. accumulator[name] = normalizedValue;
  168. }
  169. return accumulator;
  170. }, {});
  171. }
  172. module.exports = {
  173. OptimizationLevel: OptimizationLevel,
  174. optimizationLevelFrom: optimizationLevelFrom,
  175. };