1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | var tslib_1 = require("tslib");
|
4 | var tree_1 = tslib_1.__importDefault(require("../tree"));
|
5 | var visitor_1 = tslib_1.__importDefault(require("./visitor"));
|
6 | var logger_1 = tslib_1.__importDefault(require("../logger"));
|
7 | var utils = tslib_1.__importStar(require("../utils"));
|
8 |
|
9 | var ExtendFinderVisitor = (function () {
|
10 | function ExtendFinderVisitor() {
|
11 | this._visitor = new visitor_1.default(this);
|
12 | this.contexts = [];
|
13 | this.allExtendsStack = [[]];
|
14 | }
|
15 | ExtendFinderVisitor.prototype.run = function (root) {
|
16 | root = this._visitor.visit(root);
|
17 | root.allExtends = this.allExtendsStack[0];
|
18 | return root;
|
19 | };
|
20 | ExtendFinderVisitor.prototype.visitDeclaration = function (declNode, visitArgs) {
|
21 | visitArgs.visitDeeper = false;
|
22 | };
|
23 | ExtendFinderVisitor.prototype.visitMixinDefinition = function (mixinDefinitionNode, visitArgs) {
|
24 | visitArgs.visitDeeper = false;
|
25 | };
|
26 | ExtendFinderVisitor.prototype.visitRuleset = function (rulesetNode, visitArgs) {
|
27 | if (rulesetNode.root) {
|
28 | return;
|
29 | }
|
30 | var i;
|
31 | var j;
|
32 | var extend;
|
33 | var allSelectorsExtendList = [];
|
34 | var extendList;
|
35 |
|
36 | var rules = rulesetNode.rules, ruleCnt = rules ? rules.length : 0;
|
37 | for (i = 0; i < ruleCnt; i++) {
|
38 | if (rulesetNode.rules[i] instanceof tree_1.default.Extend) {
|
39 | allSelectorsExtendList.push(rules[i]);
|
40 | rulesetNode.extendOnEveryPath = true;
|
41 | }
|
42 | }
|
43 |
|
44 |
|
45 | var paths = rulesetNode.paths;
|
46 | for (i = 0; i < paths.length; i++) {
|
47 | var selectorPath = paths[i], selector = selectorPath[selectorPath.length - 1], selExtendList = selector.extendList;
|
48 | extendList = selExtendList ? utils.copyArray(selExtendList).concat(allSelectorsExtendList)
|
49 | : allSelectorsExtendList;
|
50 | if (extendList) {
|
51 | extendList = extendList.map(function (allSelectorsExtend) {
|
52 | return allSelectorsExtend.clone();
|
53 | });
|
54 | }
|
55 | for (j = 0; j < extendList.length; j++) {
|
56 | this.foundExtends = true;
|
57 | extend = extendList[j];
|
58 | extend.findSelfSelectors(selectorPath);
|
59 | extend.ruleset = rulesetNode;
|
60 | if (j === 0) {
|
61 | extend.firstExtendOnThisSelectorPath = true;
|
62 | }
|
63 | this.allExtendsStack[this.allExtendsStack.length - 1].push(extend);
|
64 | }
|
65 | }
|
66 | this.contexts.push(rulesetNode.selectors);
|
67 | };
|
68 | ExtendFinderVisitor.prototype.visitRulesetOut = function (rulesetNode) {
|
69 | if (!rulesetNode.root) {
|
70 | this.contexts.length = this.contexts.length - 1;
|
71 | }
|
72 | };
|
73 | ExtendFinderVisitor.prototype.visitMedia = function (mediaNode, visitArgs) {
|
74 | mediaNode.allExtends = [];
|
75 | this.allExtendsStack.push(mediaNode.allExtends);
|
76 | };
|
77 | ExtendFinderVisitor.prototype.visitMediaOut = function (mediaNode) {
|
78 | this.allExtendsStack.length = this.allExtendsStack.length - 1;
|
79 | };
|
80 | ExtendFinderVisitor.prototype.visitAtRule = function (atRuleNode, visitArgs) {
|
81 | atRuleNode.allExtends = [];
|
82 | this.allExtendsStack.push(atRuleNode.allExtends);
|
83 | };
|
84 | ExtendFinderVisitor.prototype.visitAtRuleOut = function (atRuleNode) {
|
85 | this.allExtendsStack.length = this.allExtendsStack.length - 1;
|
86 | };
|
87 | return ExtendFinderVisitor;
|
88 | }());
|
89 | var ProcessExtendsVisitor = (function () {
|
90 | function ProcessExtendsVisitor() {
|
91 | this._visitor = new visitor_1.default(this);
|
92 | }
|
93 | ProcessExtendsVisitor.prototype.run = function (root) {
|
94 | var extendFinder = new ExtendFinderVisitor();
|
95 | this.extendIndices = {};
|
96 | extendFinder.run(root);
|
97 | if (!extendFinder.foundExtends) {
|
98 | return root;
|
99 | }
|
100 | root.allExtends = root.allExtends.concat(this.doExtendChaining(root.allExtends, root.allExtends));
|
101 | this.allExtendsStack = [root.allExtends];
|
102 | var newRoot = this._visitor.visit(root);
|
103 | this.checkExtendsForNonMatched(root.allExtends);
|
104 | return newRoot;
|
105 | };
|
106 | ProcessExtendsVisitor.prototype.checkExtendsForNonMatched = function (extendList) {
|
107 | var indices = this.extendIndices;
|
108 | extendList.filter(function (extend) {
|
109 | return !extend.hasFoundMatches && extend.parent_ids.length == 1;
|
110 | }).forEach(function (extend) {
|
111 | var selector = '_unknown_';
|
112 | try {
|
113 | selector = extend.selector.toCSS({});
|
114 | }
|
115 | catch (_) { }
|
116 | if (!indices[extend.index + " " + selector]) {
|
117 | indices[extend.index + " " + selector] = true;
|
118 | logger_1.default.warn("extend '" + selector + "' has no matches");
|
119 | }
|
120 | });
|
121 | };
|
122 | ProcessExtendsVisitor.prototype.doExtendChaining = function (extendsList, extendsListTarget, iterationCount) {
|
123 |
|
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 |
|
131 | var extendIndex;
|
132 | var targetExtendIndex;
|
133 | var matches;
|
134 | var extendsToAdd = [];
|
135 | var newSelector;
|
136 | var extendVisitor = this;
|
137 | var selectorPath;
|
138 | var extend;
|
139 | var targetExtend;
|
140 | var newExtend;
|
141 | iterationCount = iterationCount || 0;
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 | for (extendIndex = 0; extendIndex < extendsList.length; extendIndex++) {
|
149 | for (targetExtendIndex = 0; targetExtendIndex < extendsListTarget.length; targetExtendIndex++) {
|
150 | extend = extendsList[extendIndex];
|
151 | targetExtend = extendsListTarget[targetExtendIndex];
|
152 |
|
153 | if (extend.parent_ids.indexOf(targetExtend.object_id) >= 0) {
|
154 | continue;
|
155 | }
|
156 |
|
157 | selectorPath = [targetExtend.selfSelectors[0]];
|
158 | matches = extendVisitor.findMatch(extend, selectorPath);
|
159 | if (matches.length) {
|
160 | extend.hasFoundMatches = true;
|
161 |
|
162 | extend.selfSelectors.forEach(function (selfSelector) {
|
163 | var info = targetExtend.visibilityInfo();
|
164 |
|
165 | newSelector = extendVisitor.extendSelector(matches, selectorPath, selfSelector, extend.isVisible());
|
166 |
|
167 | newExtend = new (tree_1.default.Extend)(targetExtend.selector, targetExtend.option, 0, targetExtend.fileInfo(), info);
|
168 | newExtend.selfSelectors = newSelector;
|
169 |
|
170 | newSelector[newSelector.length - 1].extendList = [newExtend];
|
171 |
|
172 | extendsToAdd.push(newExtend);
|
173 | newExtend.ruleset = targetExtend.ruleset;
|
174 |
|
175 | newExtend.parent_ids = newExtend.parent_ids.concat(targetExtend.parent_ids, extend.parent_ids);
|
176 |
|
177 |
|
178 |
|
179 | if (targetExtend.firstExtendOnThisSelectorPath) {
|
180 | newExtend.firstExtendOnThisSelectorPath = true;
|
181 | targetExtend.ruleset.paths.push(newSelector);
|
182 | }
|
183 | });
|
184 | }
|
185 | }
|
186 | }
|
187 | if (extendsToAdd.length) {
|
188 |
|
189 |
|
190 | this.extendChainCount++;
|
191 | if (iterationCount > 100) {
|
192 | var selectorOne = '{unable to calculate}';
|
193 | var selectorTwo = '{unable to calculate}';
|
194 | try {
|
195 | selectorOne = extendsToAdd[0].selfSelectors[0].toCSS();
|
196 | selectorTwo = extendsToAdd[0].selector.toCSS();
|
197 | }
|
198 | catch (e) { }
|
199 | throw { message: "extend circular reference detected. One of the circular extends is currently:" + selectorOne + ":extend(" + selectorTwo + ")" };
|
200 | }
|
201 |
|
202 |
|
203 | return extendsToAdd.concat(extendVisitor.doExtendChaining(extendsToAdd, extendsListTarget, iterationCount + 1));
|
204 | }
|
205 | else {
|
206 | return extendsToAdd;
|
207 | }
|
208 | };
|
209 | ProcessExtendsVisitor.prototype.visitDeclaration = function (ruleNode, visitArgs) {
|
210 | visitArgs.visitDeeper = false;
|
211 | };
|
212 | ProcessExtendsVisitor.prototype.visitMixinDefinition = function (mixinDefinitionNode, visitArgs) {
|
213 | visitArgs.visitDeeper = false;
|
214 | };
|
215 | ProcessExtendsVisitor.prototype.visitSelector = function (selectorNode, visitArgs) {
|
216 | visitArgs.visitDeeper = false;
|
217 | };
|
218 | ProcessExtendsVisitor.prototype.visitRuleset = function (rulesetNode, visitArgs) {
|
219 | if (rulesetNode.root) {
|
220 | return;
|
221 | }
|
222 | var matches;
|
223 | var pathIndex;
|
224 | var extendIndex;
|
225 | var allExtends = this.allExtendsStack[this.allExtendsStack.length - 1];
|
226 | var selectorsToAdd = [];
|
227 | var extendVisitor = this;
|
228 | var selectorPath;
|
229 |
|
230 | for (extendIndex = 0; extendIndex < allExtends.length; extendIndex++) {
|
231 | for (pathIndex = 0; pathIndex < rulesetNode.paths.length; pathIndex++) {
|
232 | selectorPath = rulesetNode.paths[pathIndex];
|
233 |
|
234 | if (rulesetNode.extendOnEveryPath) {
|
235 | continue;
|
236 | }
|
237 | var extendList = selectorPath[selectorPath.length - 1].extendList;
|
238 | if (extendList && extendList.length) {
|
239 | continue;
|
240 | }
|
241 | matches = this.findMatch(allExtends[extendIndex], selectorPath);
|
242 | if (matches.length) {
|
243 | allExtends[extendIndex].hasFoundMatches = true;
|
244 | allExtends[extendIndex].selfSelectors.forEach(function (selfSelector) {
|
245 | var extendedSelectors;
|
246 | extendedSelectors = extendVisitor.extendSelector(matches, selectorPath, selfSelector, allExtends[extendIndex].isVisible());
|
247 | selectorsToAdd.push(extendedSelectors);
|
248 | });
|
249 | }
|
250 | }
|
251 | }
|
252 | rulesetNode.paths = rulesetNode.paths.concat(selectorsToAdd);
|
253 | };
|
254 | ProcessExtendsVisitor.prototype.findMatch = function (extend, haystackSelectorPath) {
|
255 |
|
256 |
|
257 |
|
258 |
|
259 | var haystackSelectorIndex;
|
260 | var hackstackSelector;
|
261 | var hackstackElementIndex;
|
262 | var haystackElement;
|
263 | var targetCombinator;
|
264 | var i;
|
265 | var extendVisitor = this;
|
266 | var needleElements = extend.selector.elements;
|
267 | var potentialMatches = [];
|
268 | var potentialMatch;
|
269 | var matches = [];
|
270 |
|
271 | for (haystackSelectorIndex = 0; haystackSelectorIndex < haystackSelectorPath.length; haystackSelectorIndex++) {
|
272 | hackstackSelector = haystackSelectorPath[haystackSelectorIndex];
|
273 | for (hackstackElementIndex = 0; hackstackElementIndex < hackstackSelector.elements.length; hackstackElementIndex++) {
|
274 | haystackElement = hackstackSelector.elements[hackstackElementIndex];
|
275 |
|
276 | if (extend.allowBefore || (haystackSelectorIndex === 0 && hackstackElementIndex === 0)) {
|
277 | potentialMatches.push({ pathIndex: haystackSelectorIndex, index: hackstackElementIndex, matched: 0,
|
278 | initialCombinator: haystackElement.combinator });
|
279 | }
|
280 | for (i = 0; i < potentialMatches.length; i++) {
|
281 | potentialMatch = potentialMatches[i];
|
282 |
|
283 |
|
284 |
|
285 | targetCombinator = haystackElement.combinator.value;
|
286 | if (targetCombinator === '' && hackstackElementIndex === 0) {
|
287 | targetCombinator = ' ';
|
288 | }
|
289 |
|
290 | if (!extendVisitor.isElementValuesEqual(needleElements[potentialMatch.matched].value, haystackElement.value) ||
|
291 | (potentialMatch.matched > 0 && needleElements[potentialMatch.matched].combinator.value !== targetCombinator)) {
|
292 | potentialMatch = null;
|
293 | }
|
294 | else {
|
295 | potentialMatch.matched++;
|
296 | }
|
297 |
|
298 | if (potentialMatch) {
|
299 | potentialMatch.finished = potentialMatch.matched === needleElements.length;
|
300 | if (potentialMatch.finished &&
|
301 | (!extend.allowAfter &&
|
302 | (hackstackElementIndex + 1 < hackstackSelector.elements.length || haystackSelectorIndex + 1 < haystackSelectorPath.length))) {
|
303 | potentialMatch = null;
|
304 | }
|
305 | }
|
306 |
|
307 | if (potentialMatch) {
|
308 | if (potentialMatch.finished) {
|
309 | potentialMatch.length = needleElements.length;
|
310 | potentialMatch.endPathIndex = haystackSelectorIndex;
|
311 | potentialMatch.endPathElementIndex = hackstackElementIndex + 1;
|
312 | potentialMatches.length = 0;
|
313 | matches.push(potentialMatch);
|
314 | }
|
315 | }
|
316 | else {
|
317 | potentialMatches.splice(i, 1);
|
318 | i--;
|
319 | }
|
320 | }
|
321 | }
|
322 | }
|
323 | return matches;
|
324 | };
|
325 | ProcessExtendsVisitor.prototype.isElementValuesEqual = function (elementValue1, elementValue2) {
|
326 | if (typeof elementValue1 === 'string' || typeof elementValue2 === 'string') {
|
327 | return elementValue1 === elementValue2;
|
328 | }
|
329 | if (elementValue1 instanceof tree_1.default.Attribute) {
|
330 | if (elementValue1.op !== elementValue2.op || elementValue1.key !== elementValue2.key) {
|
331 | return false;
|
332 | }
|
333 | if (!elementValue1.value || !elementValue2.value) {
|
334 | if (elementValue1.value || elementValue2.value) {
|
335 | return false;
|
336 | }
|
337 | return true;
|
338 | }
|
339 | elementValue1 = elementValue1.value.value || elementValue1.value;
|
340 | elementValue2 = elementValue2.value.value || elementValue2.value;
|
341 | return elementValue1 === elementValue2;
|
342 | }
|
343 | elementValue1 = elementValue1.value;
|
344 | elementValue2 = elementValue2.value;
|
345 | if (elementValue1 instanceof tree_1.default.Selector) {
|
346 | if (!(elementValue2 instanceof tree_1.default.Selector) || elementValue1.elements.length !== elementValue2.elements.length) {
|
347 | return false;
|
348 | }
|
349 | for (var i = 0; i < elementValue1.elements.length; i++) {
|
350 | if (elementValue1.elements[i].combinator.value !== elementValue2.elements[i].combinator.value) {
|
351 | if (i !== 0 || (elementValue1.elements[i].combinator.value || ' ') !== (elementValue2.elements[i].combinator.value || ' ')) {
|
352 | return false;
|
353 | }
|
354 | }
|
355 | if (!this.isElementValuesEqual(elementValue1.elements[i].value, elementValue2.elements[i].value)) {
|
356 | return false;
|
357 | }
|
358 | }
|
359 | return true;
|
360 | }
|
361 | return false;
|
362 | };
|
363 | ProcessExtendsVisitor.prototype.extendSelector = function (matches, selectorPath, replacementSelector, isVisible) {
|
364 |
|
365 | var currentSelectorPathIndex = 0, currentSelectorPathElementIndex = 0, path = [], matchIndex, selector, firstElement, match, newElements;
|
366 | for (matchIndex = 0; matchIndex < matches.length; matchIndex++) {
|
367 | match = matches[matchIndex];
|
368 | selector = selectorPath[match.pathIndex];
|
369 | firstElement = new tree_1.default.Element(match.initialCombinator, replacementSelector.elements[0].value, replacementSelector.elements[0].isVariable, replacementSelector.elements[0].getIndex(), replacementSelector.elements[0].fileInfo());
|
370 | if (match.pathIndex > currentSelectorPathIndex && currentSelectorPathElementIndex > 0) {
|
371 | path[path.length - 1].elements = path[path.length - 1]
|
372 | .elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
|
373 | currentSelectorPathElementIndex = 0;
|
374 | currentSelectorPathIndex++;
|
375 | }
|
376 | newElements = selector.elements
|
377 | .slice(currentSelectorPathElementIndex, match.index)
|
378 | .concat([firstElement])
|
379 | .concat(replacementSelector.elements.slice(1));
|
380 | if (currentSelectorPathIndex === match.pathIndex && matchIndex > 0) {
|
381 | path[path.length - 1].elements =
|
382 | path[path.length - 1].elements.concat(newElements);
|
383 | }
|
384 | else {
|
385 | path = path.concat(selectorPath.slice(currentSelectorPathIndex, match.pathIndex));
|
386 | path.push(new tree_1.default.Selector(newElements));
|
387 | }
|
388 | currentSelectorPathIndex = match.endPathIndex;
|
389 | currentSelectorPathElementIndex = match.endPathElementIndex;
|
390 | if (currentSelectorPathElementIndex >= selectorPath[currentSelectorPathIndex].elements.length) {
|
391 | currentSelectorPathElementIndex = 0;
|
392 | currentSelectorPathIndex++;
|
393 | }
|
394 | }
|
395 | if (currentSelectorPathIndex < selectorPath.length && currentSelectorPathElementIndex > 0) {
|
396 | path[path.length - 1].elements = path[path.length - 1]
|
397 | .elements.concat(selectorPath[currentSelectorPathIndex].elements.slice(currentSelectorPathElementIndex));
|
398 | currentSelectorPathIndex++;
|
399 | }
|
400 | path = path.concat(selectorPath.slice(currentSelectorPathIndex, selectorPath.length));
|
401 | path = path.map(function (currentValue) {
|
402 |
|
403 | var derived = currentValue.createDerived(currentValue.elements);
|
404 | if (isVisible) {
|
405 | derived.ensureVisibility();
|
406 | }
|
407 | else {
|
408 | derived.ensureInvisibility();
|
409 | }
|
410 | return derived;
|
411 | });
|
412 | return path;
|
413 | };
|
414 | ProcessExtendsVisitor.prototype.visitMedia = function (mediaNode, visitArgs) {
|
415 | var newAllExtends = mediaNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]);
|
416 | newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, mediaNode.allExtends));
|
417 | this.allExtendsStack.push(newAllExtends);
|
418 | };
|
419 | ProcessExtendsVisitor.prototype.visitMediaOut = function (mediaNode) {
|
420 | var lastIndex = this.allExtendsStack.length - 1;
|
421 | this.allExtendsStack.length = lastIndex;
|
422 | };
|
423 | ProcessExtendsVisitor.prototype.visitAtRule = function (atRuleNode, visitArgs) {
|
424 | var newAllExtends = atRuleNode.allExtends.concat(this.allExtendsStack[this.allExtendsStack.length - 1]);
|
425 | newAllExtends = newAllExtends.concat(this.doExtendChaining(newAllExtends, atRuleNode.allExtends));
|
426 | this.allExtendsStack.push(newAllExtends);
|
427 | };
|
428 | ProcessExtendsVisitor.prototype.visitAtRuleOut = function (atRuleNode) {
|
429 | var lastIndex = this.allExtendsStack.length - 1;
|
430 | this.allExtendsStack.length = lastIndex;
|
431 | };
|
432 | return ProcessExtendsVisitor;
|
433 | }());
|
434 | exports.default = ProcessExtendsVisitor;
|
435 |
|
\ | No newline at end of file |