| var csstree = require('css-tree'); |
| var parse = csstree.parse; |
| var compress = require('./compress'); |
| var generate = csstree.generate; |
| |
| function debugOutput(name, options, startTime, data) { |
| if (options.debug) { |
| console.error('## ' + name + ' done in %d ms\n', Date.now() - startTime); |
| } |
| |
| return data; |
| } |
| |
| function createDefaultLogger(level) { |
| var lastDebug; |
| |
| return function logger(title, ast) { |
| var line = title; |
| |
| if (ast) { |
| line = '[' + ((Date.now() - lastDebug) / 1000).toFixed(3) + 's] ' + line; |
| } |
| |
| if (level > 1 && ast) { |
| var css = generate(ast); |
| |
| // when level 2, limit css to 256 symbols |
| if (level === 2 && css.length > 256) { |
| css = css.substr(0, 256) + '...'; |
| } |
| |
| line += '\n ' + css + '\n'; |
| } |
| |
| console.error(line); |
| lastDebug = Date.now(); |
| }; |
| } |
| |
| function copy(obj) { |
| var result = {}; |
| |
| for (var key in obj) { |
| result[key] = obj[key]; |
| } |
| |
| return result; |
| } |
| |
| function buildCompressOptions(options) { |
| options = copy(options); |
| |
| if (typeof options.logger !== 'function' && options.debug) { |
| options.logger = createDefaultLogger(options.debug); |
| } |
| |
| return options; |
| } |
| |
| function runHandler(ast, options, handlers) { |
| if (!Array.isArray(handlers)) { |
| handlers = [handlers]; |
| } |
| |
| handlers.forEach(function(fn) { |
| fn(ast, options); |
| }); |
| } |
| |
| function minify(context, source, options) { |
| options = options || {}; |
| |
| var filename = options.filename || '<unknown>'; |
| var result; |
| |
| // parse |
| var ast = debugOutput('parsing', options, Date.now(), |
| parse(source, { |
| context: context, |
| filename: filename, |
| positions: Boolean(options.sourceMap) |
| }) |
| ); |
| |
| // before compress handlers |
| if (options.beforeCompress) { |
| debugOutput('beforeCompress', options, Date.now(), |
| runHandler(ast, options, options.beforeCompress) |
| ); |
| } |
| |
| // compress |
| var compressResult = debugOutput('compress', options, Date.now(), |
| compress(ast, buildCompressOptions(options)) |
| ); |
| |
| // after compress handlers |
| if (options.afterCompress) { |
| debugOutput('afterCompress', options, Date.now(), |
| runHandler(compressResult, options, options.afterCompress) |
| ); |
| } |
| |
| // generate |
| if (options.sourceMap) { |
| result = debugOutput('generate(sourceMap: true)', options, Date.now(), (function() { |
| var tmp = generate(compressResult.ast, { sourceMap: true }); |
| tmp.map._file = filename; // since other tools can relay on file in source map transform chain |
| tmp.map.setSourceContent(filename, source); |
| return tmp; |
| })()); |
| } else { |
| result = debugOutput('generate', options, Date.now(), { |
| css: generate(compressResult.ast), |
| map: null |
| }); |
| } |
| |
| return result; |
| } |
| |
| function minifyStylesheet(source, options) { |
| return minify('stylesheet', source, options); |
| } |
| |
| function minifyBlock(source, options) { |
| return minify('declarationList', source, options); |
| } |
| |
| module.exports = { |
| version: require('../package.json').version, |
| |
| // main methods |
| minify: minifyStylesheet, |
| minifyBlock: minifyBlock, |
| |
| // compress an AST |
| compress: compress, |
| |
| // css syntax parser/walkers/generator/etc |
| syntax: csstree |
| }; |