index.js 3.4 KB

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