source: imaps-frontend/node_modules/clean-css/lib/optimizer/level-2/properties/merge-into-shorthands.js

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

F4 Finalna Verzija

  • Property mode set to 100644
File size: 14.0 KB
Line 
1var everyValuesPair = require('./every-values-pair');
2var hasInherit = require('./has-inherit');
3var hasSameValues = require('./has-same-values');
4var populateComponents = require('./populate-components');
5
6var configuration = require('../../configuration');
7var deepClone = require('../../clone').deep;
8var restoreWithComponents = require('../restore-with-components');
9
10var restoreFromOptimizing = require('../../restore-from-optimizing');
11var wrapSingle = require('../../wrap-for-optimizing').single;
12
13var serializeBody = require('../../../writer/one-time').body;
14var Token = require('../../../tokenizer/token');
15
16function mergeIntoShorthands(properties, validator) {
17 var candidates = {};
18 var descriptor;
19 var componentOf;
20 var property;
21 var i, l;
22 var j, m;
23
24 // there is no shorthand property made up of less than 3 longhands
25 if (properties.length < 3) {
26 return;
27 }
28
29 for (i = 0, l = properties.length; i < l; i++) {
30 property = properties[i];
31 descriptor = configuration[property.name];
32
33 if (property.dynamic) {
34 continue;
35 }
36
37 if (property.unused) {
38 continue;
39 }
40
41 if (property.hack) {
42 continue;
43 }
44
45 if (property.block) {
46 continue;
47 }
48
49 if (descriptor && descriptor.singleTypeComponents && !hasSameValues(property)) {
50 continue;
51 }
52
53 invalidateOrCompact(properties, i, candidates, validator);
54
55 if (descriptor && descriptor.componentOf) {
56 for (j = 0, m = descriptor.componentOf.length; j < m; j++) {
57 componentOf = descriptor.componentOf[j];
58
59 candidates[componentOf] = candidates[componentOf] || {};
60 candidates[componentOf][property.name] = property;
61 }
62 }
63 }
64
65 invalidateOrCompact(properties, i, candidates, validator);
66}
67
68function invalidateOrCompact(properties, position, candidates, validator) {
69 var invalidatedBy = properties[position];
70 var shorthandName;
71 var shorthandDescriptor;
72 var candidateComponents;
73 var replacedCandidates = [];
74 var i;
75
76 for (shorthandName in candidates) {
77 if (undefined !== invalidatedBy && shorthandName == invalidatedBy.name) {
78 continue;
79 }
80
81 shorthandDescriptor = configuration[shorthandName];
82 candidateComponents = candidates[shorthandName];
83 if (invalidatedBy && invalidates(candidates, shorthandName, invalidatedBy)) {
84 delete candidates[shorthandName];
85 continue;
86 }
87
88 if (shorthandDescriptor.components.length > Object.keys(candidateComponents).length) {
89 continue;
90 }
91
92 if (mixedImportance(candidateComponents)) {
93 continue;
94 }
95
96 if (!overridable(candidateComponents, shorthandName, validator)) {
97 continue;
98 }
99
100 if (!mergeable(candidateComponents)) {
101 continue;
102 }
103
104 if (mixedInherit(candidateComponents)) {
105 replaceWithInheritBestFit(properties, candidateComponents, shorthandName, validator);
106 } else {
107 replaceWithShorthand(properties, candidateComponents, shorthandName, validator);
108 }
109
110 replacedCandidates.push(shorthandName);
111 }
112
113 for (i = replacedCandidates.length - 1; i >= 0; i--) {
114 delete candidates[replacedCandidates[i]];
115 }
116}
117
118function invalidates(candidates, shorthandName, invalidatedBy) {
119 var shorthandDescriptor = configuration[shorthandName];
120 var invalidatedByDescriptor = configuration[invalidatedBy.name];
121 var componentName;
122
123 if ('overridesShorthands' in shorthandDescriptor && shorthandDescriptor.overridesShorthands.indexOf(invalidatedBy.name) > -1) {
124 return true;
125 }
126
127 if (invalidatedByDescriptor && 'componentOf' in invalidatedByDescriptor) {
128 for (componentName in candidates[shorthandName]) {
129 if (invalidatedByDescriptor.componentOf.indexOf(componentName) > -1) {
130 return true;
131 }
132 }
133 }
134
135 return false;
136}
137
138function mixedImportance(components) {
139 var important;
140 var componentName;
141
142 for (componentName in components) {
143 if (undefined !== important && components[componentName].important != important) {
144 return true;
145 }
146
147 important = components[componentName].important;
148 }
149
150 return false;
151}
152
153function overridable(components, shorthandName, validator) {
154 var descriptor = configuration[shorthandName];
155 var newValuePlaceholder = [
156 Token.PROPERTY,
157 [Token.PROPERTY_NAME, shorthandName],
158 [Token.PROPERTY_VALUE, descriptor.defaultValue]
159 ];
160 var newProperty = wrapSingle(newValuePlaceholder);
161 var component;
162 var mayOverride;
163 var i, l;
164
165 populateComponents([newProperty], validator, []);
166
167 for (i = 0, l = descriptor.components.length; i < l; i++) {
168 component = components[descriptor.components[i]];
169 mayOverride = configuration[component.name].canOverride || sameValue;
170
171 if (!everyValuesPair(mayOverride.bind(null, validator), newProperty.components[i], component)) {
172 return false;
173 }
174 }
175
176 return true;
177}
178
179function sameValue(_validator, value1, value2) {
180 return value1 === value2;
181}
182
183function mergeable(components) {
184 var lastCount = null;
185 var currentCount;
186 var componentName;
187 var component;
188 var descriptor;
189 var values;
190
191 for (componentName in components) {
192 component = components[componentName];
193 descriptor = configuration[componentName];
194
195 if (!('restore' in descriptor)) {
196 continue;
197 }
198
199 restoreFromOptimizing([component.all[component.position]], restoreWithComponents);
200 values = descriptor.restore(component, configuration);
201
202 currentCount = values.length;
203
204 if (lastCount !== null && currentCount !== lastCount) {
205 return false;
206 }
207
208 lastCount = currentCount;
209 }
210
211 return true;
212}
213
214function mixedInherit(components) {
215 var componentName;
216 var lastValue = null;
217 var currentValue;
218
219 for (componentName in components) {
220 currentValue = hasInherit(components[componentName]);
221
222 if (lastValue !== null && lastValue !== currentValue) {
223 return true;
224 }
225
226 lastValue = currentValue;
227 }
228
229 return false;
230}
231
232function replaceWithInheritBestFit(properties, candidateComponents, shorthandName, validator) {
233 var viaLonghands = buildSequenceWithInheritLonghands(candidateComponents, shorthandName, validator);
234 var viaShorthand = buildSequenceWithInheritShorthand(candidateComponents, shorthandName, validator);
235 var longhandTokensSequence = viaLonghands[0];
236 var shorthandTokensSequence = viaShorthand[0];
237 var isLonghandsShorter = serializeBody(longhandTokensSequence).length < serializeBody(shorthandTokensSequence).length;
238 var newTokensSequence = isLonghandsShorter ? longhandTokensSequence : shorthandTokensSequence;
239 var newProperty = isLonghandsShorter ? viaLonghands[1] : viaShorthand[1];
240 var newComponents = isLonghandsShorter ? viaLonghands[2] : viaShorthand[2];
241 var lastComponent = candidateComponents[Object.keys(candidateComponents).pop()];
242 var all = lastComponent.all;
243 var insertAt = lastComponent.position;
244 var componentName;
245 var oldComponent;
246 var newComponent;
247 var newToken;
248
249 newProperty.position = insertAt;
250 newProperty.shorthand = true;
251 newProperty.important = lastComponent.important;
252 newProperty.multiplex = false;
253 newProperty.dirty = true;
254 newProperty.all = all;
255 newProperty.all[insertAt] = newTokensSequence[0];
256
257 properties.splice(insertAt, 1, newProperty);
258
259 for (componentName in candidateComponents) {
260 oldComponent = candidateComponents[componentName];
261 oldComponent.unused = true;
262
263 newProperty.multiplex = newProperty.multiplex || oldComponent.multiplex;
264
265 if (oldComponent.name in newComponents) {
266 newComponent = newComponents[oldComponent.name];
267 newToken = findTokenIn(newTokensSequence, componentName);
268
269 newComponent.position = all.length;
270 newComponent.all = all;
271 newComponent.all.push(newToken);
272
273 properties.push(newComponent);
274 }
275 }
276}
277
278function buildSequenceWithInheritLonghands(components, shorthandName, validator) {
279 var tokensSequence = [];
280 var inheritComponents = {};
281 var nonInheritComponents = {};
282 var descriptor = configuration[shorthandName];
283 var shorthandToken = [
284 Token.PROPERTY,
285 [Token.PROPERTY_NAME, shorthandName],
286 [Token.PROPERTY_VALUE, descriptor.defaultValue]
287 ];
288 var newProperty = wrapSingle(shorthandToken);
289 var component;
290 var longhandToken;
291 var newComponent;
292 var nameMetadata;
293 var i, l;
294
295 populateComponents([newProperty], validator, []);
296
297 for (i = 0, l = descriptor.components.length; i < l; i++) {
298 component = components[descriptor.components[i]];
299
300 if (hasInherit(component)) {
301 longhandToken = component.all[component.position].slice(0, 2);
302 Array.prototype.push.apply(longhandToken, component.value);
303 tokensSequence.push(longhandToken);
304
305 newComponent = deepClone(component);
306 newComponent.value = inferComponentValue(components, newComponent.name);
307
308 newProperty.components[i] = newComponent;
309 inheritComponents[component.name] = deepClone(component);
310 } else {
311 newComponent = deepClone(component);
312 newComponent.all = component.all;
313 newProperty.components[i] = newComponent;
314
315 nonInheritComponents[component.name] = component;
316 }
317 }
318
319 newProperty.important = components[Object.keys(components).pop()].important;
320
321 nameMetadata = joinMetadata(nonInheritComponents, 1);
322 shorthandToken[1].push(nameMetadata);
323
324 restoreFromOptimizing([newProperty], restoreWithComponents);
325
326 shorthandToken = shorthandToken.slice(0, 2);
327 Array.prototype.push.apply(shorthandToken, newProperty.value);
328
329 tokensSequence.unshift(shorthandToken);
330
331 return [tokensSequence, newProperty, inheritComponents];
332}
333
334function inferComponentValue(components, propertyName) {
335 var descriptor = configuration[propertyName];
336
337 if ('oppositeTo' in descriptor) {
338 return components[descriptor.oppositeTo].value;
339 }
340 return [[Token.PROPERTY_VALUE, descriptor.defaultValue]];
341}
342
343function joinMetadata(components, at) {
344 var metadata = [];
345 var component;
346 var originalValue;
347 var componentMetadata;
348 var componentName;
349
350 for (componentName in components) {
351 component = components[componentName];
352 originalValue = component.all[component.position];
353 componentMetadata = originalValue[at][originalValue[at].length - 1];
354
355 Array.prototype.push.apply(metadata, componentMetadata);
356 }
357
358 return metadata.sort(metadataSorter);
359}
360
361function metadataSorter(metadata1, metadata2) {
362 var line1 = metadata1[0];
363 var line2 = metadata2[0];
364 var column1 = metadata1[1];
365 var column2 = metadata2[1];
366
367 if (line1 < line2) {
368 return -1;
369 } if (line1 === line2) {
370 return column1 < column2 ? -1 : 1;
371 }
372 return 1;
373}
374
375function buildSequenceWithInheritShorthand(components, shorthandName, validator) {
376 var tokensSequence = [];
377 var inheritComponents = {};
378 var nonInheritComponents = {};
379 var descriptor = configuration[shorthandName];
380 var shorthandToken = [
381 Token.PROPERTY,
382 [Token.PROPERTY_NAME, shorthandName],
383 [Token.PROPERTY_VALUE, 'inherit']
384 ];
385 var newProperty = wrapSingle(shorthandToken);
386 var component;
387 var longhandToken;
388 var nameMetadata;
389 var valueMetadata;
390 var i, l;
391
392 populateComponents([newProperty], validator, []);
393
394 for (i = 0, l = descriptor.components.length; i < l; i++) {
395 component = components[descriptor.components[i]];
396
397 if (hasInherit(component)) {
398 inheritComponents[component.name] = component;
399 } else {
400 longhandToken = component.all[component.position].slice(0, 2);
401 Array.prototype.push.apply(longhandToken, component.value);
402 tokensSequence.push(longhandToken);
403
404 nonInheritComponents[component.name] = deepClone(component);
405 }
406 }
407
408 nameMetadata = joinMetadata(inheritComponents, 1);
409 shorthandToken[1].push(nameMetadata);
410
411 valueMetadata = joinMetadata(inheritComponents, 2);
412 shorthandToken[2].push(valueMetadata);
413
414 tokensSequence.unshift(shorthandToken);
415
416 return [tokensSequence, newProperty, nonInheritComponents];
417}
418
419function findTokenIn(tokens, componentName) {
420 var i, l;
421
422 for (i = 0, l = tokens.length; i < l; i++) {
423 if (tokens[i][1][1] == componentName) {
424 return tokens[i];
425 }
426 }
427}
428
429function replaceWithShorthand(properties, candidateComponents, shorthandName, validator) {
430 var descriptor = configuration[shorthandName];
431 var nameMetadata;
432 var valueMetadata;
433 var newValuePlaceholder = [
434 Token.PROPERTY,
435 [Token.PROPERTY_NAME, shorthandName],
436 [Token.PROPERTY_VALUE, descriptor.defaultValue]
437 ];
438 var all;
439 var insertAt = inferInsertAtFrom(properties, candidateComponents, shorthandName);
440
441 var newProperty = wrapSingle(newValuePlaceholder);
442 newProperty.shorthand = true;
443 newProperty.dirty = true;
444 newProperty.multiplex = false;
445
446 populateComponents([newProperty], validator, []);
447
448 for (var i = 0, l = descriptor.components.length; i < l; i++) {
449 var component = candidateComponents[descriptor.components[i]];
450
451 newProperty.components[i] = deepClone(component);
452 newProperty.important = component.important;
453 newProperty.multiplex = newProperty.multiplex || component.multiplex;
454
455 all = component.all;
456 }
457
458 for (var componentName in candidateComponents) {
459 candidateComponents[componentName].unused = true;
460 }
461
462 nameMetadata = joinMetadata(candidateComponents, 1);
463 newValuePlaceholder[1].push(nameMetadata);
464
465 valueMetadata = joinMetadata(candidateComponents, 2);
466 newValuePlaceholder[2].push(valueMetadata);
467
468 newProperty.position = insertAt;
469 newProperty.all = all;
470 newProperty.all[insertAt] = newValuePlaceholder;
471
472 properties.splice(insertAt, 1, newProperty);
473}
474
475function inferInsertAtFrom(properties, candidateComponents, shorthandName) {
476 var candidateComponentNames = Object.keys(candidateComponents);
477 var firstCandidatePosition = candidateComponents[candidateComponentNames[0]].position;
478 var lastCandidatePosition = candidateComponents[candidateComponentNames[candidateComponentNames.length - 1]].position;
479
480 if (shorthandName == 'border' && traversesVia(properties.slice(firstCandidatePosition, lastCandidatePosition), 'border-image')) {
481 return firstCandidatePosition;
482 }
483 return lastCandidatePosition;
484}
485
486function traversesVia(properties, propertyName) {
487 for (var i = properties.length - 1; i >= 0; i--) {
488 if (properties[i].name == propertyName) {
489 return true;
490 }
491 }
492
493 return false;
494}
495
496module.exports = mergeIntoShorthands;
Note: See TracBrowser for help on using the repository browser.