source: imaps-frontend/node_modules/clean-css/lib/optimizer/level-2/is-mergeable.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: 7.0 KB
Line 
1var Marker = require('../../tokenizer/marker');
2var split = require('../../utils/split');
3
4var DEEP_SELECTOR_PATTERN = /\/deep\//;
5var DOUBLE_COLON_PATTERN = /^::/;
6var VENDOR_PREFIXED_PATTERN = /:(-moz-|-ms-|-o-|-webkit-)/;
7
8var NOT_PSEUDO = ':not';
9var PSEUDO_CLASSES_WITH_ARGUMENTS = [
10 ':dir',
11 ':lang',
12 ':not',
13 ':nth-child',
14 ':nth-last-child',
15 ':nth-last-of-type',
16 ':nth-of-type'
17];
18var RELATION_PATTERN = /[>+~]/;
19var UNMIXABLE_PSEUDO_CLASSES = [
20 ':after',
21 ':before',
22 ':first-letter',
23 ':first-line',
24 ':lang'
25];
26var UNMIXABLE_PSEUDO_ELEMENTS = [
27 '::after',
28 '::before',
29 '::first-letter',
30 '::first-line'
31];
32
33var Level = {
34 DOUBLE_QUOTE: 'double-quote',
35 SINGLE_QUOTE: 'single-quote',
36 ROOT: 'root'
37};
38
39function isMergeable(selector, mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging) {
40 var singleSelectors = split(selector, Marker.COMMA);
41 var singleSelector;
42 var i, l;
43
44 for (i = 0, l = singleSelectors.length; i < l; i++) {
45 singleSelector = singleSelectors[i];
46
47 if (singleSelector.length === 0
48 || isDeepSelector(singleSelector)
49 || isVendorPrefixed(singleSelector)
50 || (singleSelector.indexOf(Marker.COLON) > -1
51 && !areMergeable(
52 singleSelector,
53 extractPseudoFrom(singleSelector),
54 mergeablePseudoClasses,
55 mergeablePseudoElements,
56 multiplePseudoMerging
57 ))) {
58 return false;
59 }
60 }
61
62 return true;
63}
64
65function isDeepSelector(selector) {
66 return DEEP_SELECTOR_PATTERN.test(selector);
67}
68
69function isVendorPrefixed(selector) {
70 return VENDOR_PREFIXED_PATTERN.test(selector);
71}
72
73function extractPseudoFrom(selector) {
74 var list = [];
75 var character;
76 var buffer = [];
77 var level = Level.ROOT;
78 var roundBracketLevel = 0;
79 var isQuoted;
80 var isEscaped;
81 var isPseudo = false;
82 var isRelation;
83 var wasColon = false;
84 var index;
85 var len;
86
87 for (index = 0, len = selector.length; index < len; index++) {
88 character = selector[index];
89
90 isRelation = !isEscaped && RELATION_PATTERN.test(character);
91 isQuoted = level == Level.DOUBLE_QUOTE || level == Level.SINGLE_QUOTE;
92
93 if (isEscaped) {
94 buffer.push(character);
95 } else if (character == Marker.DOUBLE_QUOTE && level == Level.ROOT) {
96 buffer.push(character);
97 level = Level.DOUBLE_QUOTE;
98 } else if (character == Marker.DOUBLE_QUOTE && level == Level.DOUBLE_QUOTE) {
99 buffer.push(character);
100 level = Level.ROOT;
101 } else if (character == Marker.SINGLE_QUOTE && level == Level.ROOT) {
102 buffer.push(character);
103 level = Level.SINGLE_QUOTE;
104 } else if (character == Marker.SINGLE_QUOTE && level == Level.SINGLE_QUOTE) {
105 buffer.push(character);
106 level = Level.ROOT;
107 } else if (isQuoted) {
108 buffer.push(character);
109 } else if (character == Marker.OPEN_ROUND_BRACKET) {
110 buffer.push(character);
111 roundBracketLevel++;
112 } else if (character == Marker.CLOSE_ROUND_BRACKET && roundBracketLevel == 1 && isPseudo) {
113 buffer.push(character);
114 list.push(buffer.join(''));
115 roundBracketLevel--;
116 buffer = [];
117 isPseudo = false;
118 } else if (character == Marker.CLOSE_ROUND_BRACKET) {
119 buffer.push(character);
120 roundBracketLevel--;
121 } else if (character == Marker.COLON && roundBracketLevel === 0 && isPseudo && !wasColon) {
122 list.push(buffer.join(''));
123 buffer = [];
124 buffer.push(character);
125 } else if (character == Marker.COLON && roundBracketLevel === 0 && !wasColon) {
126 buffer = [];
127 buffer.push(character);
128 isPseudo = true;
129 } else if (character == Marker.SPACE && roundBracketLevel === 0 && isPseudo) {
130 list.push(buffer.join(''));
131 buffer = [];
132 isPseudo = false;
133 } else if (isRelation && roundBracketLevel === 0 && isPseudo) {
134 list.push(buffer.join(''));
135 buffer = [];
136 isPseudo = false;
137 } else {
138 buffer.push(character);
139 }
140
141 isEscaped = character == Marker.BACK_SLASH;
142 wasColon = character == Marker.COLON;
143 }
144
145 if (buffer.length > 0 && isPseudo) {
146 list.push(buffer.join(''));
147 }
148
149 return list;
150}
151
152function areMergeable(selector, matches, mergeablePseudoClasses, mergeablePseudoElements, multiplePseudoMerging) {
153 return areAllowed(matches, mergeablePseudoClasses, mergeablePseudoElements)
154 && needArguments(matches)
155 && (matches.length < 2 || !someIncorrectlyChained(selector, matches))
156 && (matches.length < 2 || multiplePseudoMerging && allMixable(matches));
157}
158
159function areAllowed(matches, mergeablePseudoClasses, mergeablePseudoElements) {
160 var match;
161 var name;
162 var i, l;
163
164 for (i = 0, l = matches.length; i < l; i++) {
165 match = matches[i];
166 name = match.indexOf(Marker.OPEN_ROUND_BRACKET) > -1
167 ? match.substring(0, match.indexOf(Marker.OPEN_ROUND_BRACKET))
168 : match;
169
170 if (mergeablePseudoClasses.indexOf(name) === -1 && mergeablePseudoElements.indexOf(name) === -1) {
171 return false;
172 }
173 }
174
175 return true;
176}
177
178function needArguments(matches) {
179 var match;
180 var name;
181 var bracketOpensAt;
182 var hasArguments;
183 var i, l;
184
185 for (i = 0, l = matches.length; i < l; i++) {
186 match = matches[i];
187
188 bracketOpensAt = match.indexOf(Marker.OPEN_ROUND_BRACKET);
189 hasArguments = bracketOpensAt > -1;
190 name = hasArguments
191 ? match.substring(0, bracketOpensAt)
192 : match;
193
194 if (hasArguments && PSEUDO_CLASSES_WITH_ARGUMENTS.indexOf(name) == -1) {
195 return false;
196 }
197
198 if (!hasArguments && PSEUDO_CLASSES_WITH_ARGUMENTS.indexOf(name) > -1) {
199 return false;
200 }
201 }
202
203 return true;
204}
205
206function someIncorrectlyChained(selector, matches) {
207 var positionInSelector = 0;
208 var match;
209 var matchAt;
210 var nextMatch;
211 var nextMatchAt;
212 var name;
213 var nextName;
214 var areChained;
215 var i, l;
216
217 for (i = 0, l = matches.length; i < l; i++) {
218 match = matches[i];
219 nextMatch = matches[i + 1];
220
221 if (!nextMatch) {
222 break;
223 }
224
225 matchAt = selector.indexOf(match, positionInSelector);
226 nextMatchAt = selector.indexOf(match, matchAt + 1);
227 positionInSelector = nextMatchAt;
228 areChained = matchAt + match.length == nextMatchAt;
229
230 if (areChained) {
231 name = match.indexOf(Marker.OPEN_ROUND_BRACKET) > -1
232 ? match.substring(0, match.indexOf(Marker.OPEN_ROUND_BRACKET))
233 : match;
234 nextName = nextMatch.indexOf(Marker.OPEN_ROUND_BRACKET) > -1
235 ? nextMatch.substring(0, nextMatch.indexOf(Marker.OPEN_ROUND_BRACKET))
236 : nextMatch;
237
238 if (name != NOT_PSEUDO || nextName != NOT_PSEUDO) {
239 return true;
240 }
241 }
242 }
243
244 return false;
245}
246
247function allMixable(matches) {
248 var unmixableMatches = 0;
249 var match;
250 var i, l;
251
252 for (i = 0, l = matches.length; i < l; i++) {
253 match = matches[i];
254
255 if (isPseudoElement(match)) {
256 unmixableMatches += UNMIXABLE_PSEUDO_ELEMENTS.indexOf(match) > -1 ? 1 : 0;
257 } else {
258 unmixableMatches += UNMIXABLE_PSEUDO_CLASSES.indexOf(match) > -1 ? 1 : 0;
259 }
260
261 if (unmixableMatches > 1) {
262 return false;
263 }
264 }
265
266 return true;
267}
268
269function isPseudoElement(pseudo) {
270 return DOUBLE_COLON_PATTERN.test(pseudo);
271}
272
273module.exports = isMergeable;
Note: See TracBrowser for help on using the repository browser.