index.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. var parse = require('./parser');
  2. var compress = require('./compressor');
  3. var translate = require('./utils/translate');
  4. var translateWithSourceMap = require('./utils/translateWithSourceMap');
  5. var walkers = require('./utils/walk');
  6. var clone = require('./utils/clone');
  7. var List = require('./utils/list');
  8. function debugOutput(name, options, startTime, data) {
  9. if (options.debug) {
  10. console.error('## ' + name + ' done in %d ms\n', Date.now() - startTime);
  11. }
  12. return data;
  13. }
  14. function createDefaultLogger(level) {
  15. var lastDebug;
  16. return function logger(title, ast) {
  17. var line = title;
  18. if (ast) {
  19. line = '[' + ((Date.now() - lastDebug) / 1000).toFixed(3) + 's] ' + line;
  20. }
  21. if (level > 1 && ast) {
  22. var css = translate(ast, true);
  23. // when level 2, limit css to 256 symbols
  24. if (level === 2 && css.length > 256) {
  25. css = css.substr(0, 256) + '...';
  26. }
  27. line += '\n ' + css + '\n';
  28. }
  29. console.error(line);
  30. lastDebug = Date.now();
  31. };
  32. }
  33. function copy(obj) {
  34. var result = {};
  35. for (var key in obj) {
  36. result[key] = obj[key];
  37. }
  38. return result;
  39. }
  40. function buildCompressOptions(options) {
  41. options = copy(options);
  42. if (typeof options.logger !== 'function' && options.debug) {
  43. options.logger = createDefaultLogger(options.debug);
  44. }
  45. return options;
  46. }
  47. function runHandler(ast, options, handlers) {
  48. if (!Array.isArray(handlers)) {
  49. handlers = [handlers];
  50. }
  51. handlers.forEach(function(fn) {
  52. fn(ast, options);
  53. });
  54. }
  55. function minify(context, source, options) {
  56. options = options || {};
  57. var filename = options.filename || '<unknown>';
  58. var result;
  59. // parse
  60. var ast = debugOutput('parsing', options, Date.now(),
  61. parse(source, {
  62. context: context,
  63. filename: filename,
  64. positions: Boolean(options.sourceMap)
  65. })
  66. );
  67. // before compress handlers
  68. if (options.beforeCompress) {
  69. debugOutput('beforeCompress', options, Date.now(),
  70. runHandler(ast, options, options.beforeCompress)
  71. );
  72. }
  73. // compress
  74. var compressResult = debugOutput('compress', options, Date.now(),
  75. compress(ast, buildCompressOptions(options))
  76. );
  77. // after compress handlers
  78. if (options.afterCompress) {
  79. debugOutput('afterCompress', options, Date.now(),
  80. runHandler(compressResult, options, options.afterCompress)
  81. );
  82. }
  83. // translate
  84. if (options.sourceMap) {
  85. result = debugOutput('translateWithSourceMap', options, Date.now(), (function() {
  86. var tmp = translateWithSourceMap(compressResult.ast);
  87. tmp.map._file = filename; // since other tools can relay on file in source map transform chain
  88. tmp.map.setSourceContent(filename, source);
  89. return tmp;
  90. })());
  91. } else {
  92. result = debugOutput('translate', options, Date.now(), {
  93. css: translate(compressResult.ast),
  94. map: null
  95. });
  96. }
  97. return result;
  98. }
  99. function minifyStylesheet(source, options) {
  100. return minify('stylesheet', source, options);
  101. };
  102. function minifyBlock(source, options) {
  103. return minify('block', source, options);
  104. }
  105. module.exports = {
  106. version: require('../package.json').version,
  107. // classes
  108. List: List,
  109. // main methods
  110. minify: minifyStylesheet,
  111. minifyBlock: minifyBlock,
  112. // step by step
  113. parse: parse,
  114. compress: compress,
  115. translate: translate,
  116. translateWithSourceMap: translateWithSourceMap,
  117. // walkers
  118. walk: walkers.all,
  119. walkRules: walkers.rules,
  120. walkRulesRight: walkers.rulesRight,
  121. // utils
  122. clone: clone
  123. };