source: imaps-frontend/node_modules/clean-css/lib/optimizer/level-1/optimize.js@ 79a0317

main
Last change on this file since 79a0317 was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 4 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 9.7 KB
Line 
1var sortSelectors = require('./sort-selectors');
2var tidyRules = require('./tidy-rules');
3var tidyBlock = require('./tidy-block');
4var tidyAtRule = require('./tidy-at-rule');
5
6var Hack = require('../hack');
7var removeUnused = require('../remove-unused');
8var restoreFromOptimizing = require('../restore-from-optimizing');
9var wrapForOptimizing = require('../wrap-for-optimizing').all;
10
11var configuration = require('../configuration');
12var optimizers = require('./value-optimizers');
13
14var OptimizationLevel = require('../../options/optimization-level').OptimizationLevel;
15
16var Token = require('../../tokenizer/token');
17var Marker = require('../../tokenizer/marker');
18
19var formatPosition = require('../../utils/format-position');
20
21var serializeRules = require('../../writer/one-time').rules;
22
23var CHARSET_TOKEN = '@charset';
24var CHARSET_REGEXP = new RegExp('^' + CHARSET_TOKEN, 'i');
25
26var DEFAULT_ROUNDING_PRECISION = require('../../options/rounding-precision').DEFAULT;
27
28var VARIABLE_PROPERTY_NAME_PATTERN = /^--\S+$/;
29var PROPERTY_NAME_PATTERN = /^(?:-chrome-|-[\w-]+\w|\w[\w-]+\w|\w{1,})$/;
30var IMPORT_PREFIX_PATTERN = /^@import/i;
31var URL_PREFIX_PATTERN = /^url\(/i;
32
33function startsAsUrl(value) {
34 return URL_PREFIX_PATTERN.test(value);
35}
36
37function isImport(token) {
38 return IMPORT_PREFIX_PATTERN.test(token[1]);
39}
40
41function isLegacyFilter(property) {
42 var value;
43
44 if (property.name == 'filter' || property.name == '-ms-filter') {
45 value = property.value[0][1];
46
47 return value.indexOf('progid') > -1
48 || value.indexOf('alpha') === 0
49 || value.indexOf('chroma') === 0;
50 }
51 return false;
52}
53
54function noop() {}
55
56function noopValueOptimizer(_name, value, _options) { return value; }
57
58function optimizeBody(rule, properties, context) {
59 var options = context.options;
60 var valueOptimizers;
61 var property, name, type, value;
62 var propertyToken;
63 var propertyOptimizer;
64 var serializedRule = serializeRules(rule);
65 var _properties = wrapForOptimizing(properties);
66 var pluginValueOptimizers = context.options.plugins.level1Value;
67 var pluginPropertyOptimizers = context.options.plugins.level1Property;
68 var isVariable;
69 var i, l;
70
71 for (i = 0, l = _properties.length; i < l; i++) {
72 var j, k, m, n;
73
74 property = _properties[i];
75 name = property.name;
76 propertyOptimizer = configuration[name] && configuration[name].propertyOptimizer || noop;
77 valueOptimizers = configuration[name] && configuration[name].valueOptimizers || [optimizers.whiteSpace];
78 isVariable = VARIABLE_PROPERTY_NAME_PATTERN.test(name);
79
80 if (isVariable) {
81 valueOptimizers = options.variableOptimizers.length > 0
82 ? options.variableOptimizers
83 : [optimizers.whiteSpace];
84 }
85
86 if (!isVariable && !PROPERTY_NAME_PATTERN.test(name)) {
87 propertyToken = property.all[property.position];
88 context.warnings.push('Invalid property name \'' + name + '\' at ' + formatPosition(propertyToken[1][2][0]) + '. Ignoring.');
89 property.unused = true;
90 continue;
91 }
92
93 if (property.value.length === 0) {
94 propertyToken = property.all[property.position];
95 context.warnings.push('Empty property \'' + name + '\' at ' + formatPosition(propertyToken[1][2][0]) + '. Ignoring.');
96 property.unused = true;
97 continue;
98 }
99
100 if (property.hack && (
101 (property.hack[0] == Hack.ASTERISK || property.hack[0] == Hack.UNDERSCORE)
102 && !options.compatibility.properties.iePrefixHack
103 || property.hack[0] == Hack.BACKSLASH && !options.compatibility.properties.ieSuffixHack
104 || property.hack[0] == Hack.BANG && !options.compatibility.properties.ieBangHack)) {
105 property.unused = true;
106 continue;
107 }
108
109 if (!options.compatibility.properties.ieFilters && isLegacyFilter(property)) {
110 property.unused = true;
111 continue;
112 }
113
114 if (property.block) {
115 optimizeBody(rule, property.value[0][1], context);
116 continue;
117 }
118
119 for (j = 0, m = property.value.length; j < m; j++) {
120 type = property.value[j][0];
121 value = property.value[j][1];
122
123 if (type == Token.PROPERTY_BLOCK) {
124 property.unused = true;
125 context.warnings.push('Invalid value token at ' + formatPosition(value[0][1][2][0]) + '. Ignoring.');
126 break;
127 }
128
129 if (startsAsUrl(value) && !context.validator.isUrl(value)) {
130 property.unused = true;
131 context.warnings.push('Broken URL \'' + value + '\' at ' + formatPosition(property.value[j][2][0]) + '. Ignoring.');
132 break;
133 }
134
135 for (k = 0, n = valueOptimizers.length; k < n; k++) {
136 value = valueOptimizers[k](name, value, options);
137 }
138
139 for (k = 0, n = pluginValueOptimizers.length; k < n; k++) {
140 value = pluginValueOptimizers[k](name, value, options);
141 }
142
143 property.value[j][1] = value;
144 }
145
146 propertyOptimizer(serializedRule, property, options);
147
148 for (j = 0, m = pluginPropertyOptimizers.length; j < m; j++) {
149 pluginPropertyOptimizers[j](serializedRule, property, options);
150 }
151 }
152
153 restoreFromOptimizing(_properties);
154 removeUnused(_properties);
155 removeComments(properties, options);
156}
157
158function removeComments(tokens, options) {
159 var token;
160 var i;
161
162 for (i = 0; i < tokens.length; i++) {
163 token = tokens[i];
164
165 if (token[0] != Token.COMMENT) {
166 continue;
167 }
168
169 optimizeComment(token, options);
170
171 if (token[1].length === 0) {
172 tokens.splice(i, 1);
173 i--;
174 }
175 }
176}
177
178function optimizeComment(token, options) {
179 if (token[1][2] == Marker.EXCLAMATION && (options.level[OptimizationLevel.One].specialComments == 'all' || options.commentsKept < options.level[OptimizationLevel.One].specialComments)) {
180 options.commentsKept++;
181 return;
182 }
183
184 token[1] = [];
185}
186
187function cleanupCharsets(tokens) {
188 var hasCharset = false;
189
190 for (var i = 0, l = tokens.length; i < l; i++) {
191 var token = tokens[i];
192
193 if (token[0] != Token.AT_RULE) { continue; }
194
195 if (!CHARSET_REGEXP.test(token[1])) { continue; }
196
197 if (hasCharset || token[1].indexOf(CHARSET_TOKEN) == -1) {
198 tokens.splice(i, 1);
199 i--;
200 l--;
201 } else {
202 hasCharset = true;
203 tokens.splice(i, 1);
204 tokens.unshift([Token.AT_RULE, token[1].replace(CHARSET_REGEXP, CHARSET_TOKEN)]);
205 }
206 }
207}
208
209function buildUnitRegexp(options) {
210 var units = ['px', 'em', 'ex', 'cm', 'mm', 'in', 'pt', 'pc', '%'];
211 var otherUnits = ['ch', 'rem', 'vh', 'vm', 'vmax', 'vmin', 'vw'];
212
213 otherUnits.forEach(function(unit) {
214 if (options.compatibility.units[unit]) {
215 units.push(unit);
216 }
217 });
218
219 return new RegExp('(^|\\s|\\(|,)0(?:' + units.join('|') + ')(\\W|$)', 'g');
220}
221
222function buildPrecisionOptions(roundingPrecision) {
223 var precisionOptions = {
224 matcher: null,
225 units: {}
226 };
227 var optimizable = [];
228 var unit;
229 var value;
230
231 for (unit in roundingPrecision) {
232 value = roundingPrecision[unit];
233
234 if (value != DEFAULT_ROUNDING_PRECISION) {
235 precisionOptions.units[unit] = {};
236 precisionOptions.units[unit].value = value;
237 precisionOptions.units[unit].multiplier = 10 ** value;
238
239 optimizable.push(unit);
240 }
241 }
242
243 if (optimizable.length > 0) {
244 precisionOptions.enabled = true;
245 precisionOptions.decimalPointMatcher = new RegExp('(\\d)\\.($|' + optimizable.join('|') + ')($|\\W)', 'g');
246 precisionOptions.zeroMatcher = new RegExp('(\\d*)(\\.\\d+)(' + optimizable.join('|') + ')', 'g');
247 }
248
249 return precisionOptions;
250}
251
252function buildVariableOptimizers(options) {
253 return options.level[OptimizationLevel.One].variableValueOptimizers.map(function(optimizer) {
254 if (typeof (optimizer) == 'string') {
255 return optimizers[optimizer] || noopValueOptimizer;
256 }
257
258 return optimizer;
259 });
260}
261
262function level1Optimize(tokens, context) {
263 var options = context.options;
264 var levelOptions = options.level[OptimizationLevel.One];
265 var ie7Hack = options.compatibility.selectors.ie7Hack;
266 var adjacentSpace = options.compatibility.selectors.adjacentSpace;
267 var spaceAfterClosingBrace = options.compatibility.properties.spaceAfterClosingBrace;
268 var format = options.format;
269 var mayHaveCharset = false;
270 var afterRules = false;
271
272 options.unitsRegexp = options.unitsRegexp || buildUnitRegexp(options);
273 options.precision = options.precision || buildPrecisionOptions(levelOptions.roundingPrecision);
274 options.commentsKept = options.commentsKept || 0;
275 options.variableOptimizers = options.variableOptimizers || buildVariableOptimizers(options);
276
277 for (var i = 0, l = tokens.length; i < l; i++) {
278 var token = tokens[i];
279
280 switch (token[0]) {
281 case Token.AT_RULE:
282 token[1] = isImport(token) && afterRules ? '' : token[1];
283 token[1] = levelOptions.tidyAtRules ? tidyAtRule(token[1]) : token[1];
284 mayHaveCharset = true;
285 break;
286 case Token.AT_RULE_BLOCK:
287 optimizeBody(token[1], token[2], context);
288 afterRules = true;
289 break;
290 case Token.NESTED_BLOCK:
291 token[1] = levelOptions.tidyBlockScopes ? tidyBlock(token[1], spaceAfterClosingBrace) : token[1];
292 level1Optimize(token[2], context);
293 afterRules = true;
294 break;
295 case Token.COMMENT:
296 optimizeComment(token, options);
297 break;
298 case Token.RULE:
299 token[1] = levelOptions.tidySelectors
300 ? tidyRules(token[1], !ie7Hack, adjacentSpace, format, context.warnings)
301 : token[1];
302 token[1] = token[1].length > 1 ? sortSelectors(token[1], levelOptions.selectorsSortingMethod) : token[1];
303 optimizeBody(token[1], token[2], context);
304 afterRules = true;
305 break;
306 }
307
308 if (token[0] == Token.COMMENT
309 && token[1].length === 0
310 || levelOptions.removeEmpty
311 && (token[1].length === 0 || (token[2] && token[2].length === 0))) {
312 tokens.splice(i, 1);
313 i--;
314 l--;
315 }
316 }
317
318 if (levelOptions.cleanupCharsets && mayHaveCharset) {
319 cleanupCharsets(tokens);
320 }
321
322 return tokens;
323}
324
325module.exports = level1Optimize;
Note: See TracBrowser for help on using the repository browser.