1 | import { off } from "process";
|
2 | import { modifiers } from "../src/compiler/theme.imba";
|
3 | import { TAG_NAMES } from '../src/compiler/constants.imba1';
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 | function CssSelectorParser() {
|
27 | this.pseudos = {};
|
28 | this.attrEqualityMods = {};
|
29 | this.ruleNestingOperators = {};
|
30 | this.substitutesEnabled = false;
|
31 | }
|
32 |
|
33 | function RULE(obj,base=[]){
|
34 | return Object.assign(base,obj);
|
35 | }
|
36 |
|
37 | CssSelectorParser.prototype.registerSelectorPseudos = function(name) {
|
38 | for (var j = 0, len = arguments.length; j < len; j++) {
|
39 | name = arguments[j];
|
40 | this.pseudos[name] = 'selector';
|
41 | }
|
42 | return this;
|
43 | };
|
44 |
|
45 | CssSelectorParser.prototype.unregisterSelectorPseudos = function(name) {
|
46 | for (var j = 0, len = arguments.length; j < len; j++) {
|
47 | name = arguments[j];
|
48 | delete this.pseudos[name];
|
49 | }
|
50 | return this;
|
51 | };
|
52 |
|
53 | CssSelectorParser.prototype.registerNumericPseudos = function(name) {
|
54 | for (var j = 0, len = arguments.length; j < len; j++) {
|
55 | name = arguments[j];
|
56 | this.pseudos[name] = 'numeric';
|
57 | }
|
58 | return this;
|
59 | };
|
60 |
|
61 | CssSelectorParser.prototype.unregisterNumericPseudos = function(name) {
|
62 | for (var j = 0, len = arguments.length; j < len; j++) {
|
63 | name = arguments[j];
|
64 | delete this.pseudos[name];
|
65 | }
|
66 | return this;
|
67 | };
|
68 |
|
69 | CssSelectorParser.prototype.registerNestingOperators = function(operator) {
|
70 | for (var j = 0, len = arguments.length; j < len; j++) {
|
71 | operator = arguments[j];
|
72 | this.ruleNestingOperators[operator] = true;
|
73 | }
|
74 | return this;
|
75 | };
|
76 |
|
77 | CssSelectorParser.prototype.unregisterNestingOperators = function(operator) {
|
78 | for (var j = 0, len = arguments.length; j < len; j++) {
|
79 | operator = arguments[j];
|
80 | delete this.ruleNestingOperators[operator];
|
81 | }
|
82 | return this;
|
83 | };
|
84 |
|
85 | CssSelectorParser.prototype.registerAttrEqualityMods = function(mod) {
|
86 | for (var j = 0, len = arguments.length; j < len; j++) {
|
87 | mod = arguments[j];
|
88 | this.attrEqualityMods[mod] = true;
|
89 | }
|
90 | return this;
|
91 | };
|
92 |
|
93 | CssSelectorParser.prototype.unregisterAttrEqualityMods = function(mod) {
|
94 | for (var j = 0, len = arguments.length; j < len; j++) {
|
95 | mod = arguments[j];
|
96 | delete this.attrEqualityMods[mod];
|
97 | }
|
98 | return this;
|
99 | };
|
100 |
|
101 | CssSelectorParser.prototype.enableSubstitutes = function() {
|
102 | this.substitutesEnabled = true;
|
103 | return this;
|
104 | };
|
105 |
|
106 | CssSelectorParser.prototype.disableSubstitutes = function() {
|
107 | this.substitutesEnabled = false;
|
108 | return this;
|
109 | };
|
110 |
|
111 | function isIdentStart(c) {
|
112 | return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c === '-') || (c === '_');
|
113 | }
|
114 |
|
115 | function isIdent(c) {
|
116 | return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c === '-' || c === '_';
|
117 | }
|
118 |
|
119 | function isHex(c) {
|
120 | return (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (c >= '0' && c <= '9');
|
121 | }
|
122 |
|
123 | function isDecimal(c) {
|
124 | return c >= '0' && c <= '9';
|
125 | }
|
126 |
|
127 | function isAttrMatchOperator(chr) {
|
128 | return chr === '=' || chr === '^' || chr === '$' || chr === '*' || chr === '~';
|
129 | }
|
130 |
|
131 | var identSpecialChars = {
|
132 | '!': true,
|
133 | '"': true,
|
134 | '#': true,
|
135 | '$': true,
|
136 | '%': true,
|
137 | '&': true,
|
138 | '\'': true,
|
139 | '(': true,
|
140 | ')': true,
|
141 | '*': true,
|
142 | '+': true,
|
143 | ',': true,
|
144 | '.': true,
|
145 | '/': true,
|
146 | ';': true,
|
147 | '<': true,
|
148 | '=': true,
|
149 | '>': true,
|
150 | '?': true,
|
151 | '@': true,
|
152 | '[': true,
|
153 | '\\': true,
|
154 | ']': true,
|
155 | '^': true,
|
156 | '`': true,
|
157 | '{': true,
|
158 | '|': true,
|
159 | '}': true,
|
160 | '~': true
|
161 | };
|
162 |
|
163 | var strReplacementsRev = {
|
164 | '\n': '\\n',
|
165 | '\r': '\\r',
|
166 | '\t': '\\t',
|
167 | '\f': '\\f',
|
168 | '\v': '\\v'
|
169 | };
|
170 |
|
171 | var singleQuoteEscapeChars = {
|
172 | n: '\n',
|
173 | r: '\r',
|
174 | t: '\t',
|
175 | f: '\f',
|
176 | '\\': '\\',
|
177 | '\'': '\''
|
178 | };
|
179 |
|
180 | var doubleQuotesEscapeChars = {
|
181 | n: '\n',
|
182 | r: '\r',
|
183 | t: '\t',
|
184 | f: '\f',
|
185 | '\\': '\\',
|
186 | '"': '"'
|
187 | };
|
188 |
|
189 | function ParseContext(str, pos, pseudos, attrEqualityMods, ruleNestingOperators, substitutesEnabled) {
|
190 | var chr, getIdent, getStr, l, skipWhitespace;
|
191 | l = str.length;
|
192 | chr = null;
|
193 | getStr = function(quote, escapeTable) {
|
194 | var esc, hex, result;
|
195 | result = '';
|
196 | pos++;
|
197 | chr = str.charAt(pos);
|
198 | while (pos < l) {
|
199 | if (chr === quote) {
|
200 | pos++;
|
201 | return result;
|
202 | } else if (chr === '\\') {
|
203 | pos++;
|
204 | chr = str.charAt(pos);
|
205 | if (chr === quote) {
|
206 | result += quote;
|
207 | } else if (esc = escapeTable[chr]) {
|
208 | result += esc;
|
209 | } else if (isHex(chr)) {
|
210 | hex = chr;
|
211 | pos++;
|
212 | chr = str.charAt(pos);
|
213 | while (isHex(chr)) {
|
214 | hex += chr;
|
215 | pos++;
|
216 | chr = str.charAt(pos);
|
217 | }
|
218 | if (chr === ' ') {
|
219 | pos++;
|
220 | chr = str.charAt(pos);
|
221 | }
|
222 | result += String.fromCharCode(parseInt(hex, 16));
|
223 | continue;
|
224 | } else {
|
225 | result += chr;
|
226 | }
|
227 | } else {
|
228 | result += chr;
|
229 | }
|
230 | pos++;
|
231 | chr = str.charAt(pos);
|
232 | }
|
233 | return result;
|
234 | };
|
235 | getIdent = function(specials) {
|
236 | var result = '';
|
237 | chr = str.charAt(pos);
|
238 | while (pos < l) {
|
239 | if (isIdent(chr) || (specials && specials[chr])) {
|
240 | result += chr;
|
241 | } else if (chr === '\\') {
|
242 | pos++;
|
243 | if (pos >= l) {
|
244 | throw Error('Expected symbol but end of file reached.');
|
245 | }
|
246 | chr = str.charAt(pos);
|
247 | if (identSpecialChars[chr]) {
|
248 | result += chr;
|
249 | } else if (isHex(chr)) {
|
250 | var hex = chr;
|
251 | pos++;
|
252 | chr = str.charAt(pos);
|
253 | while (isHex(chr)) {
|
254 | hex += chr;
|
255 | pos++;
|
256 | chr = str.charAt(pos);
|
257 | }
|
258 | if (chr === ' ') {
|
259 | pos++;
|
260 | chr = str.charAt(pos);
|
261 | }
|
262 | result += String.fromCharCode(parseInt(hex, 16));
|
263 | continue;
|
264 | } else {
|
265 | result += chr;
|
266 | }
|
267 | } else {
|
268 | return result;
|
269 | }
|
270 | pos++;
|
271 | chr = str.charAt(pos);
|
272 | }
|
273 | return result;
|
274 | };
|
275 | skipWhitespace = function() {
|
276 | chr = str.charAt(pos);
|
277 | var result = false;
|
278 | while (chr === ' ' || chr === "\t" || chr === "\n" || chr === "\r" || chr === "\f") {
|
279 | result = true;
|
280 | pos++;
|
281 | chr = str.charAt(pos);
|
282 | }
|
283 | return result;
|
284 | };
|
285 | this.parse = function() {
|
286 | var res = this.parseSelector();
|
287 | if (pos < l) {
|
288 | throw Error('Rule expected but "' + str.charAt(pos) + '" found.');
|
289 | }
|
290 | return res;
|
291 | };
|
292 | this.parseSelector = function() {
|
293 | var res;
|
294 | var selector = res = this.parseSingleSelector();
|
295 | chr = str.charAt(pos);
|
296 | while (chr === ',') {
|
297 | pos++;
|
298 | skipWhitespace();
|
299 | if (res.type !== 'selectors') {
|
300 | res = {
|
301 | type: 'selectors',
|
302 | selectors: [selector]
|
303 | };
|
304 | }
|
305 | selector = this.parseSingleSelector();
|
306 | if (!selector) {
|
307 | throw Error('Rule expected after ",".');
|
308 | }
|
309 | res.selectors.push(selector);
|
310 | }
|
311 | return res;
|
312 | };
|
313 |
|
314 | this.parseSingleSelector = function() {
|
315 | skipWhitespace();
|
316 |
|
317 | let opm = str.slice(pos,pos + 4).match(/^(\>{1,3}|\+|~)/);
|
318 |
|
319 | var selector = {
|
320 | type: 'ruleSet'
|
321 | };
|
322 |
|
323 | var rule = opm ? Object.assign([],{type: 'rule', isScope: true}) : this.parseRule();
|
324 |
|
325 | if (!rule) {
|
326 | return null;
|
327 | }
|
328 | var currentRule = selector;
|
329 | while (rule) {
|
330 | rule.type = 'rule';
|
331 | if(currentRule == rule){
|
332 |
|
333 | } else {
|
334 | currentRule.rule = rule;
|
335 | currentRule = rule;
|
336 | }
|
337 |
|
338 | skipWhitespace();
|
339 | chr = str.charAt(pos);
|
340 | if (pos >= l || chr === ',' || chr === ')') {
|
341 | break;
|
342 | }
|
343 | if (ruleNestingOperators[chr]) {
|
344 | var op = chr;
|
345 | if(op == '>' && str.charAt(pos + 1) == '>' && str.charAt(pos + 2) == '>'){
|
346 | op = '>>>';
|
347 | pos = pos + 3;
|
348 | } else if(op == '>' && str.charAt(pos + 1) == '>'){
|
349 | op = '>>';
|
350 | pos = pos + 2;
|
351 | } else {
|
352 | pos++;
|
353 | }
|
354 | skipWhitespace();
|
355 | rule = this.parseRule(null);
|
356 |
|
357 | if (!rule) {
|
358 | if(op == '>' || op == '>>>' || op == '>>'){
|
359 | rule = RULE({tagName: '*'});
|
360 | } else {
|
361 | throw Error('Rule expected after "' + op + '".');
|
362 | }
|
363 | }
|
364 | rule.nestingOperator = op;
|
365 | } else {
|
366 | rule = this.parseRule(currentRule);
|
367 | }
|
368 | }
|
369 | return selector;
|
370 | };
|
371 |
|
372 | this.parseSubRule = function(type = 'is',simple = false,nest = false){
|
373 | let pseudo = {name: type, valueType: 'selector', up: true};
|
374 |
|
375 |
|
376 |
|
377 | if(simple){
|
378 | let value = this.parseRule();
|
379 | value.type = 'rule';
|
380 | pseudo.value = {type: 'ruleSet',rule: value};
|
381 | if(nest){
|
382 | pseudo.after = value.rule = RULE({tagName: '*', nestingOperator: null, type: 'rule'});
|
383 | }
|
384 | } else {
|
385 | let value = this.parseSelector();
|
386 | pseudo.value = value;
|
387 | }
|
388 |
|
389 | return pseudo;
|
390 | }
|
391 |
|
392 | this.parseRule = function(currentRule) {
|
393 | var rule = null;
|
394 | var unimportant = false;
|
395 | var nextIsPseudo = false;
|
396 | var negate = false;
|
397 | var closest = false;
|
398 |
|
399 | var part = {}
|
400 |
|
401 |
|
402 |
|
403 |
|
404 | var up = 0;
|
405 |
|
406 | while (pos < l) {
|
407 | chr = str.charAt(pos);
|
408 |
|
409 | part = {}
|
410 |
|
411 | if (chr == '!') {
|
412 | negate = true;
|
413 | chr = str.charAt(++pos);
|
414 | rule = rule || currentRule;
|
415 | part.not = true;
|
416 | }
|
417 |
|
418 |
|
419 | if(chr == '@' && str.charAt(pos + 1) == '.'){
|
420 | rule = rule || currentRule;
|
421 | part.implicitScope = true;
|
422 | pos++; chr = '.';
|
423 | } else if(chr == '@' && str.charAt(pos + 1) == '@'){
|
424 | part.closest = true;
|
425 | rule = rule || currentRule;
|
426 | pos++;
|
427 | } else if(chr == '.' && str.charAt(pos + 1) == '.'){
|
428 | closest = part;
|
429 | rule = rule || currentRule;
|
430 | pos++;
|
431 |
|
432 |
|
433 |
|
434 | let next = str.charAt(pos + 1);
|
435 | if(next == '%' || next == '$' || next == '@'){
|
436 | chr = next;
|
437 | pos++;
|
438 | }
|
439 |
|
440 | }
|
441 |
|
442 | while (chr == '^') {
|
443 | chr = str.charAt(++pos);
|
444 | rule = rule || currentRule;
|
445 | up++;
|
446 |
|
447 | }
|
448 |
|
449 | part.up = up;
|
450 |
|
451 |
|
452 | part.closest = closest;
|
453 |
|
454 |
|
455 | if (chr === '&') {
|
456 | pos++;
|
457 | (rule = rule || []).isScope = true;
|
458 |
|
459 | } else if (chr === '^') {
|
460 | pos++;
|
461 | let pseudo = this.parseSubRule('is',true,true);
|
462 | (rule = rule || currentRule || []).push(pseudo);
|
463 | } else if (chr === '*') {
|
464 | pos++;
|
465 |
|
466 | (rule = rule || []).tagName = '*';
|
467 |
|
468 | } else if (isIdentStart(chr) || chr === '\\') {
|
469 | (rule = rule || []).tagName = getIdent();
|
470 | } else if (chr === '$') {
|
471 | pos++;
|
472 | part.flag = '$' + getIdent();
|
473 | part.ref = true;
|
474 | (rule = rule || []).push(part);
|
475 | } else if (chr === '%') {
|
476 | pos++;
|
477 | part.flag = chr + getIdent();
|
478 | (rule = rule || []).push(part);
|
479 | } else if (chr === '.') {
|
480 | pos++;
|
481 | let flag = str.charAt(pos++);
|
482 | if(flag == '!'){
|
483 | part.not = true
|
484 | flag = ''
|
485 | }
|
486 | flag += getIdent({});
|
487 | part.flag = flag;
|
488 | (rule = rule || []).push(part);
|
489 | } else if (chr === '#') {
|
490 | pos++;
|
491 | (rule = rule || []).id = getIdent();
|
492 | } else if (chr === '[') {
|
493 | pos++;
|
494 | skipWhitespace();
|
495 | var attr = part.attr = {
|
496 | name: getIdent()
|
497 | };
|
498 | skipWhitespace();
|
499 | if (chr === ']') {
|
500 | pos++;
|
501 | } else {
|
502 | var operator = '';
|
503 | if (attrEqualityMods[chr]) {
|
504 | operator = chr;
|
505 | pos++;
|
506 | chr = str.charAt(pos);
|
507 | }
|
508 | if (pos >= l) {
|
509 | throw Error('Expected "=" but end of file reached.');
|
510 | }
|
511 | if (chr !== '=') {
|
512 | throw Error('Expected "=" but "' + chr + '" found.');
|
513 | }
|
514 | attr.operator = operator + '=';
|
515 | pos++;
|
516 | skipWhitespace();
|
517 | var attrValue = '';
|
518 | attr.valueType = 'string';
|
519 | if (chr === '"') {
|
520 | attrValue = getStr('"', doubleQuotesEscapeChars);
|
521 | } else if (chr === '\'') {
|
522 | attrValue = getStr('\'', singleQuoteEscapeChars);
|
523 | } else if (substitutesEnabled && chr === '$') {
|
524 | pos++;
|
525 | attrValue = getIdent();
|
526 | attr.valueType = 'substitute';
|
527 | } else {
|
528 | while (pos < l) {
|
529 | if (chr === ']') {
|
530 | break;
|
531 | }
|
532 | attrValue += chr;
|
533 | pos++;
|
534 | chr = str.charAt(pos);
|
535 | }
|
536 | attrValue = attrValue.trim();
|
537 | }
|
538 | skipWhitespace();
|
539 | if (pos >= l) {
|
540 | throw Error('Expected "]" but end of file reached.');
|
541 | }
|
542 | if (chr !== ']') {
|
543 | throw Error('Expected "]" but "' + chr + '" found.');
|
544 | }
|
545 | pos++;
|
546 | attr.value = attrValue;
|
547 | }
|
548 | (rule = rule || []).push(part);
|
549 |
|
550 | } else if (chr === ':' || chr === '@') {
|
551 |
|
552 | if(chr == ':' && str.charAt(pos + 1) == ':'){
|
553 | (rule = rule || currentRule || []).pseudoElement = getIdent({':':true})
|
554 | continue;
|
555 | }
|
556 |
|
557 | pos++;
|
558 | part.name = chr;
|
559 | var pseudo = part;
|
560 |
|
561 | let pseudoName = str.charAt(pos++);
|
562 |
|
563 | if(pseudoName == '!'){
|
564 | part.not = true;
|
565 | pseudoName = '';
|
566 | }
|
567 |
|
568 | pseudoName += getIdent({'~':true,'+':true,'.':false,'>':true,'<':true});
|
569 |
|
570 | if(pseudoName == 'unimportant'){
|
571 | unimportant = true;
|
572 | part.type = 'unimportant';
|
573 |
|
574 | (rule = rule || currentRule || []).push(part);
|
575 |
|
576 |
|
577 | continue;
|
578 | }
|
579 |
|
580 | part.name += pseudoName;
|
581 | part.pseudo = pseudoName;
|
582 |
|
583 | if (chr === '(') {
|
584 | pos++;
|
585 | var value = '';
|
586 | skipWhitespace();
|
587 | if (pseudos[pseudoName] === 'selector') {
|
588 | pseudo.valueType = 'selector';
|
589 | value = this.parseSelector();
|
590 | } else {
|
591 | pseudo.valueType = pseudos[pseudoName] || 'string';
|
592 | if (chr === '"') {
|
593 | value = getStr('"', doubleQuotesEscapeChars);
|
594 | } else if (chr === '\'') {
|
595 | value = getStr('\'', singleQuoteEscapeChars);
|
596 | } else if (substitutesEnabled && chr === '$') {
|
597 | pos++;
|
598 | value = getIdent();
|
599 | pseudo.valueType = 'substitute';
|
600 | } else {
|
601 | while (pos < l) {
|
602 | if (chr === ')') {
|
603 | break;
|
604 | }
|
605 | value += chr;
|
606 | pos++;
|
607 | chr = str.charAt(pos);
|
608 | }
|
609 | value = value.trim();
|
610 | }
|
611 | skipWhitespace();
|
612 | }
|
613 | if (pos >= l) {
|
614 | throw Error('Expected ")" but end of file reached.');
|
615 | }
|
616 | if (chr !== ')') {
|
617 | throw Error('Expected ")" but "' + chr + '" found.');
|
618 | }
|
619 | pos++;
|
620 | pseudo.value = value;
|
621 |
|
622 | }
|
623 | (rule = rule || currentRule || []).push(part);
|
624 | } else {
|
625 | break;
|
626 | }
|
627 | }
|
628 | return rule;
|
629 | };
|
630 | return this;
|
631 | }
|
632 |
|
633 | CssSelectorParser.prototype.parse = function(str) {
|
634 | var context = new ParseContext(
|
635 | str,
|
636 | 0,
|
637 | this.pseudos,
|
638 | this.attrEqualityMods,
|
639 | this.ruleNestingOperators,
|
640 | this.substitutesEnabled
|
641 | );
|
642 | return context.parse();
|
643 | };
|
644 |
|
645 | CssSelectorParser.prototype.escapeIdentifier = function(s) {
|
646 | var result = '';
|
647 | var i = 0;
|
648 | var len = s.length;
|
649 | while (i < len) {
|
650 | var chr = s.charAt(i);
|
651 | if (identSpecialChars[chr]) {
|
652 | result += '\\' + chr;
|
653 | } else {
|
654 | if (
|
655 | !(
|
656 | chr === '_' || chr === '-' ||
|
657 | (chr >= 'A' && chr <= 'Z') ||
|
658 | (chr >= 'a' && chr <= 'z') ||
|
659 | (i !== 0 && chr >= '0' && chr <= '9')
|
660 | )
|
661 | ) {
|
662 | var charCode = chr.charCodeAt(0);
|
663 | if ((charCode & 0xF800) === 0xD800) {
|
664 | var extraCharCode = s.charCodeAt(i++);
|
665 | if ((charCode & 0xFC00) !== 0xD800 || (extraCharCode & 0xFC00) !== 0xDC00) {
|
666 | throw Error('UCS-2(decode): illegal sequence');
|
667 | }
|
668 | charCode = ((charCode & 0x3FF) << 10) + (extraCharCode & 0x3FF) + 0x10000;
|
669 | }
|
670 | result += '\\' + charCode.toString(16) + ' ';
|
671 | } else {
|
672 | result += chr;
|
673 | }
|
674 | }
|
675 | i++;
|
676 | }
|
677 | return result;
|
678 | };
|
679 |
|
680 | CssSelectorParser.prototype.escapeStr = function(s) {
|
681 | var result = '';
|
682 | var i = 0;
|
683 | var len = s.length;
|
684 | var chr, replacement;
|
685 | while (i < len) {
|
686 | chr = s.charAt(i);
|
687 | if (chr === '"') {
|
688 | chr = '\\"';
|
689 | } else if (chr === '\\') {
|
690 | chr = '\\\\';
|
691 | } else if (replacement = strReplacementsRev[chr]) {
|
692 | chr = replacement;
|
693 | }
|
694 | result += chr;
|
695 | i++;
|
696 | }
|
697 | return "\"" + result + "\"";
|
698 | };
|
699 |
|
700 | CssSelectorParser.prototype.render = function(path) {
|
701 | return this._renderEntity(path).trim();
|
702 | };
|
703 |
|
704 | var rootSelector = null;
|
705 | CssSelectorParser.prototype._renderEntity = function(entity,parent) {
|
706 | var currentEntity, parts, res;
|
707 | res = '';
|
708 | switch (entity.type) {
|
709 | case 'ruleSet':
|
710 | currentEntity = entity.rule;
|
711 | rootSelector = entity;
|
712 | parts = [];
|
713 | while (currentEntity) {
|
714 | if (currentEntity.nestingOperator) {
|
715 | parts.push(currentEntity.nestingOperator);
|
716 | }
|
717 | parts.push(this._renderEntity(currentEntity));
|
718 | currentEntity = currentEntity.rule;
|
719 | }
|
720 | let media = entity.media && entity.media.length ? ` @media ${entity.media.join(' and ')}` : ''
|
721 | res = parts.join(' ') + media;
|
722 | break;
|
723 | case 'selectors':
|
724 | res = entity.selectors.map(this._renderEntity, this).join(', ');
|
725 | break;
|
726 | case 'rule':
|
727 | let s0 = entity.s1;
|
728 | let s1 = entity.s2;
|
729 | let tagName = entity.tagName;
|
730 |
|
731 | if (tagName) {
|
732 | if (tagName === '*') {
|
733 | res = '*';
|
734 | } else {
|
735 | let native = TAG_NAMES[tagName] || tagName == 'svg' || tagName.indexOf('-') > 0;
|
736 | let escaped = this.escapeIdentifier(tagName);
|
737 |
|
738 | if(native){
|
739 | res = escaped;
|
740 | } else {
|
741 | res = `:is(${escaped},${escaped}-tag)`
|
742 | }
|
743 | }
|
744 | }
|
745 | if (entity.id) {
|
746 | res += "#" + this.escapeIdentifier(entity.id);
|
747 | }
|
748 |
|
749 | let idx = 0;
|
750 | let len = entity.length;
|
751 |
|
752 | while(idx < len){
|
753 | let shortest = null;
|
754 | let part = entity[idx++];
|
755 | let attr = part.attr;
|
756 | let flag = part.flag;
|
757 | let out = "";
|
758 | let neg = part.not;
|
759 | let pseudo = part.pseudo ? part : null;
|
760 | let desc = modifiers[part.pseudo];
|
761 |
|
762 |
|
763 |
|
764 | if(part.media || part.skip){
|
765 |
|
766 | continue;
|
767 | }
|
768 |
|
769 | if(desc && desc.flag){
|
770 | flag = desc.flag;
|
771 | pseudo = null;
|
772 | }
|
773 |
|
774 | if(desc && desc.type == 'el'){
|
775 | pseudo = null;
|
776 | entity.pseudoElement ||= '::' + part.pseudo;
|
777 | }
|
778 |
|
779 | if(flag){
|
780 | out = '.' + this.escapeIdentifier(flag);
|
781 | }
|
782 |
|
783 | if(attr) {
|
784 | if (attr.operator) {
|
785 | if (attr.valueType === 'substitute') {
|
786 | out = "[" + this.escapeIdentifier(attr.name) + attr.operator + "$" + attr.value + "]";
|
787 | } else {
|
788 | out = "[" + this.escapeIdentifier(attr.name) + attr.operator + this.escapeStr(attr.value) + "]";
|
789 | }
|
790 | } else {
|
791 | out = "[" + this.escapeIdentifier(attr.name) + "]";
|
792 | }
|
793 | }
|
794 |
|
795 | if(pseudo){
|
796 |
|
797 | let name = (desc && desc.name) ?? pseudo.pseudo;
|
798 | let escaped = this.escapeIdentifier(name);
|
799 |
|
800 | if(desc && desc.valueType) {
|
801 | pseudo = desc;
|
802 | }
|
803 |
|
804 |
|
805 | let post = "";
|
806 | let value = pseudo.value || pseudo.name;
|
807 |
|
808 | let pre = ":" + escaped;
|
809 |
|
810 |
|
811 | if (pseudo.valueType) {
|
812 | if (pseudo.valueType === 'selector') {
|
813 | out = pre + "(" + this._renderEntity(pseudo.value,parent) + ")" + post;
|
814 | } else if (pseudo.valueType === 'substitute') {
|
815 | out = pre + "($" + pseudo.value + ")" + post;
|
816 | } else if (pseudo.valueType === 'numeric') {
|
817 | out = pre + "(" + pseudo.value + ")" + post;
|
818 | } else if (pseudo.valueType === 'raw' || pseudo.valueType === 'string' ) {
|
819 | out = pre + "(" + pseudo.value + ")" + post;
|
820 | } else {
|
821 | out = pre + "(" + this.escapeIdentifier(pseudo.value) + ")" + post;
|
822 | }
|
823 | } else if(pseudo.type == 'el') {
|
824 | out = ':' + pre;
|
825 | } else if(!desc) {
|
826 | out = `.\\@${escaped}`
|
827 | } else if(desc.shim) {
|
828 | let pre = neg ? ':not' : ':is';
|
829 | out = `.\\@${escaped}`
|
830 | out = `${pre}(:${typeof desc.native == 'string' ? desc.native : escaped},${out})`;
|
831 | neg = false;
|
832 | } else if(desc.flag) {
|
833 | out = `.\\@${escaped}`
|
834 | } else {
|
835 | out = pre + post;
|
836 | }
|
837 | }
|
838 |
|
839 | if(part.closest) {
|
840 |
|
841 |
|
842 | let parts = entity.filter(v=> v.closest == part);
|
843 |
|
844 | parts.map( v=> v.closest = null )
|
845 | part.not = false;
|
846 | let all = this._renderEntity(RULE({type: 'rule'},parts))
|
847 | parts.map( v=> v.skip = true )
|
848 |
|
849 |
|
850 | out = `:${neg ? 'not' : 'is'}(${all} *)`
|
851 | neg = false;
|
852 |
|
853 | } else if (part.up) {
|
854 | let rest = part.up > 5 ? ' *' : ' > *'.repeat(part.up);
|
855 | out = `:${neg ? 'not' : 'is'}(${out}${rest})`
|
856 | neg = false;
|
857 | }
|
858 |
|
859 | if(neg){
|
860 | out = `:not(${out})`
|
861 | }
|
862 |
|
863 | res += out;
|
864 | }
|
865 |
|
866 | if(s0 > 0){
|
867 | while (--s0 >= 0) res += ":not(#_)";
|
868 | }
|
869 | if(s1 > 0){
|
870 | while (--s1 >= 0) res += ":not(._0)";
|
871 | }
|
872 |
|
873 | if(entity.pseudoElement){
|
874 | res += entity.pseudoElement;
|
875 | }
|
876 | break;
|
877 | default:
|
878 | throw Error('Unknown entity type: "' + entity.type(+'".'));
|
879 | }
|
880 | return res;
|
881 | };
|
882 |
|
883 | var parser = new CssSelectorParser();
|
884 | parser.registerSelectorPseudos('has','not','is','matches','any','where')
|
885 | parser.registerNumericPseudos('nth-child')
|
886 | parser.registerNestingOperators('>>>','>>','>', '+', '~')
|
887 | parser.registerAttrEqualityMods('^', '$', '*', '~')
|
888 |
|
889 |
|
890 | export const parse = function(v){
|
891 |
|
892 | return parser.parse(v) }
|
893 | export const render = function(v){ return parser.render(v) }
|
894 |
|
\ | No newline at end of file |