1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | var level0Optimize = require('./optimizer/level-0/optimize');
|
9 | var level1Optimize = require('./optimizer/level-1/optimize');
|
10 | var level2Optimize = require('./optimizer/level-2/optimize');
|
11 | var validator = require('./optimizer/validator');
|
12 |
|
13 | var compatibilityFrom = require('./options/compatibility');
|
14 | var fetchFrom = require('./options/fetch');
|
15 | var formatFrom = require('./options/format').formatFrom;
|
16 | var inlineFrom = require('./options/inline');
|
17 | var inlineRequestFrom = require('./options/inline-request');
|
18 | var inlineTimeoutFrom = require('./options/inline-timeout');
|
19 | var OptimizationLevel = require('./options/optimization-level').OptimizationLevel;
|
20 | var optimizationLevelFrom = require('./options/optimization-level').optimizationLevelFrom;
|
21 | var rebaseFrom = require('./options/rebase');
|
22 | var rebaseToFrom = require('./options/rebase-to');
|
23 |
|
24 | var inputSourceMapTracker = require('./reader/input-source-map-tracker');
|
25 | var readSources = require('./reader/read-sources');
|
26 |
|
27 | var serializeStyles = require('./writer/simple');
|
28 | var serializeStylesAndSourceMap = require('./writer/source-maps');
|
29 |
|
30 | var CleanCSS = module.exports = function CleanCSS(options) {
|
31 | options = options || {};
|
32 |
|
33 | this.options = {
|
34 | compatibility: compatibilityFrom(options.compatibility),
|
35 | fetch: fetchFrom(options.fetch),
|
36 | format: formatFrom(options.format),
|
37 | inline: inlineFrom(options.inline),
|
38 | inlineRequest: inlineRequestFrom(options.inlineRequest),
|
39 | inlineTimeout: inlineTimeoutFrom(options.inlineTimeout),
|
40 | level: optimizationLevelFrom(options.level),
|
41 | rebase: rebaseFrom(options.rebase),
|
42 | rebaseTo: rebaseToFrom(options.rebaseTo),
|
43 | returnPromise: !!options.returnPromise,
|
44 | sourceMap: !!options.sourceMap,
|
45 | sourceMapInlineSources: !!options.sourceMapInlineSources
|
46 | };
|
47 | };
|
48 |
|
49 |
|
50 |
|
51 | CleanCSS.process = function (input, opts) {
|
52 | var cleanCss;
|
53 | var optsTo = opts.to;
|
54 |
|
55 | delete opts.to;
|
56 | cleanCss = new CleanCSS(Object.assign({ returnPromise: true, rebaseTo: optsTo }, opts));
|
57 |
|
58 | return cleanCss.minify(input)
|
59 | .then(function(output) {
|
60 | return { css: output.styles };
|
61 | });
|
62 | };
|
63 |
|
64 |
|
65 | CleanCSS.prototype.minify = function (input, maybeSourceMap, maybeCallback) {
|
66 | var options = this.options;
|
67 |
|
68 | if (options.returnPromise) {
|
69 | return new Promise(function (resolve, reject) {
|
70 | minify(input, options, maybeSourceMap, function (errors, output) {
|
71 | return errors ?
|
72 | reject(errors) :
|
73 | resolve(output);
|
74 | });
|
75 | });
|
76 | } else {
|
77 | return minify(input, options, maybeSourceMap, maybeCallback);
|
78 | }
|
79 | };
|
80 |
|
81 | function minify(input, options, maybeSourceMap, maybeCallback) {
|
82 | var sourceMap = typeof maybeSourceMap != 'function' ?
|
83 | maybeSourceMap :
|
84 | null;
|
85 | var callback = typeof maybeCallback == 'function' ?
|
86 | maybeCallback :
|
87 | (typeof maybeSourceMap == 'function' ? maybeSourceMap : null);
|
88 | var context = {
|
89 | stats: {
|
90 | efficiency: 0,
|
91 | minifiedSize: 0,
|
92 | originalSize: 0,
|
93 | startedAt: Date.now(),
|
94 | timeSpent: 0
|
95 | },
|
96 | cache: {
|
97 | specificity: {}
|
98 | },
|
99 | errors: [],
|
100 | inlinedStylesheets: [],
|
101 | inputSourceMapTracker: inputSourceMapTracker(),
|
102 | localOnly: !callback,
|
103 | options: options,
|
104 | source: null,
|
105 | sourcesContent: {},
|
106 | validator: validator(options.compatibility),
|
107 | warnings: []
|
108 | };
|
109 |
|
110 | if (sourceMap) {
|
111 | context.inputSourceMapTracker.track(undefined, sourceMap);
|
112 | }
|
113 |
|
114 | return runner(context.localOnly)(function () {
|
115 | return readSources(input, context, function (tokens) {
|
116 | var serialize = context.options.sourceMap ?
|
117 | serializeStylesAndSourceMap :
|
118 | serializeStyles;
|
119 |
|
120 | var optimizedTokens = optimize(tokens, context);
|
121 | var optimizedStyles = serialize(optimizedTokens, context);
|
122 | var output = withMetadata(optimizedStyles, context);
|
123 |
|
124 | return callback ?
|
125 | callback(context.errors.length > 0 ? context.errors : null, output) :
|
126 | output;
|
127 | });
|
128 | });
|
129 | }
|
130 |
|
131 | function runner(localOnly) {
|
132 |
|
133 |
|
134 | return localOnly ?
|
135 | function (callback) { return callback(); } :
|
136 | process.nextTick;
|
137 | }
|
138 |
|
139 | function optimize(tokens, context) {
|
140 | var optimized;
|
141 |
|
142 | optimized = level0Optimize(tokens, context);
|
143 | optimized = OptimizationLevel.One in context.options.level ?
|
144 | level1Optimize(tokens, context) :
|
145 | tokens;
|
146 | optimized = OptimizationLevel.Two in context.options.level ?
|
147 | level2Optimize(tokens, context, true) :
|
148 | optimized;
|
149 |
|
150 | return optimized;
|
151 | }
|
152 |
|
153 | function withMetadata(output, context) {
|
154 | output.stats = calculateStatsFrom(output.styles, context);
|
155 | output.errors = context.errors;
|
156 | output.inlinedStylesheets = context.inlinedStylesheets;
|
157 | output.warnings = context.warnings;
|
158 |
|
159 | return output;
|
160 | }
|
161 |
|
162 | function calculateStatsFrom(styles, context) {
|
163 | var finishedAt = Date.now();
|
164 | var timeSpent = finishedAt - context.stats.startedAt;
|
165 |
|
166 | delete context.stats.startedAt;
|
167 | context.stats.timeSpent = timeSpent;
|
168 | context.stats.efficiency = 1 - styles.length / context.stats.originalSize;
|
169 | context.stats.minifiedSize = styles.length;
|
170 |
|
171 | return context.stats;
|
172 | }
|