parse-css 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1432 @@
1
+ // Copied from https://github.com/tabatkins/parse-css/blob/3dfe12a9bb63b8762c3bfd37db4e3593aa39bd5e/parse-css.js
2
+
3
+ "use strict";
4
+ (function (global, factory) {
5
+ // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
6
+ // Rhino, and plain browser loading.
7
+ if (typeof define === 'function' && define.amd) {
8
+ define(['exports'], factory);
9
+ } else if (typeof exports !== 'undefined') {
10
+ factory(exports);
11
+ } else {
12
+ global = typeof globalThis !== 'undefined' ? globalThis : global || self;
13
+ factory(global);
14
+ }
15
+ }(this, function (exports) {
16
+ function between(num, first, last) { return num >= first && num <= last; }
17
+ function digit(code) { return between(code, 0x30,0x39); }
18
+ function hexdigit(code) { return digit(code) || between(code, 0x41,0x46) || between(code, 0x61,0x66); }
19
+ function uppercaseletter(code) { return between(code, 0x41,0x5a); }
20
+ function lowercaseletter(code) { return between(code, 0x61,0x7a); }
21
+ function letter(code) { return uppercaseletter(code) || lowercaseletter(code); }
22
+ function nonascii(code) {
23
+ return (
24
+ code == 0xb7 ||
25
+ between(code, 0xc0, 0xd6) ||
26
+ between(code, 0xd8, 0xf6) ||
27
+ between(code, 0xf8, 0x37d) ||
28
+ between(code, 0x37f, 0x1fff) ||
29
+ code == 0x200c ||
30
+ code == 0x200d ||
31
+ code == 0x203f ||
32
+ code == 0x2040 ||
33
+ between(code, 0x2070, 0x218f) ||
34
+ between(code, 0x2c00, 0x2fef) ||
35
+ between(code, 0x3001, 0xd7ff) ||
36
+ between(code, 0xf900, 0xfdcf) ||
37
+ between(code, 0xfdf0, 0xfffd) ||
38
+ code >= 0x10000
39
+ );
40
+ }
41
+ function namestartchar(code) { return letter(code) || nonascii(code) || code == 0x5f; }
42
+ function namechar(code) { return namestartchar(code) || digit(code) || code == 0x2d; }
43
+ function nonprintable(code) { return between(code, 0,8) || code == 0xb || between(code, 0xe,0x1f) || code == 0x7f; }
44
+ function newline(code) { return code == 0xa; }
45
+ function whitespace(code) { return newline(code) || code == 9 || code == 0x20; }
46
+ function badescape(code) { return newline(code) || isNaN(code); }
47
+ function surrogate(code) { return between(code, 0xd800, 0xdfff); }
48
+
49
+ var maximumallowedcodepoint = 0x10ffff;
50
+
51
+ class InvalidCharacterError extends Error {
52
+ constructor(message) {
53
+ super();
54
+ this.name = "InvalidCharacterError";
55
+ this.message = message;
56
+ }
57
+ }
58
+
59
+ class SpecError extends Error {
60
+ constructor(...args) {
61
+ super(...args);
62
+ this.name = "SpecError";
63
+ }
64
+ }
65
+
66
+ function preprocess(str) {
67
+ // Turn a string into an array of code points,
68
+ // following the preprocessing cleanup rules.
69
+ var codepoints = [];
70
+ for(var i = 0; i < str.length; i++) {
71
+ var code = str.codePointAt(i);
72
+ if (code == 0xd && str.charCodeAt(i+1) == 0xa) {
73
+ code = 0xa; i++;
74
+ } else if (code == 0xd || code == 0xc) {
75
+ code = 0xa;
76
+ } else if (code == 0x0 || between(code, 0xd800, 0xdfff)) {
77
+ code = 0xfffd;
78
+ } else if (code > 0xffff) {
79
+ i++;
80
+ }
81
+ codepoints.push(code);
82
+ }
83
+ return codepoints;
84
+ }
85
+
86
+ function asciiCaselessMatch(s1, s2) {
87
+ return s1.toLowerCase() == s2.toLowerCase();
88
+ }
89
+
90
+ function tokenize(str) {
91
+ str = preprocess(str);
92
+ var i = -1;
93
+ var tokens = [];
94
+ var code;
95
+
96
+ // Line number information.
97
+ var line = 0;
98
+ var column = 0;
99
+ // The only use of lastLineLength is in reconsume().
100
+ var lastLineLength = 0;
101
+ var incrLineno = function() {
102
+ line += 1;
103
+ lastLineLength = column;
104
+ column = 0;
105
+ };
106
+ var locStart = {line:line, column:column};
107
+
108
+ var codepoint = function(i) {
109
+ if(i >= str.length) {
110
+ return -1;
111
+ }
112
+ return str[i];
113
+ }
114
+ var next = function(num) {
115
+ if(num === undefined)
116
+ num = 1;
117
+ if(num > 3)
118
+ throw new SpecError("no more than three codepoints of lookahead.");
119
+ return codepoint(i+num);
120
+ };
121
+ var consume = function(num) {
122
+ if(num === undefined)
123
+ num = 1;
124
+ i += num;
125
+ code = codepoint(i);
126
+ if(newline(code)) incrLineno();
127
+ else column += num;
128
+ //console.log('Consume '+i+' '+String.fromCharCode(code) + ' 0x' + code.toString(16));
129
+ return true;
130
+ };
131
+ var reconsume = function() {
132
+ i -= 1;
133
+ if (newline(code)) {
134
+ line -= 1;
135
+ column = lastLineLength;
136
+ } else {
137
+ column -= 1;
138
+ }
139
+ locStart.line = line;
140
+ locStart.column = column;
141
+ return true;
142
+ };
143
+ var eof = function(codepoint) {
144
+ if(codepoint === undefined) codepoint = code;
145
+ return codepoint == -1;
146
+ };
147
+ var donothing = function() {};
148
+ var parseerror = function() { console.log("Parse error at index " + i + ", processing codepoint 0x" + code.toString(16) + ".");return true; };
149
+
150
+ var consumeAToken = function() {
151
+ consumeComments();
152
+ consume();
153
+ if(whitespace(code)) {
154
+ while(whitespace(next())) consume();
155
+ return new WhitespaceToken;
156
+ }
157
+ else if(code == 0x22) return consumeAStringToken();
158
+ else if(code == 0x23) {
159
+ if(namechar(next()) || areAValidEscape(next(1), next(2))) {
160
+ const isIdent = wouldStartAnIdentifier(next(1), next(2), next(3));
161
+ return new HashToken(consumeAName(), isIdent);
162
+ } else {
163
+ return new DelimToken(code);
164
+ }
165
+ }
166
+ else if(code == 0x27) return consumeAStringToken();
167
+ else if(code == 0x28) return new OpenParenToken();
168
+ else if(code == 0x29) return new CloseParenToken();
169
+ else if(code == 0x2b) {
170
+ if(startsWithANumber()) {
171
+ reconsume();
172
+ return consumeANumericToken();
173
+ } else {
174
+ return new DelimToken(code);
175
+ }
176
+ }
177
+ else if(code == 0x2c) return new CommaToken();
178
+ else if(code == 0x2d) {
179
+ if(startsWithANumber()) {
180
+ reconsume();
181
+ return consumeANumericToken();
182
+ } else if(next(1) == 0x2d && next(2) == 0x3e) {
183
+ consume(2);
184
+ return new CDCToken();
185
+ } else if(startsWithAnIdentifier()) {
186
+ reconsume();
187
+ return consumeAnIdentlikeToken();
188
+ } else {
189
+ return new DelimToken(code);
190
+ }
191
+ }
192
+ else if(code == 0x2e) {
193
+ if(startsWithANumber()) {
194
+ reconsume();
195
+ return consumeANumericToken();
196
+ } else {
197
+ return new DelimToken(code);
198
+ }
199
+ }
200
+ else if(code == 0x3a) return new ColonToken;
201
+ else if(code == 0x3b) return new SemicolonToken;
202
+ else if(code == 0x3c) {
203
+ if(next(1) == 0x21 && next(2) == 0x2d && next(3) == 0x2d) {
204
+ consume(3);
205
+ return new CDOToken();
206
+ } else {
207
+ return new DelimToken(code);
208
+ }
209
+ }
210
+ else if(code == 0x40) {
211
+ if(wouldStartAnIdentifier(next(1), next(2), next(3))) {
212
+ return new AtKeywordToken(consumeAName());
213
+ } else {
214
+ return new DelimToken(code);
215
+ }
216
+ }
217
+ else if(code == 0x5b) return new OpenSquareToken();
218
+ else if(code == 0x5c) {
219
+ if(startsWithAValidEscape()) {
220
+ reconsume();
221
+ return consumeAnIdentlikeToken();
222
+ } else {
223
+ parseerror();
224
+ return new DelimToken(code);
225
+ }
226
+ }
227
+ else if(code == 0x5d) return new CloseSquareToken();
228
+ else if(code == 0x7b) return new OpenCurlyToken();
229
+ else if(code == 0x7d) return new CloseCurlyToken();
230
+ else if(digit(code)) {
231
+ reconsume();
232
+ return consumeANumericToken();
233
+ }
234
+ else if(namestartchar(code)) {
235
+ reconsume();
236
+ return consumeAnIdentlikeToken();
237
+ }
238
+ else if(eof()) return new EOFToken();
239
+ else return new DelimToken(code);
240
+ };
241
+
242
+ var consumeComments = function() {
243
+ while(next(1) == 0x2f && next(2) == 0x2a) {
244
+ consume(2);
245
+ while(true) {
246
+ consume();
247
+ if(code == 0x2a && next() == 0x2f) {
248
+ consume();
249
+ break;
250
+ } else if(eof()) {
251
+ parseerror();
252
+ return;
253
+ }
254
+ }
255
+ }
256
+ };
257
+
258
+ var consumeANumericToken = function() {
259
+ var {value, isInteger, sign} = consumeANumber();
260
+ if(wouldStartAnIdentifier(next(1), next(2), next(3))) {
261
+ const unit = consumeAName();
262
+ return new DimensionToken(value, isInteger, unit, sign);
263
+ } else if(next() == 0x25) {
264
+ consume();
265
+ return new PercentageToken(value, sign);
266
+ } else {
267
+ return new NumberToken(value, isInteger, sign);
268
+ }
269
+ };
270
+
271
+ var consumeAnIdentlikeToken = function() {
272
+ var str = consumeAName();
273
+ if(str.toLowerCase() == "url" && next() == 0x28) {
274
+ consume();
275
+ while(whitespace(next(1)) && whitespace(next(2))) consume();
276
+ if(next() == 0x22 || next() == 0x27) {
277
+ return new FunctionToken(str);
278
+ } else if(whitespace(next()) && (next(2) == 0x22 || next(2) == 0x27)) {
279
+ return new FunctionToken(str);
280
+ } else {
281
+ return consumeAURLToken();
282
+ }
283
+ } else if(next() == 0x28) {
284
+ consume();
285
+ return new FunctionToken(str);
286
+ } else {
287
+ return new IdentToken(str);
288
+ }
289
+ };
290
+
291
+ var consumeAStringToken = function(endingCodePoint) {
292
+ if(endingCodePoint === undefined) endingCodePoint = code;
293
+ var string = "";
294
+ while(consume()) {
295
+ if(code == endingCodePoint || eof()) {
296
+ return new StringToken(string);
297
+ } else if(newline(code)) {
298
+ parseerror();
299
+ reconsume();
300
+ return new BadStringToken();
301
+ } else if(code == 0x5c) {
302
+ if(eof(next())) {
303
+ donothing();
304
+ } else if(newline(next())) {
305
+ consume();
306
+ } else {
307
+ string += String.fromCodePoint(consumeEscape())
308
+ }
309
+ } else {
310
+ string += String.fromCodePoint(code);
311
+ }
312
+ }
313
+ };
314
+
315
+ var consumeAURLToken = function() {
316
+ var token = new URLToken("");
317
+ while(whitespace(next())) consume();
318
+ if(eof(next())) return token;
319
+ while(consume()) {
320
+ if(code == 0x29 || eof()) {
321
+ return token;
322
+ } else if(whitespace(code)) {
323
+ while(whitespace(next())) consume();
324
+ if(next() == 0x29 || eof(next())) {
325
+ consume();
326
+ return token;
327
+ } else {
328
+ consumeTheRemnantsOfABadURL();
329
+ return new BadURLToken();
330
+ }
331
+ } else if(code == 0x22 || code == 0x27 || code == 0x28 || nonprintable(code)) {
332
+ parseerror();
333
+ consumeTheRemnantsOfABadURL();
334
+ return new BadURLToken();
335
+ } else if(code == 0x5c) {
336
+ if(startsWithAValidEscape()) {
337
+ token.value += String.fromCodePoint(consumeEscape());
338
+ } else {
339
+ parseerror();
340
+ consumeTheRemnantsOfABadURL();
341
+ return new BadURLToken();
342
+ }
343
+ } else {
344
+ token.value += String.fromCodePoint(code);
345
+ }
346
+ }
347
+ };
348
+
349
+ var consumeEscape = function() {
350
+ // Assume the the current character is the \
351
+ // and the next code point is not a newline.
352
+ consume();
353
+ if(hexdigit(code)) {
354
+ // Consume 1-6 hex digits
355
+ var digits = [code];
356
+ for(var total = 0; total < 5; total++) {
357
+ if(hexdigit(next())) {
358
+ consume();
359
+ digits.push(code);
360
+ } else {
361
+ break;
362
+ }
363
+ }
364
+ if(whitespace(next())) consume();
365
+ var value = parseInt(digits.map(function(x){return String.fromCharCode(x);}).join(''), 16);
366
+ if (value === 0x0 || between(value, 0xd800, 0xdfff) || value > maximumallowedcodepoint ) value = 0xfffd;
367
+ return value;
368
+ } else if(eof()) {
369
+ return 0xfffd;
370
+ } else {
371
+ return code;
372
+ }
373
+ };
374
+
375
+ var areAValidEscape = function(c1, c2) {
376
+ if(c1 != 0x5c) return false;
377
+ if(newline(c2)) return false;
378
+ return true;
379
+ };
380
+ var startsWithAValidEscape = function() {
381
+ return areAValidEscape(code, next());
382
+ };
383
+
384
+ var wouldStartAnIdentifier = function(c1, c2, c3) {
385
+ if(c1 == 0x2d) {
386
+ return namestartchar(c2) || c2 == 0x2d || areAValidEscape(c2, c3);
387
+ } else if(namestartchar(c1)) {
388
+ return true;
389
+ } else if(c1 == 0x5c) {
390
+ return areAValidEscape(c1, c2);
391
+ } else {
392
+ return false;
393
+ }
394
+ };
395
+ var startsWithAnIdentifier = function() {
396
+ return wouldStartAnIdentifier(code, next(1), next(2));
397
+ };
398
+
399
+ var wouldStartANumber = function(c1, c2, c3) {
400
+ if(c1 == 0x2b || c1 == 0x2d) {
401
+ if(digit(c2)) return true;
402
+ if(c2 == 0x2e && digit(c3)) return true;
403
+ return false;
404
+ } else if(c1 == 0x2e) {
405
+ if(digit(c2)) return true;
406
+ return false;
407
+ } else if(digit(c1)) {
408
+ return true;
409
+ } else {
410
+ return false;
411
+ }
412
+ };
413
+ var startsWithANumber = function() {
414
+ return wouldStartANumber(code, next(1), next(2));
415
+ };
416
+
417
+ var consumeAName = function() {
418
+ var result = "";
419
+ while(consume()) {
420
+ if(namechar(code)) {
421
+ result += String.fromCodePoint(code);
422
+ } else if(startsWithAValidEscape()) {
423
+ result += String.fromCodePoint(consumeEscape());
424
+ } else {
425
+ reconsume();
426
+ return result;
427
+ }
428
+ }
429
+ };
430
+
431
+ var consumeANumber = function() {
432
+ let isInteger = true;
433
+ let sign;
434
+ let numberPart = "";
435
+ let exponentPart = "";
436
+ if(next() == 0x2b || next() == 0x2d) {
437
+ consume();
438
+ sign = String.fromCodePoint(code);
439
+ numberPart += sign;
440
+ }
441
+ while(digit(next())) {
442
+ consume();
443
+ numberPart += String.fromCodePoint(code);
444
+ }
445
+ if(next(1) == 0x2e && digit(next(2))) {
446
+ consume();
447
+ numberPart += ".";
448
+ while(digit(next())) {
449
+ consume();
450
+ numberPart += String.fromCodePoint(code);
451
+ }
452
+ isInteger = false;
453
+ }
454
+ var c1 = next(1), c2 = next(2), c3 = next(3);
455
+ const eDigit = (c1 == 0x45 || c1 == 0x65) && digit(c2);
456
+ const eSignDigit = (c1 == 0x45 || c1 == 0x65) && (c2 == 0x2b || c2 == 0x2d) && digit(c3);
457
+ if(eDigit || eSignDigit) {
458
+ consume();
459
+ if(eSignDigit) {
460
+ consume();
461
+ exponentPart += String.fromCodePoint(code);
462
+ }
463
+ while(digit(next())) {
464
+ consume();
465
+ exponentPart += String.fromCodePoint(code);
466
+ }
467
+ isInteger = false;
468
+ }
469
+
470
+ // parse with native engine to prevent a precision issue
471
+ // (e.g. 12E-1 becomes 1.2000000000000002)
472
+ let value = Number(numberPart + (exponentPart ? 'e' + exponentPart : ''));
473
+ // let value = +numberPart;
474
+ // if(exponentPart) value = value * Math.pow(10, +exponentPart);
475
+
476
+ return {value, isInteger, sign};
477
+ };
478
+
479
+ var consumeTheRemnantsOfABadURL = function() {
480
+ while(consume()) {
481
+ if(code == 0x29 || eof()) {
482
+ return;
483
+ } else if(startsWithAValidEscape()) {
484
+ consumeEscape();
485
+ donothing();
486
+ } else {
487
+ donothing();
488
+ }
489
+ }
490
+ };
491
+
492
+
493
+
494
+ var iterationCount = 0;
495
+ while (true) {
496
+ var token = consumeAToken();
497
+ tokens.push(token);
498
+ if (token instanceof EOFToken) {
499
+ break;
500
+ }
501
+ iterationCount++;
502
+ if(iterationCount > str.length*2) throw new Error("I'm infinite-looping!");
503
+ }
504
+ return tokens;
505
+ }
506
+
507
+ class CSSParserToken {
508
+ constructor(type) {
509
+ this.type = type;
510
+ }
511
+
512
+ toJSON() { return {type:this.type}; }
513
+ toString() { return this.type; }
514
+ toSource() { throw new Error("Not implemented."); }
515
+ }
516
+ //toJSON()
517
+ //toString()
518
+ //toSource()
519
+
520
+ class BadStringToken extends CSSParserToken {
521
+ constructor() {
522
+ super("BADSTRING");
523
+ }
524
+ toSource() { return '"\n'; }
525
+ }
526
+
527
+ class BadURLToken extends CSSParserToken {
528
+ constructor() {
529
+ super("BADURL");
530
+ }
531
+ toSource() { return "url(BAD URL)"}
532
+ }
533
+ BadURLToken.prototype.tokenType = "BADURL";
534
+
535
+ class WhitespaceToken extends CSSParserToken {
536
+ constructor() {
537
+ super("WHITESPACE");
538
+ }
539
+ toString() { return "WS"; }
540
+ toSource() { return " "; }
541
+ }
542
+
543
+ class CDOToken extends CSSParserToken {
544
+ constructor() {
545
+ super("CDO");
546
+ }
547
+ toSource() { return "<!--"; }
548
+ }
549
+
550
+ class CDCToken extends CSSParserToken {
551
+ constructor() {
552
+ super("CDC");
553
+ }
554
+ toSource() { return "-->"; }
555
+ }
556
+
557
+ class ColonToken extends CSSParserToken {
558
+ constructor() {
559
+ super("COLON");
560
+ }
561
+ toSource() { return ":"; }
562
+ }
563
+
564
+ class SemicolonToken extends CSSParserToken {
565
+ constructor() {
566
+ super("SEMICOLON");
567
+ }
568
+ toSource() { return ";" };
569
+ }
570
+
571
+ class CommaToken extends CSSParserToken {
572
+ constructor() {
573
+ super("COMMA");
574
+ }
575
+ toSource() { return "," }
576
+ }
577
+
578
+ class OpenCurlyToken extends CSSParserToken {
579
+ constructor() {
580
+ super("OPEN-CURLY");
581
+ this.grouping = true;
582
+ this.mirror = CloseCurlyToken;
583
+ }
584
+ toSource() { return "{"; }
585
+ }
586
+
587
+ class CloseCurlyToken extends CSSParserToken {
588
+ constructor() {
589
+ super("CLOSE-CURLY");
590
+ }
591
+ toSource() { return "}"; }
592
+ }
593
+
594
+ class OpenSquareToken extends CSSParserToken {
595
+ constructor() {
596
+ super("OPEN-SQUARE");
597
+ this.grouping = true;
598
+ this.mirror = CloseSquareToken;
599
+ }
600
+ toSource() { return "["; }
601
+ }
602
+
603
+ class CloseSquareToken extends CSSParserToken {
604
+ constructor() {
605
+ super("CLOSE-SQUARE");
606
+ }
607
+ toSource() { return "]"; }
608
+ }
609
+
610
+ class OpenParenToken extends CSSParserToken {
611
+ constructor() {
612
+ super("OPEN-PAREN");
613
+ this.grouping = true;
614
+ this.mirror = CloseParenToken;
615
+ }
616
+ toSource() { return "("; }
617
+ }
618
+
619
+ class CloseParenToken extends CSSParserToken {
620
+ constructor() {
621
+ super("CLOSE-PAREN");
622
+ }
623
+ toSource() { return ")"; }
624
+ }
625
+
626
+ class EOFToken extends CSSParserToken {
627
+ constructor() {
628
+ super("EOF");
629
+ }
630
+ toSource() { return ""; }
631
+ }
632
+
633
+ class DelimToken extends CSSParserToken {
634
+ constructor(val) {
635
+ super("DELIM");
636
+ if(typeof val == "number") {
637
+ val = String.fromCodePoint(val);
638
+ } else {
639
+ val = String(val);
640
+ }
641
+ this.value = val;
642
+ }
643
+ toString() { return `DELIM(${this.value})`; }
644
+ toJSON() { return {type:this.type, value:this.value}; }
645
+ toSource() {
646
+ if(this.value == "\\") return "\\\n";
647
+ return this.value;
648
+ }
649
+ }
650
+
651
+ class IdentToken extends CSSParserToken {
652
+ constructor(val) {
653
+ super("IDENT");
654
+ this.value = val;
655
+ }
656
+ toString() { return `IDENT(${this.value})`; }
657
+ toJSON() { return {type:this.type, value:this.value}; }
658
+ toSource() { return escapeIdent(this.value); }
659
+ }
660
+
661
+ class FunctionToken extends CSSParserToken {
662
+ constructor(val) {
663
+ super("FUNCTION");
664
+ this.value = val;
665
+ this.mirror = CloseParenToken;
666
+ }
667
+ toString() { return `FUNCTION(${this.value})`; }
668
+ toJSON() { return {type:this.type, value:this.value}; }
669
+ toSource() { return escapeIdent(this.value) + "("; }
670
+ }
671
+
672
+ class AtKeywordToken extends CSSParserToken {
673
+ constructor(val) {
674
+ super("AT-KEYWORD");
675
+ this.value = val;
676
+ }
677
+ toString() { return `AT(${this.value})`; }
678
+ toJSON() { return {type:this.type, value:this.value }; }
679
+ toSource() { return "@" + escapeIdent(this.value); }
680
+ }
681
+
682
+ class HashToken extends CSSParserToken {
683
+ constructor(val, isIdent) {
684
+ super("HASH");
685
+ this.value = val;
686
+ this.isIdent = isIdent;
687
+ }
688
+ toString() { return `HASH(${this.value})`; }
689
+ toJSON() { return {type:this.type, value:this.value, isIdent:this.isIdent}; }
690
+ toSource() {
691
+ if(this.isIdent) {
692
+ return "#" + escapeIdent(this.value);
693
+ }
694
+ return "#" + escapeHash(this.value);
695
+ }
696
+ }
697
+
698
+ class StringToken extends CSSParserToken {
699
+ constructor(val) {
700
+ super("STRING");
701
+ this.value = val;
702
+ }
703
+ toString() { return `STRING(${this.value})`; }
704
+ toJSON() { return {type:this.type, value:this.value}; }
705
+ toSource() { return `"${escapeString(this.value)}"`; }
706
+ }
707
+
708
+ class URLToken extends CSSParserToken {
709
+ constructor(val) {
710
+ super("URL");
711
+ this.value = val;
712
+ }
713
+ toString() { return `URL(${this.value})`; }
714
+ toJSON() { return {type:this.type, value:this.value}; }
715
+ toSource() { return `url("${escapeString(this.value)}")`; }
716
+ }
717
+
718
+ class NumberToken extends CSSParserToken {
719
+ constructor(val, isInteger, sign=undefined) {
720
+ super("NUMBER");
721
+ this.value = val;
722
+ this.isInteger = isInteger;
723
+ this.sign = sign;
724
+ }
725
+ toString() {
726
+ const name = this.isInteger ? "INT" : "NUMBER";
727
+ const sign = this.sign == "+" ? "+" : "";
728
+ return `${name}(${sign}${this.value})`;
729
+ }
730
+ toJSON() { return {type:this.type, value:this.value, isInteger:this.isInteger, sign:this.sign}; }
731
+ toSource() { return formatNumber(this.value, this.sign); }
732
+ }
733
+
734
+ class PercentageToken extends CSSParserToken {
735
+ constructor(val, sign=undefined) {
736
+ super("PERCENTAGE");
737
+ this.value = val;
738
+ this.sign = sign;
739
+ }
740
+ toString() {
741
+ const sign = this.sign == "+" ? "+" : "";
742
+ return `PERCENTAGE(${sign}${this.value})`;
743
+ }
744
+ toJSON() { return {type:this.type, value:this.value, sign:this.sign}; }
745
+ toSource() { return `${formatNumber(this.value, this.sign)}%`; }
746
+ }
747
+
748
+ class DimensionToken extends CSSParserToken {
749
+ constructor(val, isInteger, unit, sign=undefined) {
750
+ super("DIMENSION");
751
+ this.value = val;
752
+ this.isInteger = isInteger;
753
+ this.unit = unit;
754
+ this.sign = sign;
755
+ }
756
+ toString() {
757
+ const sign = this.sign == "+" ? "+" : "";
758
+ return `DIM(${sign}${this.value}, ${this.unit})`;
759
+ }
760
+ toJSON() { return {type:this.type, value:this.value, isInteger:this.isInteger, unit:this.unit, sign:this.sign}; }
761
+ toSource() {
762
+ let unit = escapeIdent(this.unit);
763
+ if(unit[0].toLowerCase() == "e" && (unit[1] == "-" || digit(unit[1].charCodeAt(0)))) {
764
+ // Unit is ambiguous with scinot
765
+ // Remove the leading "e", replace with escape.
766
+ unit = "\\65 " + unit.slice(1, unit.length);
767
+ }
768
+ return `${formatNumber(this.value, this.sign)}${unit}`;
769
+ }
770
+ }
771
+
772
+ function escapeIdent(string) {
773
+ return Array.from(String(string), (e,i)=>{
774
+ const code = e.codePointAt(0);
775
+ if(i == 0) {
776
+ if(namestartchar(code)) return e;
777
+ return escapeIdentCode(code);
778
+ }
779
+ if(namechar(code)) return e;
780
+ return escapeIdentCode(code);
781
+ }).join("");
782
+ }
783
+
784
+ function escapeIdentCode(code) {
785
+ if(digit(code) || letter(code)) {
786
+ return `\\${code.toString(16)} `;
787
+ }
788
+ return "\\"+String.fromCodePoint(code);
789
+ }
790
+
791
+ function escapeHash(string) {
792
+ // Escapes the value (after the #) of a hash.
793
+ return Array.from(String(string), e=>{
794
+ const code = e.codePointAt(0);
795
+ if(namechar(code)) return e;
796
+ return escapeIdentCode(code);
797
+ }).join("");
798
+ }
799
+
800
+ function escapeString(string) {
801
+ // Escapes the contents (between the quotes) of a string
802
+ return Array.from(String(string), e=>{
803
+ const code = e.codePointAt(0);
804
+ if(between(code, 0x0, 0x1f)
805
+ || code == 0x7f
806
+ || code == 0x22
807
+ || code == 0x5c
808
+ ) {
809
+ return "\\" + code.toString(16) + " ";
810
+ }
811
+ return e;
812
+ }).join("");
813
+ }
814
+
815
+ function formatNumber(num, sign=undefined) {
816
+ // TODO: Fix this to match CSS stringification behavior.
817
+ return (sign == "+" ? "+" : "") + String(num);
818
+ }
819
+
820
+ // Exportation.
821
+ exports.tokenize = tokenize;
822
+ exports.IdentToken = IdentToken;
823
+ exports.FunctionToken = FunctionToken;
824
+ exports.AtKeywordToken = AtKeywordToken;
825
+ exports.HashToken = HashToken;
826
+ exports.StringToken = StringToken;
827
+ exports.BadStringToken = BadStringToken;
828
+ exports.URLToken = URLToken;
829
+ exports.BadURLToken = BadURLToken;
830
+ exports.DelimToken = DelimToken;
831
+ exports.NumberToken = NumberToken;
832
+ exports.PercentageToken = PercentageToken;
833
+ exports.DimensionToken = DimensionToken;
834
+ exports.WhitespaceToken = WhitespaceToken;
835
+ exports.CDOToken = CDOToken;
836
+ exports.CDCToken = CDCToken;
837
+ exports.ColonToken = ColonToken;
838
+ exports.SemicolonToken = SemicolonToken;
839
+ exports.CommaToken = CommaToken;
840
+ exports.OpenParenToken = OpenParenToken;
841
+ exports.CloseParenToken = CloseParenToken;
842
+ exports.OpenSquareToken = OpenSquareToken;
843
+ exports.CloseSquareToken = CloseSquareToken;
844
+ exports.OpenCurlyToken = OpenCurlyToken;
845
+ exports.CloseCurlyToken = CloseCurlyToken;
846
+ exports.EOFToken = EOFToken;
847
+ exports.CSSParserToken = CSSParserToken;
848
+
849
+ class TokenStream {
850
+ constructor(tokens) {
851
+ // Assume that tokens is an array.
852
+ this.tokens = tokens;
853
+ this.i = 0;
854
+ this.marks = [];
855
+ }
856
+ nextToken() {
857
+ if(this.i < this.tokens.length) return this.tokens[this.i];
858
+ return new EOFToken();
859
+ }
860
+ empty() {
861
+ return this.i >= this.tokens.length;
862
+ }
863
+ consumeToken() {
864
+ const tok = this.nextToken();
865
+ this.i++;
866
+ return tok;
867
+ }
868
+ discardToken() {
869
+ this.i++;
870
+ }
871
+ mark() {
872
+ this.marks.push(this.i);
873
+ return this;
874
+ }
875
+ restoreMark() {
876
+ if(this.marks.length) {
877
+ this.i = this.marks.pop();
878
+ return this;
879
+ }
880
+ throw new Error("No marks to restore.");
881
+ }
882
+ discardMark() {
883
+ if(this.marks.length) {
884
+ this.marks.pop();
885
+ return this;
886
+ }
887
+ throw new Error("No marks to restore.");
888
+ }
889
+ discardWhitespace() {
890
+ while(this.nextToken() instanceof WhitespaceToken) {
891
+ this.discardToken();
892
+ }
893
+ return this;
894
+ }
895
+ }
896
+
897
+ function parseerror(s, msg) {
898
+ console.log("Parse error at token " + s.i + ": " + s.tokens[s.i] + ".\n" + msg);
899
+ return true;
900
+ }
901
+
902
+ function consumeAStylesheetsContents(s) {
903
+ const rules = [];
904
+ while(1) {
905
+ const token = s.nextToken();
906
+ if(token instanceof WhitespaceToken) {
907
+ s.discardToken();
908
+ } else if(token instanceof EOFToken) {
909
+ return rules;
910
+ } else if(token instanceof CDOToken || token instanceof CDCToken) {
911
+ s.discardToken();
912
+ } else if(token instanceof AtKeywordToken) {
913
+ const rule = consumeAnAtRule(s)
914
+ if(rule) rules.push(rule);
915
+ } else {
916
+ const rule = consumeAQualifiedRule(s);
917
+ if(rule) rules.push(rule);
918
+ }
919
+ }
920
+ }
921
+
922
+ function consumeAnAtRule(s, nested=false) {
923
+ const token = s.consumeToken();
924
+ if(!(token instanceof AtKeywordToken))
925
+ throw new Error("consumeAnAtRule() called with an invalid token stream state.");
926
+ const rule = new AtRule(token.value);
927
+ while(1) {
928
+ const token = s.nextToken();
929
+ if(token instanceof SemicolonToken || token instanceof EOFToken) {
930
+ s.discardToken();
931
+ return filterValid(rule);
932
+ } else if(token instanceof CloseCurlyToken) {
933
+ if(nested) return filterValid(rule);
934
+ else {
935
+ parseerror(s, "Hit an unmatched } in the prelude of an at-rule.");
936
+ rule.prelude.push(s.consumeToken());
937
+ }
938
+ } else if(token instanceof OpenCurlyToken) {
939
+ [rule.declarations, rule.rules] = consumeABlock(s);
940
+ return filterValid(rule);
941
+ } else {
942
+ rule.prelude.push(consumeAComponentValue(s));
943
+ }
944
+ }
945
+ }
946
+
947
+ function consumeAQualifiedRule(s, nested=false, stopToken=EOFToken) {
948
+ var rule = new QualifiedRule();
949
+ while(1) {
950
+ const token = s.nextToken();
951
+ if(token instanceof EOFToken || token instanceof stopToken) {
952
+ parseerror(s, "Hit EOF or semicolon when trying to parse the prelude of a qualified rule.");
953
+ return;
954
+ } else if(token instanceof CloseCurlyToken) {
955
+ parseerror(s, "Hit an unmatched } in the prelude of a qualified rule.");
956
+ if(nested) return;
957
+ else {
958
+ rule.prelude.push(s.consumeToken());
959
+ }
960
+ } else if(token instanceof OpenCurlyToken) {
961
+ if(looksLikeACustomProperty(rule.prelude)) {
962
+ consumeTheRemnantsOfABadDeclaration(s, nested);
963
+ return;
964
+ }
965
+ [rule.declarations, rule.rules] = consumeABlock(s);
966
+ return filterValid(rule);
967
+ } else {
968
+ rule.prelude.push(consumeAComponentValue(s));
969
+ }
970
+ }
971
+ }
972
+
973
+ function looksLikeACustomProperty(tokens) {
974
+ let foundDashedIdent = false;
975
+ for(const token of tokens) {
976
+ if(token instanceof WhitespaceToken) continue;
977
+ if(!foundDashedIdent && token instanceof IdentToken && token.value.slice(0, 2) == "--") {
978
+ foundDashedIdent = true;
979
+ continue;
980
+ }
981
+ if(foundDashedIdent && token instanceof ColonToken) {
982
+ return true;
983
+ }
984
+ return false;
985
+ }
986
+ return false;
987
+ }
988
+
989
+ function consumeABlock(s) {
990
+ if(!(s.nextToken() instanceof OpenCurlyToken)) {
991
+ throw new Error("consumeABlock() called with an invalid token stream state.");
992
+ }
993
+ s.discardToken();
994
+ const [decls, rules] = consumeABlocksContents(s);
995
+ s.discardToken();
996
+ return [decls, rules];
997
+ }
998
+
999
+ function consumeABlocksContents(s) {
1000
+ const decls = [];
1001
+ const rules = [];
1002
+ while(1) {
1003
+ const token = s.nextToken();
1004
+ if(token instanceof WhitespaceToken || token instanceof SemicolonToken) {
1005
+ s.discardToken();
1006
+ } else if(token instanceof EOFToken || token instanceof CloseCurlyToken) {
1007
+ return [decls, rules];
1008
+ } else if(token instanceof AtKeywordToken) {
1009
+ const rule = consumeAnAtRule(s, true);
1010
+ if(rule) rules.push(rule);
1011
+ } else {
1012
+ s.mark();
1013
+ const decl = consumeADeclaration(s, true);
1014
+ if(decl) {
1015
+ decls.push(decl);
1016
+ s.discardMark();
1017
+ continue;
1018
+ }
1019
+ s.restoreMark();
1020
+ const rule = consumeAQualifiedRule(s, true, SemicolonToken);
1021
+ if(rule) rules.push(rule);
1022
+ }
1023
+ }
1024
+ }
1025
+
1026
+ function consumeADeclaration(s, nested=false) {
1027
+ let decl;
1028
+ if(s.nextToken() instanceof IdentToken) {
1029
+ decl = new Declaration(s.consumeToken().value);
1030
+ } else {
1031
+ consumeTheRemnantsOfABadDeclaration(s, nested);
1032
+ return;
1033
+ }
1034
+ s.discardWhitespace();
1035
+ if(s.nextToken() instanceof ColonToken) {
1036
+ s.discardToken();
1037
+ } else {
1038
+ consumeTheRemnantsOfABadDeclaration(s, nested);
1039
+ return;
1040
+ }
1041
+ s.discardWhitespace();
1042
+ decl.value = consumeAListOfComponentValues(s, nested, SemicolonToken);
1043
+
1044
+ var foundImportant = false;
1045
+ for(var i = decl.value.length - 1; i >= 0; i--) {
1046
+ if(decl.value[i] instanceof WhitespaceToken) {
1047
+ continue;
1048
+ } else if(!foundImportant && decl.value[i] instanceof IdentToken && asciiCaselessMatch(decl.value[i].value, "important")) {
1049
+ foundImportant = true;
1050
+ } else if(foundImportant && decl.value[i] instanceof DelimToken && decl.value[i].value == "!") {
1051
+ decl.value.length = i;
1052
+ decl.important = true;
1053
+ break;
1054
+ } else {
1055
+ break;
1056
+ }
1057
+ }
1058
+
1059
+ var i = decl.value.length - 1;
1060
+ while(decl.value[i] instanceof WhitespaceToken) {
1061
+ decl.value.length = i;
1062
+ i--;
1063
+ }
1064
+ return filterValid(decl);
1065
+ }
1066
+
1067
+ function consumeTheRemnantsOfABadDeclaration(s, nested) {
1068
+ while(1) {
1069
+ const token = s.nextToken();
1070
+ if(token instanceof EOFToken || token instanceof SemicolonToken) {
1071
+ s.discardToken();
1072
+ return;
1073
+ } else if(token instanceof CloseCurlyToken) {
1074
+ if(nested) return;
1075
+ else s.discardToken();
1076
+ } else {
1077
+ consumeAComponentValue(s);
1078
+ }
1079
+ }
1080
+ }
1081
+
1082
+ function consumeAListOfComponentValues(s, nested=false, stopToken=EOFToken) {
1083
+ const values = [];
1084
+ while(1) {
1085
+ const token = s.nextToken();
1086
+ if(token instanceof EOFToken || token instanceof stopToken) {
1087
+ return values;
1088
+ } else if(token instanceof CloseCurlyToken) {
1089
+ if(nested) return values;
1090
+ else {
1091
+ parseerror(s, "Hit an unmatched } in a declaration value.");
1092
+ values.push(s.consumeToken());
1093
+ }
1094
+ } else {
1095
+ values.push(consumeAComponentValue(s));
1096
+ }
1097
+ }
1098
+ }
1099
+
1100
+ function consumeAComponentValue(s) {
1101
+ const token = s.nextToken();
1102
+ if(token instanceof OpenCurlyToken || token instanceof OpenSquareToken || token instanceof OpenParenToken)
1103
+ return consumeASimpleBlock(s);
1104
+ if(token instanceof FunctionToken)
1105
+ return consumeAFunction(s);
1106
+ return s.consumeToken();
1107
+ }
1108
+
1109
+ function consumeASimpleBlock(s) {
1110
+ if(!s.nextToken().mirror) {
1111
+ throw new Error("consumeASimpleBlock() called with an invalid token stream state.");
1112
+ }
1113
+ const start = s.nextToken();
1114
+ const block = new SimpleBlock(start.toSource());
1115
+ s.discardToken();
1116
+ while(1) {
1117
+ const token = s.nextToken();
1118
+ if(token instanceof EOFToken || token instanceof start.mirror) {
1119
+ s.discardToken();
1120
+ return block;
1121
+ } else {
1122
+ block.value.push(consumeAComponentValue(s));
1123
+ }
1124
+ }
1125
+ }
1126
+
1127
+ function consumeAFunction(s) {
1128
+ if(!(s.nextToken() instanceof FunctionToken)) {
1129
+ throw new Error("consumeAFunction() called with an invalid token stream state.");
1130
+ }
1131
+ var func = new Func(s.consumeToken().value);
1132
+ while(1) {
1133
+ const token = s.nextToken();
1134
+ if(token instanceof EOFToken || token instanceof CloseParenToken) {
1135
+ s.discardToken();
1136
+ return func;
1137
+ } else {
1138
+ func.value.push(consumeAComponentValue(s));
1139
+ }
1140
+ }
1141
+ }
1142
+
1143
+ function isValidInContext(construct, context) {
1144
+ // Trivial validator, without any special CSS knowledge.
1145
+
1146
+ // All at-rules are valid, who cares.
1147
+ if(construct.type == "AT-RULE") return true;
1148
+
1149
+ // Exclude qualified rules that ended up with a semicolon
1150
+ // in their prelude.
1151
+ // (Can only happen at the top level of a stylesheet.)
1152
+ if(construct.type == "QUALIFIED-RULE") {
1153
+ for(const val of construct.prelude) {
1154
+ if(val.type == "SEMICOLON") return false;
1155
+ }
1156
+ return true;
1157
+ }
1158
+
1159
+ // Exclude properties that ended up with a {}-block
1160
+ // in their value, unless they're custom.
1161
+ if(construct.type == "DECLARATION") {
1162
+ if(construct.name.slice(0, 2) == "--") return true;
1163
+ for(const val of construct.value) {
1164
+ if(val.type == "BLOCK" && val.name == "{") return false;
1165
+ }
1166
+ return true;
1167
+ }
1168
+ }
1169
+
1170
+ function filterValid(construct, context) {
1171
+ if(isValidInContext(construct, context)) return construct;
1172
+ return;
1173
+ }
1174
+
1175
+ function normalizeInput(input) {
1176
+ if(typeof input == "string")
1177
+ return new TokenStream(tokenize(input));
1178
+ if(input instanceof TokenStream)
1179
+ return input;
1180
+ if(input.length !== undefined)
1181
+ return new TokenStream(input);
1182
+ else throw SyntaxError(input);
1183
+ }
1184
+
1185
+ function parseAStylesheet(s) {
1186
+ s = normalizeInput(s);
1187
+ var sheet = new Stylesheet();
1188
+ sheet.rules = consumeAStylesheetsContents(s);
1189
+ return sheet;
1190
+ }
1191
+
1192
+ function parseAStylesheetsContents(s) {
1193
+ s = normalizeInput(s);
1194
+ return consumeAStylesheetsContents(s);
1195
+ }
1196
+
1197
+ function parseABlocksContents(s) {
1198
+ s = normalizeInput(s);
1199
+ return consumeABlocksContents(s);
1200
+ }
1201
+
1202
+ function parseARule(s) {
1203
+ s = normalizeInput(s);
1204
+ let rule;
1205
+ s.discardWhitespace();
1206
+ if(s.nextToken() instanceof EOFToken) throw SyntaxError();
1207
+ if(s.nextToken() instanceof AtKeywordToken) {
1208
+ rule = consumeAnAtRule(s);
1209
+ } else {
1210
+ rule = consumeAQualifiedRule(s);
1211
+ if(!rule) throw SyntaxError();
1212
+ }
1213
+ s.discardWhitespace();
1214
+ if(s.nextToken() instanceof EOFToken) return rule;
1215
+ throw SyntaxError();
1216
+ }
1217
+
1218
+ function parseADeclaration(s) {
1219
+ s = normalizeInput(s);
1220
+ s.discardWhitespace();
1221
+ const decl = consumeADeclaration(s);
1222
+ if(decl) return decl
1223
+ throw SyntaxError();
1224
+ }
1225
+
1226
+ function parseAComponentValue(s) {
1227
+ s = normalizeInput(s);
1228
+ s.discardWhitespace();
1229
+ if(s.empty()) throw SyntaxError();
1230
+ const val = consumeAComponentValue(s);
1231
+ s.discardWhitespace();
1232
+ if(s.empty()) return val;
1233
+ throw SyntaxError();
1234
+ }
1235
+
1236
+ function parseAListOfComponentValues(s) {
1237
+ s = normalizeInput(s);
1238
+ return consumeAListOfComponentValues(s);
1239
+ }
1240
+
1241
+ function parseACommaSeparatedListOfComponentValues(s) {
1242
+ s = normalizeInput(s);
1243
+ const groups = [];
1244
+ while(!s.empty()) {
1245
+ groups.push(consumeAListOfComponentValues(s, false, CommaToken));
1246
+ s.discardToken();
1247
+ }
1248
+ return groups;
1249
+ }
1250
+
1251
+
1252
+ class CSSParserRule {
1253
+ constructor(type) { this.type = type; }
1254
+ toString(indent) {
1255
+ return JSON.stringify(this,null,indent);
1256
+ }
1257
+ }
1258
+
1259
+ class Stylesheet extends CSSParserRule {
1260
+ constructor() {
1261
+ super("STYLESHEET");
1262
+ this.rules = [];
1263
+ return this;
1264
+ }
1265
+ toJSON() {
1266
+ return {
1267
+ type: this.type,
1268
+ rules: this.rules,
1269
+ }
1270
+ }
1271
+ toSource() {
1272
+ return this.rules.map(x=>x.toSource()).join("\n");
1273
+ }
1274
+ }
1275
+
1276
+ class AtRule extends CSSParserRule {
1277
+ constructor(name) {
1278
+ super("AT-RULE");
1279
+ this.name = name;
1280
+ this.prelude = [];
1281
+ this.declarations = null;
1282
+ this.rules = null;
1283
+ return this;
1284
+ }
1285
+ toJSON() {
1286
+ return {
1287
+ type: this.type,
1288
+ name: this.name,
1289
+ prelude: this.prelude,
1290
+ declarations: this.declarations,
1291
+ rules: this.rules,
1292
+ }
1293
+ }
1294
+ toSource(indent=0) {
1295
+ let s = printIndent(indent) + "@" + escapeIdent(this.name);
1296
+ s += this.prelude.map(x=>x.toSource()).join("");
1297
+ if(this.declarations == null) {
1298
+ s += ";\n";
1299
+ return s;
1300
+ }
1301
+ s += "{\n";
1302
+ if(this.declarations.length) {
1303
+ s += this.declarations.map(x=>x.toSource(indent+1)).join("\n") + "\n";
1304
+ }
1305
+ if(this.rules.length) {
1306
+ s += this.rules.map(x=>x.toSource(indent+1)).join("\n") + "\n";
1307
+ }
1308
+ s += printIndent(indent) + "}";
1309
+ return s;
1310
+ }
1311
+ }
1312
+
1313
+ class QualifiedRule extends CSSParserRule {
1314
+ constructor() {
1315
+ super("QUALIFIED-RULE");
1316
+ this.prelude = [];
1317
+ this.declarations = [];
1318
+ this.rules = [];
1319
+ return this;
1320
+ }
1321
+ toJSON() {
1322
+ return {
1323
+ type: this.type,
1324
+ prelude: this.prelude,
1325
+ declarations: this.declarations,
1326
+ rules: this.rules,
1327
+ }
1328
+ }
1329
+ toSource(indent=0) {
1330
+ let s = printIndent(indent);
1331
+ s += this.prelude.map(x=>x.toSource()).join("");
1332
+ s += "{\n";
1333
+ if(this.declarations.length) {
1334
+ s += this.declarations.map(x=>x.toSource(indent+1)).join("\n") + "\n";
1335
+ }
1336
+ if(this.rules.length) {
1337
+ s += this.rules.map(x=>x.toSource(indent+1)).join("\n") + "\n";
1338
+ }
1339
+ s += printIndent(indent) + "}";
1340
+ return s;
1341
+ }
1342
+ }
1343
+
1344
+ class Declaration extends CSSParserRule {
1345
+ constructor(name) {
1346
+ super("DECLARATION")
1347
+ this.name = name;
1348
+ this.value = [];
1349
+ this.important = false;
1350
+ return this;
1351
+ }
1352
+ toJSON() {
1353
+ return {
1354
+ type: this.type,
1355
+ name: this.name,
1356
+ value: this.value,
1357
+ important: this.important,
1358
+ }
1359
+ }
1360
+ toSource(indent=0) {
1361
+ let s = printIndent(indent) + escapeIdent(this.name) + ": ";
1362
+ s += this.value.map(x=>x.toSource()).join("");
1363
+ if(this.important) {
1364
+ s += "!important";
1365
+ }
1366
+ s += ";";
1367
+ return s;
1368
+ }
1369
+ }
1370
+
1371
+ class SimpleBlock extends CSSParserRule {
1372
+ constructor(type) {
1373
+ super("BLOCK");
1374
+ this.name = type;
1375
+ this.value = [];
1376
+ return this;
1377
+ }
1378
+ toJSON() {
1379
+ return {
1380
+ type: this.type,
1381
+ name: this.name,
1382
+ value: this.value,
1383
+ }
1384
+ }
1385
+ toSource() {
1386
+ const mirror = {"{":"}", "[":"]", "(":")"};
1387
+ return this.name + this.value.map(x=>x.toSource()).join("") + mirror[this.name];
1388
+ }
1389
+ }
1390
+
1391
+ class Func extends CSSParserRule {
1392
+ constructor(name) {
1393
+ super("FUNCTION");
1394
+ this.name = name;
1395
+ this.value = [];
1396
+ return this;
1397
+ }
1398
+ toJSON() {
1399
+ return {
1400
+ type: this.type,
1401
+ name: this.name,
1402
+ value: this.value,
1403
+ }
1404
+ }
1405
+ toSource() {
1406
+ return escapeIdent(this.name) + "(" + this.value.map(x=>x.toSource()).join("") + ")";
1407
+ }
1408
+ }
1409
+
1410
+ function printIndent(level) {
1411
+ return "\t".repeat(level);
1412
+ }
1413
+
1414
+
1415
+ // Exportation.
1416
+ exports.CSSParserRule = CSSParserRule;
1417
+ exports.Stylesheet = Stylesheet;
1418
+ exports.AtRule = AtRule;
1419
+ exports.QualifiedRule = QualifiedRule;
1420
+ exports.Declaration = Declaration;
1421
+ exports.SimpleBlock = SimpleBlock;
1422
+ exports.Func = Func;
1423
+ exports.parseAStylesheet = parseAStylesheet;
1424
+ exports.parseAStylesheetsContents = parseAStylesheetsContents;
1425
+ exports.parseABlocksContents = parseABlocksContents;
1426
+ exports.parseARule = parseARule;
1427
+ exports.parseADeclaration = parseADeclaration;
1428
+ exports.parseAComponentValue = parseAComponentValue;
1429
+ exports.parseAListOfComponentValues = parseAListOfComponentValues;
1430
+ exports.parseACommaSeparatedListOfComponentValues = parseACommaSeparatedListOfComponentValues;
1431
+
1432
+ }));