source: trip-planner-front/node_modules/csso/lib/restructure/6-restructBlock.js

Last change on this file was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 10.6 KB
Line 
1var resolveProperty = require('css-tree').property;
2var resolveKeyword = require('css-tree').keyword;
3var walk = require('css-tree').walk;
4var generate = require('css-tree').generate;
5var fingerprintId = 1;
6var dontRestructure = {
7 'src': 1 // https://github.com/afelix/csso/issues/50
8};
9
10var DONT_MIX_VALUE = {
11 // https://developer.mozilla.org/en-US/docs/Web/CSS/display#Browser_compatibility
12 'display': /table|ruby|flex|-(flex)?box$|grid|contents|run-in/i,
13 // https://developer.mozilla.org/en/docs/Web/CSS/text-align
14 'text-align': /^(start|end|match-parent|justify-all)$/i
15};
16
17var SAFE_VALUES = {
18 cursor: [
19 'auto', 'crosshair', 'default', 'move', 'text', 'wait', 'help',
20 'n-resize', 'e-resize', 's-resize', 'w-resize',
21 'ne-resize', 'nw-resize', 'se-resize', 'sw-resize',
22 'pointer', 'progress', 'not-allowed', 'no-drop', 'vertical-text', 'all-scroll',
23 'col-resize', 'row-resize'
24 ],
25 overflow: [
26 'hidden', 'visible', 'scroll', 'auto'
27 ],
28 position: [
29 'static', 'relative', 'absolute', 'fixed'
30 ]
31};
32
33var NEEDLESS_TABLE = {
34 'border-width': ['border'],
35 'border-style': ['border'],
36 'border-color': ['border'],
37 'border-top': ['border'],
38 'border-right': ['border'],
39 'border-bottom': ['border'],
40 'border-left': ['border'],
41 'border-top-width': ['border-top', 'border-width', 'border'],
42 'border-right-width': ['border-right', 'border-width', 'border'],
43 'border-bottom-width': ['border-bottom', 'border-width', 'border'],
44 'border-left-width': ['border-left', 'border-width', 'border'],
45 'border-top-style': ['border-top', 'border-style', 'border'],
46 'border-right-style': ['border-right', 'border-style', 'border'],
47 'border-bottom-style': ['border-bottom', 'border-style', 'border'],
48 'border-left-style': ['border-left', 'border-style', 'border'],
49 'border-top-color': ['border-top', 'border-color', 'border'],
50 'border-right-color': ['border-right', 'border-color', 'border'],
51 'border-bottom-color': ['border-bottom', 'border-color', 'border'],
52 'border-left-color': ['border-left', 'border-color', 'border'],
53 'margin-top': ['margin'],
54 'margin-right': ['margin'],
55 'margin-bottom': ['margin'],
56 'margin-left': ['margin'],
57 'padding-top': ['padding'],
58 'padding-right': ['padding'],
59 'padding-bottom': ['padding'],
60 'padding-left': ['padding'],
61 'font-style': ['font'],
62 'font-variant': ['font'],
63 'font-weight': ['font'],
64 'font-size': ['font'],
65 'font-family': ['font'],
66 'list-style-type': ['list-style'],
67 'list-style-position': ['list-style'],
68 'list-style-image': ['list-style']
69};
70
71function getPropertyFingerprint(propertyName, declaration, fingerprints) {
72 var realName = resolveProperty(propertyName).basename;
73
74 if (realName === 'background') {
75 return propertyName + ':' + generate(declaration.value);
76 }
77
78 var declarationId = declaration.id;
79 var fingerprint = fingerprints[declarationId];
80
81 if (!fingerprint) {
82 switch (declaration.value.type) {
83 case 'Value':
84 var vendorId = '';
85 var iehack = '';
86 var special = {};
87 var raw = false;
88
89 declaration.value.children.each(function walk(node) {
90 switch (node.type) {
91 case 'Value':
92 case 'Brackets':
93 case 'Parentheses':
94 node.children.each(walk);
95 break;
96
97 case 'Raw':
98 raw = true;
99 break;
100
101 case 'Identifier':
102 var name = node.name;
103
104 if (!vendorId) {
105 vendorId = resolveKeyword(name).vendor;
106 }
107
108 if (/\\[09]/.test(name)) {
109 iehack = RegExp.lastMatch;
110 }
111
112 if (SAFE_VALUES.hasOwnProperty(realName)) {
113 if (SAFE_VALUES[realName].indexOf(name) === -1) {
114 special[name] = true;
115 }
116 } else if (DONT_MIX_VALUE.hasOwnProperty(realName)) {
117 if (DONT_MIX_VALUE[realName].test(name)) {
118 special[name] = true;
119 }
120 }
121
122 break;
123
124 case 'Function':
125 var name = node.name;
126
127 if (!vendorId) {
128 vendorId = resolveKeyword(name).vendor;
129 }
130
131 if (name === 'rect') {
132 // there are 2 forms of rect:
133 // rect(<top>, <right>, <bottom>, <left>) - standart
134 // rect(<top> <right> <bottom> <left>) – backwards compatible syntax
135 // only the same form values can be merged
136 var hasComma = node.children.some(function(node) {
137 return node.type === 'Operator' && node.value === ',';
138 });
139 if (!hasComma) {
140 name = 'rect-backward';
141 }
142 }
143
144 special[name + '()'] = true;
145
146 // check nested tokens too
147 node.children.each(walk);
148
149 break;
150
151 case 'Dimension':
152 var unit = node.unit;
153
154 if (/\\[09]/.test(unit)) {
155 iehack = RegExp.lastMatch;
156 }
157
158 switch (unit) {
159 // is not supported until IE11
160 case 'rem':
161
162 // v* units is too buggy across browsers and better
163 // don't merge values with those units
164 case 'vw':
165 case 'vh':
166 case 'vmin':
167 case 'vmax':
168 case 'vm': // IE9 supporting "vm" instead of "vmin".
169 special[unit] = true;
170 break;
171 }
172 break;
173 }
174 });
175
176 fingerprint = raw
177 ? '!' + fingerprintId++
178 : '!' + Object.keys(special).sort() + '|' + iehack + vendorId;
179 break;
180
181 case 'Raw':
182 fingerprint = '!' + declaration.value.value;
183 break;
184
185 default:
186 fingerprint = generate(declaration.value);
187 }
188
189 fingerprints[declarationId] = fingerprint;
190 }
191
192 return propertyName + fingerprint;
193}
194
195function needless(props, declaration, fingerprints) {
196 var property = resolveProperty(declaration.property);
197
198 if (NEEDLESS_TABLE.hasOwnProperty(property.basename)) {
199 var table = NEEDLESS_TABLE[property.basename];
200
201 for (var i = 0; i < table.length; i++) {
202 var ppre = getPropertyFingerprint(property.prefix + table[i], declaration, fingerprints);
203 var prev = props.hasOwnProperty(ppre) ? props[ppre] : null;
204
205 if (prev && (!declaration.important || prev.item.data.important)) {
206 return prev;
207 }
208 }
209 }
210}
211
212function processRule(rule, item, list, props, fingerprints) {
213 var declarations = rule.block.children;
214
215 declarations.eachRight(function(declaration, declarationItem) {
216 var property = declaration.property;
217 var fingerprint = getPropertyFingerprint(property, declaration, fingerprints);
218 var prev = props[fingerprint];
219
220 if (prev && !dontRestructure.hasOwnProperty(property)) {
221 if (declaration.important && !prev.item.data.important) {
222 props[fingerprint] = {
223 block: declarations,
224 item: declarationItem
225 };
226
227 prev.block.remove(prev.item);
228
229 // TODO: use it when we can refer to several points in source
230 // declaration.loc = {
231 // primary: declaration.loc,
232 // merged: prev.item.data.loc
233 // };
234 } else {
235 declarations.remove(declarationItem);
236
237 // TODO: use it when we can refer to several points in source
238 // prev.item.data.loc = {
239 // primary: prev.item.data.loc,
240 // merged: declaration.loc
241 // };
242 }
243 } else {
244 var prev = needless(props, declaration, fingerprints);
245
246 if (prev) {
247 declarations.remove(declarationItem);
248
249 // TODO: use it when we can refer to several points in source
250 // prev.item.data.loc = {
251 // primary: prev.item.data.loc,
252 // merged: declaration.loc
253 // };
254 } else {
255 declaration.fingerprint = fingerprint;
256
257 props[fingerprint] = {
258 block: declarations,
259 item: declarationItem
260 };
261 }
262 }
263 });
264
265 if (declarations.isEmpty()) {
266 list.remove(item);
267 }
268}
269
270module.exports = function restructBlock(ast) {
271 var stylesheetMap = {};
272 var fingerprints = Object.create(null);
273
274 walk(ast, {
275 visit: 'Rule',
276 reverse: true,
277 enter: function(node, item, list) {
278 var stylesheet = this.block || this.stylesheet;
279 var ruleId = (node.pseudoSignature || '') + '|' + node.prelude.children.first().id;
280 var ruleMap;
281 var props;
282
283 if (!stylesheetMap.hasOwnProperty(stylesheet.id)) {
284 ruleMap = {};
285 stylesheetMap[stylesheet.id] = ruleMap;
286 } else {
287 ruleMap = stylesheetMap[stylesheet.id];
288 }
289
290 if (ruleMap.hasOwnProperty(ruleId)) {
291 props = ruleMap[ruleId];
292 } else {
293 props = {};
294 ruleMap[ruleId] = props;
295 }
296
297 processRule.call(this, node, item, list, props, fingerprints);
298 }
299 });
300};
Note: See TracBrowser for help on using the repository browser.