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