@tbela99/css-parser 0.0.1-alpha5 → 0.0.1-rc1

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.
@@ -8,13 +8,14 @@
8
8
  // https://www.w3.org/TR/2021/CRD-css-syntax-3-20211224/#typedef-ident-token
9
9
  // '\\'
10
10
  const REVERSE_SOLIDUS = 0x5c;
11
+ const dimensionUnits = [
12
+ 'q', 'cap', 'ch', 'cm', 'cqb', 'cqh', 'cqi', 'cqmax', 'cqmin', 'cqw', 'dvb',
13
+ 'dvh', 'dvi', 'dvmax', 'dvmin', 'dvw', 'em', 'ex', 'ic', 'in', 'lh', 'lvb',
14
+ 'lvh', 'lvi', 'lvmax', 'lvw', 'mm', 'pc', 'pt', 'px', 'rem', 'rlh', 'svb',
15
+ 'svh', 'svi', 'svmin', 'svw', 'vb', 'vh', 'vi', 'vmax', 'vmin', 'vw'
16
+ ];
11
17
  function isLength(dimension) {
12
- return 'unit' in dimension && [
13
- 'q', 'cap', 'ch', 'cm', 'cqb', 'cqh', 'cqi', 'cqmax', 'cqmin', 'cqw', 'dvb',
14
- 'dvh', 'dvi', 'dvmax', 'dvmin', 'dvw', 'em', 'ex', 'ic', 'in', 'lh', 'lvb',
15
- 'lvh', 'lvi', 'lvmax', 'lvw', 'mm', 'pc', 'pt', 'px', 'rem', 'rlh', 'svb',
16
- 'svh', 'svi', 'svmin', 'svw', 'vb', 'vh', 'vi', 'vmax', 'vmin', 'vw'
17
- ].includes(dimension.unit.toLowerCase());
18
+ return 'unit' in dimension && dimensionUnits.includes(dimension.unit.toLowerCase());
18
19
  }
19
20
  function isResolution(dimension) {
20
21
  return 'unit' in dimension && ['dpi', 'dpcm', 'dppx', 'x'].includes(dimension.unit.toLowerCase());
@@ -239,6 +240,22 @@
239
240
  }
240
241
  return true;
241
242
  }
243
+ function isHexDigit(name) {
244
+ if (name.length || name.length > 6) {
245
+ return false;
246
+ }
247
+ for (let chr of name) {
248
+ let codepoint = chr.charCodeAt(0);
249
+ if (!isDigit(codepoint) &&
250
+ // A F
251
+ !(codepoint >= 0x41 && codepoint <= 0x46) &&
252
+ // a f
253
+ !(codepoint >= 0x61 && codepoint <= 0x66)) {
254
+ return false;
255
+ }
256
+ }
257
+ return true;
258
+ }
242
259
  function isFunction(name) {
243
260
  return name.endsWith('(') && isIdent(name.slice(0, -1));
244
261
  }
@@ -374,6 +391,7 @@
374
391
  },
375
392
  "border-width": {
376
393
  shorthand: "border-width",
394
+ map: "border",
377
395
  properties: [
378
396
  "border-top-width",
379
397
  "border-right-width",
@@ -384,6 +402,9 @@
384
402
  "Length",
385
403
  "Perc"
386
404
  ],
405
+ "default": [
406
+ "medium"
407
+ ],
387
408
  keywords: [
388
409
  "thin",
389
410
  "medium",
@@ -391,19 +412,24 @@
391
412
  ]
392
413
  },
393
414
  "border-top-width": {
415
+ map: "border",
394
416
  shorthand: "border-width"
395
417
  },
396
418
  "border-right-width": {
419
+ map: "border",
397
420
  shorthand: "border-width"
398
421
  },
399
422
  "border-bottom-width": {
423
+ map: "border",
400
424
  shorthand: "border-width"
401
425
  },
402
426
  "border-left-width": {
427
+ map: "border",
403
428
  shorthand: "border-width"
404
429
  },
405
430
  "border-style": {
406
431
  shorthand: "border-style",
432
+ map: "border",
407
433
  properties: [
408
434
  "border-top-style",
409
435
  "border-right-style",
@@ -412,6 +438,9 @@
412
438
  ],
413
439
  types: [
414
440
  ],
441
+ "default": [
442
+ "none"
443
+ ],
415
444
  keywords: [
416
445
  "none",
417
446
  "hidden",
@@ -426,19 +455,24 @@
426
455
  ]
427
456
  },
428
457
  "border-top-style": {
458
+ map: "border",
429
459
  shorthand: "border-style"
430
460
  },
431
461
  "border-right-style": {
462
+ map: "border",
432
463
  shorthand: "border-style"
433
464
  },
434
465
  "border-bottom-style": {
466
+ map: "border",
435
467
  shorthand: "border-style"
436
468
  },
437
469
  "border-left-style": {
470
+ map: "border",
438
471
  shorthand: "border-style"
439
472
  },
440
473
  "border-color": {
441
474
  shorthand: "border-color",
475
+ map: "border",
442
476
  properties: [
443
477
  "border-top-color",
444
478
  "border-right-color",
@@ -448,23 +482,95 @@
448
482
  types: [
449
483
  "Color"
450
484
  ],
485
+ "default": [
486
+ "currentcolor"
487
+ ],
451
488
  keywords: [
452
489
  ]
453
490
  },
454
491
  "border-top-color": {
492
+ map: "border",
455
493
  shorthand: "border-color"
456
494
  },
457
495
  "border-right-color": {
496
+ map: "border",
458
497
  shorthand: "border-color"
459
498
  },
460
499
  "border-bottom-color": {
500
+ map: "border",
461
501
  shorthand: "border-color"
462
502
  },
463
503
  "border-left-color": {
504
+ map: "border",
464
505
  shorthand: "border-color"
465
506
  }
466
507
  };
467
508
  var map = {
509
+ border: {
510
+ shorthand: "border",
511
+ pattern: "border-color border-style border-width",
512
+ keywords: [
513
+ "none"
514
+ ],
515
+ "default": [
516
+ "0",
517
+ "none"
518
+ ],
519
+ properties: {
520
+ "border-color": {
521
+ types: [
522
+ "Color"
523
+ ],
524
+ "default": [
525
+ "currentcolor"
526
+ ],
527
+ keywords: [
528
+ ]
529
+ },
530
+ "border-style": {
531
+ types: [
532
+ ],
533
+ "default": [
534
+ "none"
535
+ ],
536
+ keywords: [
537
+ "none",
538
+ "hidden",
539
+ "dotted",
540
+ "dashed",
541
+ "solid",
542
+ "double",
543
+ "groove",
544
+ "ridge",
545
+ "inset",
546
+ "outset"
547
+ ]
548
+ },
549
+ "border-width": {
550
+ types: [
551
+ "Length",
552
+ "Perc"
553
+ ],
554
+ "default": [
555
+ "medium"
556
+ ],
557
+ keywords: [
558
+ "thin",
559
+ "medium",
560
+ "thick"
561
+ ]
562
+ }
563
+ }
564
+ },
565
+ "border-color": {
566
+ shorthand: "border"
567
+ },
568
+ "border-style": {
569
+ shorthand: "border"
570
+ },
571
+ "border-width": {
572
+ shorthand: "border"
573
+ },
468
574
  outline: {
469
575
  shorthand: "outline",
470
576
  pattern: "outline-color outline-style outline-width",
@@ -481,12 +587,10 @@
481
587
  "Color"
482
588
  ],
483
589
  "default": [
484
- "currentColor",
485
- "invert"
590
+ "currentColor"
486
591
  ],
487
592
  keywords: [
488
- "currentColor",
489
- "invert"
593
+ "currentColor"
490
594
  ]
491
595
  },
492
596
  "outline-style": {
@@ -824,6 +928,7 @@
824
928
  "default": [
825
929
  "transparent"
826
930
  ],
931
+ multiple: true,
827
932
  keywords: [
828
933
  ]
829
934
  },
@@ -844,6 +949,7 @@
844
949
  "default": [
845
950
  "scroll"
846
951
  ],
952
+ multiple: true,
847
953
  keywords: [
848
954
  "scroll",
849
955
  "fixed",
@@ -856,6 +962,7 @@
856
962
  "default": [
857
963
  "border-box"
858
964
  ],
965
+ multiple: true,
859
966
  keywords: [
860
967
  "border-box",
861
968
  "padding-box",
@@ -869,6 +976,7 @@
869
976
  "default": [
870
977
  "padding-box"
871
978
  ],
979
+ multiple: true,
872
980
  keywords: [
873
981
  "border-box",
874
982
  "padding-box",
@@ -1458,7 +1566,7 @@
1458
1566
  }
1459
1567
 
1460
1568
  function render(data, opt = {}) {
1461
- const options = Object.assign(opt.compress ? {
1569
+ const options = Object.assign(opt.minify ?? true ? {
1462
1570
  indent: '',
1463
1571
  newLine: '',
1464
1572
  removeComments: true
@@ -1543,8 +1651,11 @@
1543
1651
  function renderToken(token, options = {}) {
1544
1652
  switch (token.typ) {
1545
1653
  case 'Color':
1546
- if (options.compress || options.colorConvert) {
1547
- let value = token.kin == 'hex' ? token.val.toLowerCase() : '';
1654
+ if (options.minify || options.colorConvert) {
1655
+ if (token.kin == 'lit' && token.val.toLowerCase() == 'currentcolor') {
1656
+ return 'currentcolor';
1657
+ }
1658
+ let value = token.kin == 'hex' ? token.val.toLowerCase() : (token.kin == 'lit' ? COLORS_NAMES[token.val.toLowerCase()] : '');
1548
1659
  if (token.val == 'rgb' || token.val == 'rgba') {
1549
1660
  value = rgb2Hex(token);
1550
1661
  }
@@ -1588,7 +1699,7 @@
1588
1699
  case 'UrlFunc':
1589
1700
  case 'Pseudo-class-func':
1590
1701
  // @ts-ignore
1591
- return ( /* options.compress && 'Pseudo-class-func' == token.typ && token.val.slice(0, 2) == '::' ? token.val.slice(1) :*/token.val ?? '') + '(' + token.chi.reduce((acc, curr) => {
1702
+ return ( /* options.minify && 'Pseudo-class-func' == token.typ && token.val.slice(0, 2) == '::' ? token.val.slice(1) :*/token.val ?? '') + '(' + token.chi.reduce((acc, curr) => {
1592
1703
  if (options.removeComments && curr.typ == 'Comment') {
1593
1704
  if (!options.preserveLicense || !curr.val.startsWith('/*!')) {
1594
1705
  return acc;
@@ -1679,21 +1790,45 @@
1679
1790
  case 'String':
1680
1791
  case 'Iden':
1681
1792
  case 'Delim':
1682
- return /* options.compress && 'Pseudo-class' == token.typ && '::' == token.val.slice(0, 2) ? token.val.slice(1) : */ token.val;
1793
+ return /* options.minify && 'Pseudo-class' == token.typ && '::' == token.val.slice(0, 2) ? token.val.slice(1) : */ token.val;
1683
1794
  }
1684
1795
  throw new Error(`unexpected token ${JSON.stringify(token, null, 1)}`);
1685
1796
  }
1686
1797
 
1687
1798
  function eq(a, b) {
1688
- if ((typeof a != 'object') || typeof b != 'object') {
1799
+ if (a == null || b == null) {
1800
+ return a == b;
1801
+ }
1802
+ if (typeof a != 'object' || typeof b != 'object') {
1689
1803
  return a === b;
1690
1804
  }
1805
+ if (Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) {
1806
+ return false;
1807
+ }
1808
+ if (Array.isArray(a)) {
1809
+ if (a.length != b.length) {
1810
+ return false;
1811
+ }
1812
+ let i = 0;
1813
+ for (; i < a.length; i++) {
1814
+ if (!eq(a[i], b[i])) {
1815
+ return false;
1816
+ }
1817
+ }
1818
+ return true;
1819
+ }
1691
1820
  const k1 = Object.keys(a);
1692
1821
  const k2 = Object.keys(b);
1693
- return k1.length == k2.length &&
1694
- k1.every((key) => {
1695
- return eq(a[key], b[key]);
1696
- });
1822
+ if (k1.length != k2.length) {
1823
+ return false;
1824
+ }
1825
+ let key;
1826
+ for (key of k1) {
1827
+ if (!eq(a[key], b[key])) {
1828
+ return false;
1829
+ }
1830
+ }
1831
+ return true;
1697
1832
  }
1698
1833
 
1699
1834
  class PropertySet {
@@ -1705,8 +1840,7 @@
1705
1840
  }
1706
1841
  add(declaration) {
1707
1842
  if (declaration.nam == this.config.shorthand) {
1708
- this.declarations.clear();
1709
- this.declarations.set(declaration.nam, declaration);
1843
+ this.declarations = new Map;
1710
1844
  }
1711
1845
  else {
1712
1846
  // expand shorthand
@@ -1729,6 +1863,10 @@
1729
1863
  }
1730
1864
  if (token.typ != 'Whitespace' && token.typ != 'Comment') {
1731
1865
  if (token.typ == 'Iden' && this.config.keywords.includes(token.val)) {
1866
+ if (tokens.length == 0) {
1867
+ tokens.push([]);
1868
+ current++;
1869
+ }
1732
1870
  tokens[current].push(token);
1733
1871
  }
1734
1872
  if (token.typ == 'Literal' && token.val == this.config.separator) {
@@ -1744,10 +1882,6 @@
1744
1882
  this.declarations.delete(this.config.shorthand);
1745
1883
  for (const values of tokens) {
1746
1884
  this.config.properties.forEach((property, index) => {
1747
- // if (property == declaration.nam) {
1748
- //
1749
- // return;
1750
- // }
1751
1885
  if (!this.declarations.has(property)) {
1752
1886
  this.declarations.set(property, {
1753
1887
  typ: 'Declaration',
@@ -1776,30 +1910,20 @@
1776
1910
  this.declarations.set(declaration.nam, declaration);
1777
1911
  return this;
1778
1912
  }
1779
- // declaration.chi = declaration.chi.reduce((acc: Token[], token: Token) => {
1780
- //
1781
- // if (this.config.types.includes(token.typ) || ('0' == (<DimensionToken>token).chi && (
1782
- // this.config.types.includes('Length') ||
1783
- // this.config.types.includes('Angle') ||
1784
- // this.config.types.includes('Dimension'))) || (token.typ == 'Iden' && this.config.keywords.includes(token.chi))) {
1785
- //
1786
- // acc.push(token);
1787
- // }
1788
- //
1789
- // return acc;
1790
- // }, <Token[]>[]);
1791
- this.declarations.set(declaration.nam, declaration);
1792
1913
  }
1914
+ this.declarations.set(declaration.nam, declaration);
1793
1915
  return this;
1794
1916
  }
1917
+ isShortHand() {
1918
+ if (this.declarations.has(this.config.shorthand)) {
1919
+ return this.declarations.size == 1;
1920
+ }
1921
+ return this.config.properties.length == this.declarations.size;
1922
+ }
1795
1923
  [Symbol.iterator]() {
1796
1924
  let iterator;
1797
1925
  const declarations = this.declarations;
1798
- if (declarations.size < this.config.properties.length || this.config.properties.some((property, index) => {
1799
- return !declarations.has(property) || (index > 0 &&
1800
- // @ts-ignore
1801
- declarations.get(property).val.length != declarations.get(this.config.properties[Math.floor(index / 2)]).val.length);
1802
- })) {
1926
+ if (declarations.size < this.config.properties.length) {
1803
1927
  iterator = declarations.values();
1804
1928
  }
1805
1929
  else {
@@ -1857,17 +1981,20 @@
1857
1981
  return acc;
1858
1982
  }, [])
1859
1983
  }][Symbol.iterator]();
1860
- return {
1861
- next() {
1862
- return iterator.next();
1863
- }
1864
- };
1984
+ // return {
1985
+ // next() {
1986
+ //
1987
+ // return iterator.next();
1988
+ // }
1989
+ // }
1865
1990
  }
1866
- return {
1867
- next() {
1868
- return iterator.next();
1869
- }
1870
- };
1991
+ return iterator;
1992
+ // return {
1993
+ // next() {
1994
+ //
1995
+ // return iterator.next();
1996
+ // }
1997
+ // }
1871
1998
  }
1872
1999
  }
1873
2000
 
@@ -1882,34 +2009,7 @@
1882
2009
  return false;
1883
2010
  }
1884
2011
 
1885
- function getTokenType(val) {
1886
- if (val == 'transparent' || val == 'currentcolor') {
1887
- return {
1888
- typ: 'Color',
1889
- val,
1890
- kin: 'lit'
1891
- };
1892
- }
1893
- if (val.endsWith('%')) {
1894
- return {
1895
- typ: 'Perc',
1896
- val: val.slice(0, -1)
1897
- };
1898
- }
1899
- return {
1900
- typ: isNumber(val) ? 'Number' : 'Iden',
1901
- val
1902
- };
1903
- }
1904
- function parseString(val) {
1905
- return val.split(/\s/).map(getTokenType).reduce((acc, curr) => {
1906
- if (acc.length > 0) {
1907
- acc.push({ typ: 'Whitespace' });
1908
- }
1909
- acc.push(curr);
1910
- return acc;
1911
- }, []);
1912
- }
2012
+ const propertiesConfig = getConfig();
1913
2013
  class PropertyMap {
1914
2014
  config;
1915
2015
  declarations;
@@ -1924,7 +2024,7 @@
1924
2024
  }
1925
2025
  add(declaration) {
1926
2026
  if (declaration.nam == this.config.shorthand) {
1927
- this.declarations.clear();
2027
+ this.declarations = new Map;
1928
2028
  this.declarations.set(declaration.nam, declaration);
1929
2029
  }
1930
2030
  else {
@@ -2001,8 +2101,7 @@
2001
2101
  const defaults = parseString(props.default[0]);
2002
2102
  if (!(property in tokens)) {
2003
2103
  tokens[property] = [
2004
- [...defaults
2005
- ]
2104
+ [...defaults]
2006
2105
  ];
2007
2106
  }
2008
2107
  else {
@@ -2036,145 +2135,229 @@
2036
2135
  }, new Map);
2037
2136
  }
2038
2137
  }
2039
- this.declarations.set(declaration.nam, declaration);
2138
+ // @ts-ignore
2139
+ const config = propertiesConfig.properties[declaration.nam];
2140
+ let property = declaration.nam;
2141
+ if (config != null) {
2142
+ property = config.shorthand;
2143
+ let value = this.declarations.get(property);
2144
+ if (!(value instanceof PropertySet)) {
2145
+ // @ts-ignore
2146
+ this.declarations.set(property, new PropertySet(propertiesConfig.properties[config.shorthand]));
2147
+ // Token[]
2148
+ if (value != null) {
2149
+ // @ts-ignore
2150
+ this.declarations.get(property).add(value);
2151
+ }
2152
+ }
2153
+ this.declarations.get(property).add(declaration);
2154
+ }
2155
+ else {
2156
+ this.declarations.set(declaration.nam, declaration);
2157
+ }
2040
2158
  }
2041
2159
  return this;
2042
2160
  }
2043
2161
  [Symbol.iterator]() {
2044
- let requiredCount = Object.keys(this.config.properties).reduce((acc, curr) => this.declarations.has(curr) && this.config.properties[curr].required ? ++acc : acc, 0);
2045
- if (requiredCount == 0) {
2046
- requiredCount = this.declarations.size;
2047
- }
2048
- if (requiredCount < this.requiredCount) {
2049
- // if (this.declarations.size == 1 && this.declarations.has(this.config.shorthand)) {
2050
- //
2051
- // this.declarations
2052
- // }
2053
- return this.declarations.values();
2054
- }
2055
- let count = 0;
2056
- const separator = this.config.separator;
2057
- const tokens = {};
2058
- // @ts-ignore
2059
- const valid = Object.entries(this.config.properties).reduce((acc, curr) => {
2060
- if (!this.declarations.has(curr[0])) {
2061
- if (curr[1].required) {
2062
- acc.push(curr[0]);
2162
+ let iterable;
2163
+ let requiredCount = 0;
2164
+ let property;
2165
+ let isShorthand = true;
2166
+ for (property of Object.keys(this.config.properties)) {
2167
+ if (this.config.properties[property].required) {
2168
+ if (!this.declarations.has(property)) {
2169
+ isShorthand = false;
2170
+ break;
2063
2171
  }
2064
- return acc;
2065
- }
2066
- let current = 0;
2067
- const props = this.config.properties[curr[0]];
2068
- // @ts-ignore
2069
- for (const val of this.declarations.get(curr[0]).val) {
2070
- if (separator != null && separator.typ == val.typ && eq(separator, val)) {
2071
- current++;
2072
- if (tokens[curr[0]].length == current) {
2073
- tokens[curr[0]].push([]);
2172
+ else {
2173
+ const val = this.declarations.get(property);
2174
+ if (val instanceof PropertySet && !val.isShortHand()) {
2175
+ isShorthand = false;
2176
+ break;
2074
2177
  }
2075
- continue;
2076
- }
2077
- if (val.typ == 'Whitespace' || val.typ == 'Comment') {
2078
- continue;
2079
- }
2080
- if (props.multiple && props.separator != null && props.separator.typ == val.typ && eq(val, props.separator)) {
2081
- continue;
2082
- }
2083
- if (matchType(val, curr[1])) {
2084
- if (!(curr[0] in tokens)) {
2085
- tokens[curr[0]] = [[]];
2178
+ else {
2179
+ requiredCount++;
2086
2180
  }
2087
- // is default value
2088
- tokens[curr[0]][current].push(val);
2089
- continue;
2090
2181
  }
2091
- acc.push(curr[0]);
2092
- break;
2093
2182
  }
2094
- if (count == 0) {
2095
- count = current;
2096
- }
2097
- return acc;
2098
- }, []);
2099
- if (valid.length > 0 || Object.values(tokens).every(v => v.every(v => v.length == count))) {
2100
- return this.declarations.values();
2101
2183
  }
2102
- const values = Object.entries(tokens).reduce((acc, curr) => {
2103
- const props = this.config.properties[curr[0]];
2104
- for (let i = 0; i < curr[1].length; i++) {
2105
- if (acc.length == i) {
2106
- acc.push([]);
2107
- }
2108
- let values = curr[1][i].reduce((acc, curr) => {
2109
- if (acc.length > 0) {
2110
- acc.push({ typ: 'Whitespace' });
2184
+ if (requiredCount == 0) {
2185
+ requiredCount = this.declarations.size;
2186
+ }
2187
+ if (!isShorthand || requiredCount < this.requiredCount) {
2188
+ // @ts-ignore
2189
+ iterable = this.declarations.values();
2190
+ }
2191
+ else {
2192
+ let count = 0;
2193
+ const separator = this.config.separator;
2194
+ const tokens = {};
2195
+ // @ts-ignore
2196
+ /* const valid: string[] =*/ Object.entries(this.config.properties).reduce((acc, curr) => {
2197
+ if (!this.declarations.has(curr[0])) {
2198
+ if (curr[1].required) {
2199
+ acc.push(curr[0]);
2111
2200
  }
2112
- acc.push(curr);
2113
2201
  return acc;
2114
- }, []);
2115
- if (props.default.includes(curr[1][i].reduce((acc, curr) => acc + renderToken(curr) + ' ', '').trimEnd())) {
2116
- continue;
2117
2202
  }
2118
- values = values.filter((val) => {
2203
+ let current = 0;
2204
+ const props = this.config.properties[curr[0]];
2205
+ const declaration = this.declarations.get(curr[0]);
2206
+ // @ts-ignore
2207
+ for (const val of (declaration instanceof PropertySet ? [...declaration][0] : declaration).val) {
2208
+ if (separator != null && separator.typ == val.typ && eq(separator, val)) {
2209
+ current++;
2210
+ if (tokens[curr[0]].length == current) {
2211
+ tokens[curr[0]].push([]);
2212
+ }
2213
+ continue;
2214
+ }
2119
2215
  if (val.typ == 'Whitespace' || val.typ == 'Comment') {
2120
- return false;
2216
+ continue;
2121
2217
  }
2122
- return !(val.typ == 'Iden' && props.default.includes(val.val));
2123
- });
2124
- if (values.length > 0) {
2125
- if ('mapping' in props) {
2126
- // @ts-ignore
2127
- if (!('constraints' in props) || !('max' in props.constraints) || values.length <= props.constraints.mapping.max) {
2128
- let i = values.length;
2129
- while (i--) {
2218
+ if (props.multiple && props.separator != null && props.separator.typ == val.typ && eq(props.separator, val)) {
2219
+ continue;
2220
+ }
2221
+ if (matchType(val, curr[1])) {
2222
+ if (!(curr[0] in tokens)) {
2223
+ tokens[curr[0]] = [[]];
2224
+ }
2225
+ // is default value
2226
+ tokens[curr[0]][current].push(val);
2227
+ // continue;
2228
+ }
2229
+ else {
2230
+ acc.push(curr[0]);
2231
+ break;
2232
+ }
2233
+ }
2234
+ if (count == 0) {
2235
+ count = current;
2236
+ }
2237
+ return acc;
2238
+ }, []);
2239
+ count++;
2240
+ if (!Object.values(tokens).every(v => v.length == count)) {
2241
+ // @ts-ignore
2242
+ iterable = this.declarations.values();
2243
+ }
2244
+ else {
2245
+ const values = Object.entries(tokens).reduce((acc, curr) => {
2246
+ const props = this.config.properties[curr[0]];
2247
+ for (let i = 0; i < curr[1].length; i++) {
2248
+ if (acc.length == i) {
2249
+ acc.push([]);
2250
+ }
2251
+ let values = curr[1][i].reduce((acc, curr) => {
2252
+ if (acc.length > 0) {
2253
+ acc.push({ typ: 'Whitespace' });
2254
+ }
2255
+ acc.push(curr);
2256
+ return acc;
2257
+ }, []);
2258
+ // @todo remove renderToken call
2259
+ if (props.default.includes(curr[1][i].reduce((acc, curr) => acc + renderToken(curr) + ' ', '').trimEnd())) {
2260
+ continue;
2261
+ }
2262
+ let doFilterDefault = true;
2263
+ if (curr[0] in propertiesConfig.properties) {
2264
+ for (let v of values) {
2265
+ if (!['Whitespace', 'Comment', 'Iden'].includes(v.typ)
2266
+ || (v.typ == 'Iden' && !this.config.properties[curr[0]].default.includes(v.val))) {
2267
+ doFilterDefault = false;
2268
+ break;
2269
+ }
2270
+ }
2271
+ }
2272
+ // remove default values
2273
+ values = values.filter((val) => {
2274
+ if (val.typ == 'Whitespace' || val.typ == 'Comment') {
2275
+ return false;
2276
+ }
2277
+ return !doFilterDefault || !(val.typ == 'Iden' && props.default.includes(val.val));
2278
+ });
2279
+ if (values.length > 0) {
2280
+ if ('mapping' in props) {
2130
2281
  // @ts-ignore
2131
- if (values[i].typ == 'Iden' && values[i].val in props.mapping) {
2132
- // @ts-ignore
2133
- values.splice(i, 1, ...parseString(props.mapping[values[i].val]));
2282
+ if (!('constraints' in props) || !('max' in props.constraints) || values.length <= props.constraints.mapping.max) {
2283
+ let i = values.length;
2284
+ while (i--) {
2285
+ // @ts-ignore
2286
+ if (values[i].typ == 'Iden' && values[i].val in props.mapping) {
2287
+ // @ts-ignore
2288
+ values.splice(i, 1, ...parseString(props.mapping[values[i].val]));
2289
+ }
2290
+ }
2134
2291
  }
2135
2292
  }
2293
+ if ('prefix' in props) {
2294
+ // @ts-ignore
2295
+ acc[i].push({ ...props.prefix });
2296
+ }
2297
+ else if (acc[i].length > 0) {
2298
+ acc[i].push({ typ: 'Whitespace' });
2299
+ }
2300
+ acc[i].push(...values.reduce((acc, curr) => {
2301
+ if (acc.length > 0) {
2302
+ // @ts-ignore
2303
+ acc.push({ ...(props.separator ?? { typ: 'Whitespace' }) });
2304
+ }
2305
+ // @ts-ignore
2306
+ acc.push(curr);
2307
+ return acc;
2308
+ }, []));
2136
2309
  }
2137
2310
  }
2138
- if ('prefix' in props) {
2139
- // @ts-ignore
2140
- acc[i].push({ ...props.prefix });
2311
+ return acc;
2312
+ }, []).reduce((acc, curr) => {
2313
+ if (acc.length > 0) {
2314
+ acc.push({ ...separator });
2141
2315
  }
2142
- else if (acc[i].length > 0) {
2143
- acc[i].push({ typ: 'Whitespace' });
2316
+ if (curr.length == 0 && this.config.default.length > 0) {
2317
+ curr.push(...parseString(this.config.default[0]).reduce((acc, curr) => {
2318
+ if (acc.length > 0) {
2319
+ acc.push({ typ: 'Whitespace' });
2320
+ }
2321
+ acc.push(curr);
2322
+ return acc;
2323
+ }, []));
2144
2324
  }
2145
- acc[i].push(...values.reduce((acc, curr) => {
2146
- if (acc.length > 0) {
2325
+ acc.push(...curr);
2326
+ return acc;
2327
+ }, []);
2328
+ iterable = [{
2329
+ typ: 'Declaration',
2330
+ nam: this.config.shorthand,
2331
+ val: values
2332
+ }][Symbol.iterator]();
2333
+ }
2334
+ }
2335
+ const iterators = [];
2336
+ return {
2337
+ // @ts-ignore
2338
+ next() {
2339
+ let v = iterable.next();
2340
+ while (v.done || v.value instanceof PropertySet) {
2341
+ if (v.value instanceof PropertySet) {
2342
+ // @ts-ignore
2343
+ iterators.push(iterable);
2344
+ iterable = v.value[Symbol.iterator]();
2345
+ v = iterable.next();
2346
+ }
2347
+ if (v.done) {
2348
+ if (iterators.length > 0) {
2147
2349
  // @ts-ignore
2148
- acc.push({ ...(props.separator ?? { typ: 'Whitespace' }) });
2350
+ iterable = iterators.pop();
2351
+ v = iterable.next();
2352
+ }
2353
+ if (v.done && iterators.length == 0) {
2354
+ break;
2149
2355
  }
2150
- // @ts-ignore
2151
- acc.push(curr);
2152
- return acc;
2153
- }, []));
2154
- }
2155
- }
2156
- return acc;
2157
- }, []).reduce((acc, curr) => {
2158
- if (acc.length > 0) {
2159
- acc.push({ ...separator });
2160
- }
2161
- if (curr.length == 0) {
2162
- curr.push(...this.config.default[0].split(/\s/).map(getTokenType).reduce((acc, curr) => {
2163
- if (acc.length > 0) {
2164
- acc.push({ typ: 'Whitespace' });
2165
2356
  }
2166
- acc.push(curr);
2167
- return acc;
2168
- }, []));
2357
+ }
2358
+ return v;
2169
2359
  }
2170
- acc.push(...curr);
2171
- return acc;
2172
- }, []);
2173
- return [{
2174
- typ: 'Declaration',
2175
- nam: this.config.shorthand,
2176
- val: values
2177
- }][Symbol.iterator]();
2360
+ };
2178
2361
  }
2179
2362
  }
2180
2363
 
@@ -2184,33 +2367,61 @@
2184
2367
  constructor() {
2185
2368
  this.declarations = new Map;
2186
2369
  }
2370
+ set(nam, value) {
2371
+ return this.add({ typ: 'Declaration', nam, val: Array.isArray(value) ? value : parseString(String(value)) });
2372
+ }
2187
2373
  add(declaration) {
2188
2374
  if (declaration.typ != 'Declaration') {
2189
2375
  this.declarations.set(Number(Math.random().toString().slice(2)).toString(36), declaration);
2190
2376
  return this;
2191
2377
  }
2192
- const propertyName = declaration.nam;
2378
+ let propertyName = declaration.nam;
2379
+ let shortHandType;
2380
+ let shorthand;
2193
2381
  if (propertyName in config.properties) {
2194
2382
  // @ts-ignore
2195
- const shorthand = config.properties[propertyName].shorthand;
2196
- if (!this.declarations.has(shorthand)) {
2383
+ if ('map' in config.properties[propertyName]) {
2384
+ shortHandType = 'map';
2197
2385
  // @ts-ignore
2198
- this.declarations.set(shorthand, new PropertySet(config.properties[shorthand]));
2386
+ shorthand = config.properties[propertyName].map;
2199
2387
  }
2200
- this.declarations.get(shorthand).add(declaration);
2201
- return this;
2388
+ else {
2389
+ shortHandType = 'set';
2390
+ // @ts-ignore
2391
+ shorthand = config.properties[propertyName].shorthand;
2392
+ }
2393
+ }
2394
+ else if (propertyName in config.map) {
2395
+ shortHandType = 'map';
2396
+ // @ts-ignore
2397
+ shorthand = config.map[propertyName].shorthand;
2202
2398
  }
2203
- if (propertyName in config.map) {
2399
+ // @ts-ignore
2400
+ if (shortHandType == 'map') {
2204
2401
  // @ts-ignore
2205
- const shorthand = config.map[propertyName].shorthand;
2206
2402
  if (!this.declarations.has(shorthand)) {
2207
2403
  // @ts-ignore
2208
2404
  this.declarations.set(shorthand, new PropertyMap(config.map[shorthand]));
2209
2405
  }
2406
+ // @ts-ignore
2210
2407
  this.declarations.get(shorthand).add(declaration);
2211
- return this;
2408
+ // return this;
2409
+ }
2410
+ // @ts-ignore
2411
+ else if (shortHandType == 'set') {
2412
+ // @ts-ignore
2413
+ // const shorthand: string = <string>config.properties[propertyName].shorthand;
2414
+ if (!this.declarations.has(shorthand)) {
2415
+ // @ts-ignore
2416
+ this.declarations.set(shorthand, new PropertySet(config.properties[shorthand]));
2417
+ }
2418
+ // @ts-ignore
2419
+ this.declarations.get(shorthand).add(declaration);
2420
+ // return this;
2421
+ }
2422
+ else {
2423
+ this.declarations.set(propertyName, declaration);
2212
2424
  }
2213
- this.declarations.set(propertyName, declaration);
2214
2425
  return this;
2215
2426
  }
2216
2427
  [Symbol.iterator]() {
@@ -2239,56 +2450,300 @@
2239
2450
  }
2240
2451
  }
2241
2452
 
2242
- const configuration = getConfig();
2243
2453
  const combinators = ['+', '>', '~'];
2244
2454
  const notEndingWith = ['(', '['].concat(combinators);
2245
- function wrapNodes(previous, node, match, ast, i, nodeIndex) {
2246
- // @ts-ignore
2247
- let pSel = match.selector1.reduce(reducer, []).join(',');
2248
- // @ts-ignore
2249
- let nSel = match.selector2.reduce(reducer, []).join(',');
2250
- // @ts-ignore
2251
- const wrapper = { ...previous, chi: [], sel: match.match.reduce(reducer, []).join(',') };
2252
- // @ts-ignore
2253
- Object.defineProperty(wrapper, 'raw', {
2254
- enumerable: false,
2255
- writable: true,
2455
+ function minify(ast, options = {}, recursive = false) {
2456
+ function wrapNodes(previous, node, match, ast, i, nodeIndex) {
2256
2457
  // @ts-ignore
2257
- value: match.match.map(t => t.slice())
2258
- });
2259
- if (pSel == '&' || pSel === '') {
2458
+ let pSel = match.selector1.reduce(reducer, []).join(',');
2459
+ // @ts-ignore
2460
+ let nSel = match.selector2.reduce(reducer, []).join(',');
2260
2461
  // @ts-ignore
2261
- wrapper.chi.push(...previous.chi);
2462
+ const wrapper = { ...previous, chi: [], sel: match.match.reduce(reducer, []).join(',') };
2262
2463
  // @ts-ignore
2263
- if ((nSel == '&' || nSel === '') && hasOnlyDeclarations(previous)) {
2464
+ Object.defineProperty(wrapper, 'raw', {
2465
+ enumerable: false,
2466
+ writable: true,
2264
2467
  // @ts-ignore
2265
- wrapper.chi.push(...node.chi);
2468
+ value: match.match.map(t => t.slice())
2469
+ });
2470
+ if (pSel == '&' || pSel === '') {
2471
+ // @ts-ignore
2472
+ wrapper.chi.push(...previous.chi);
2473
+ // @ts-ignore
2474
+ if ((nSel == '&' || nSel === '') && hasOnlyDeclarations(previous)) {
2475
+ // @ts-ignore
2476
+ wrapper.chi.push(...node.chi);
2477
+ }
2478
+ else {
2479
+ // @ts-ignore
2480
+ wrapper.chi.push(node);
2481
+ }
2266
2482
  }
2267
2483
  else {
2268
2484
  // @ts-ignore
2269
- wrapper.chi.push(node);
2485
+ wrapper.chi.push(previous, node);
2270
2486
  }
2487
+ // @ts-ignore
2488
+ ast.chi.splice(i, 1, wrapper);
2489
+ // @ts-ignore
2490
+ ast.chi.splice(nodeIndex, 1);
2491
+ // @ts-ignore
2492
+ previous.sel = pSel;
2493
+ // @ts-ignore
2494
+ previous.raw = match.selector1;
2495
+ // @ts-ignore
2496
+ node.sel = nSel;
2497
+ // @ts-ignore
2498
+ node.raw = match.selector2;
2499
+ reduceRuleSelector(wrapper);
2500
+ return wrapper;
2271
2501
  }
2272
- else {
2502
+ function reducer(acc, curr, index, array) {
2503
+ // trim :is()
2504
+ if (array.length == 1 && array[0][0] == ':is(' && array[0].at(-1) == ')') {
2505
+ curr = curr.slice(1, -1);
2506
+ }
2507
+ if (curr[0] == '&') {
2508
+ if (curr[1] == ' ' && !isIdent(curr[2]) && !isFunction(curr[2])) {
2509
+ curr.splice(0, 2);
2510
+ }
2511
+ else if (combinators.includes(curr[1])) {
2512
+ curr.splice(0, 1);
2513
+ }
2514
+ }
2515
+ else if (ast.typ == 'Rule' && (isIdent(curr[0]) || isFunction(curr[0]))) {
2516
+ curr.unshift('&', ' ');
2517
+ }
2518
+ acc.push(curr.join(''));
2519
+ return acc;
2520
+ }
2521
+ function diff(n1, n2, options = {}) {
2522
+ let node1 = n1;
2523
+ let node2 = n2;
2524
+ let exchanged = false;
2525
+ if (node1.chi.length > node2.chi.length) {
2526
+ const t = node1;
2527
+ node1 = node2;
2528
+ node2 = t;
2529
+ exchanged = true;
2530
+ }
2531
+ let i = node1.chi.length;
2532
+ let j = node2.chi.length;
2533
+ if (i == 0 || j == 0) {
2534
+ // @ts-ignore
2535
+ return null;
2536
+ }
2537
+ // @ts-ignore
2538
+ const raw1 = node1.raw;
2539
+ // @ts-ignore
2540
+ const raw2 = node2.raw;
2541
+ // @ts-ignore
2542
+ node1 = { ...node1, chi: node1.chi.slice() };
2543
+ node2 = { ...node2, chi: node2.chi.slice() };
2544
+ if (raw1 != null) {
2545
+ Object.defineProperty(node1, 'raw', { enumerable: false, writable: true, value: raw1 });
2546
+ }
2547
+ if (raw2 != null) {
2548
+ Object.defineProperty(node2, 'raw', { enumerable: false, writable: true, value: raw2 });
2549
+ }
2550
+ const intersect = [];
2551
+ while (i--) {
2552
+ if (node1.chi[i].typ == 'Comment') {
2553
+ continue;
2554
+ }
2555
+ j = node2.chi.length;
2556
+ if (j == 0) {
2557
+ break;
2558
+ }
2559
+ while (j--) {
2560
+ if (node2.chi[j].typ == 'Comment') {
2561
+ continue;
2562
+ }
2563
+ if (node1.chi[i].nam == node2.chi[j].nam) {
2564
+ if (eq(node1.chi[i], node2.chi[j])) {
2565
+ intersect.push(node1.chi[i]);
2566
+ node1.chi.splice(i, 1);
2567
+ node2.chi.splice(j, 1);
2568
+ break;
2569
+ }
2570
+ }
2571
+ }
2572
+ }
2273
2573
  // @ts-ignore
2274
- wrapper.chi.push(previous, node);
2574
+ const result = (intersect.length == 0 ? null : {
2575
+ ...node1,
2576
+ // @ts-ignore
2577
+ sel: [...new Set([...(n1?.raw?.reduce(reducer, []) || splitRule(n1.sel)).concat(n2?.raw?.reduce(reducer, []) || splitRule(n2.sel))])].join(','),
2578
+ chi: intersect.reverse()
2579
+ });
2580
+ if (result == null || [n1, n2].reduce((acc, curr) => curr.chi.length == 0 ? acc : acc + render(curr, options).code.length, 0) <= [node1, node2, result].reduce((acc, curr) => curr.chi.length == 0 ? acc : acc + render(curr, options).code.length, 0)) {
2581
+ // @ts-ignore
2582
+ return null;
2583
+ }
2584
+ return { result, node1: exchanged ? node2 : node1, node2: exchanged ? node2 : node2 };
2585
+ }
2586
+ function matchSelectors(selector1, selector2, parentType) {
2587
+ let match = [[]];
2588
+ const j = Math.min(selector1.reduce((acc, curr) => Math.min(acc, curr.length), selector1.length > 0 ? selector1[0].length : 0), selector2.reduce((acc, curr) => Math.min(acc, curr.length), selector2.length > 0 ? selector2[0].length : 0));
2589
+ let i = 0;
2590
+ let k;
2591
+ let l;
2592
+ let token;
2593
+ let matching = true;
2594
+ let matchFunction = 0;
2595
+ let inAttr = 0;
2596
+ for (; i < j; i++) {
2597
+ k = 0;
2598
+ token = selector1[0][i];
2599
+ for (; k < selector1.length; k++) {
2600
+ if (selector1[k][i] != token) {
2601
+ matching = false;
2602
+ break;
2603
+ }
2604
+ }
2605
+ if (matching) {
2606
+ l = 0;
2607
+ for (; l < selector2.length; l++) {
2608
+ if (selector2[l][i] != token) {
2609
+ matching = false;
2610
+ break;
2611
+ }
2612
+ }
2613
+ }
2614
+ if (!matching) {
2615
+ break;
2616
+ }
2617
+ if (token == ',') {
2618
+ match.push([]);
2619
+ }
2620
+ else {
2621
+ if (token.endsWith('(')) {
2622
+ matchFunction++;
2623
+ }
2624
+ if (token.endsWith('[')) {
2625
+ inAttr++;
2626
+ }
2627
+ else if (token == ')') {
2628
+ matchFunction--;
2629
+ }
2630
+ else if (token == ']') {
2631
+ inAttr--;
2632
+ }
2633
+ match.at(-1).push(token);
2634
+ }
2635
+ }
2636
+ // invalid function
2637
+ if (matchFunction != 0 || inAttr != 0) {
2638
+ return null;
2639
+ }
2640
+ if (parentType != 'Rule') {
2641
+ for (const part of match) {
2642
+ if (part.length > 0 && combinators.includes(part[0].charAt(0))) {
2643
+ return null;
2644
+ }
2645
+ }
2646
+ }
2647
+ if (match.length > 1) {
2648
+ console.error(`unsupported multilevel matching`);
2649
+ console.error({ match, selector1, selector2 });
2650
+ return null;
2651
+ }
2652
+ for (const part of match) {
2653
+ while (part.length > 0) {
2654
+ const token = part.at(-1);
2655
+ if (token == ' ' || combinators.includes(token) || notEndingWith.includes(token.at(-1))) {
2656
+ part.pop();
2657
+ continue;
2658
+ }
2659
+ break;
2660
+ }
2661
+ }
2662
+ if (match.every(t => t.length == 0)) {
2663
+ return null;
2664
+ }
2665
+ if (eq([['&']], match)) {
2666
+ return null;
2667
+ }
2668
+ function reduce(acc, curr) {
2669
+ if (acc === null) {
2670
+ return null;
2671
+ }
2672
+ let hasCompoundSelector = true;
2673
+ curr = curr.slice(match[0].length);
2674
+ while (curr.length > 0) {
2675
+ if (curr[0] == ' ') {
2676
+ hasCompoundSelector = false;
2677
+ curr.unshift('&');
2678
+ continue;
2679
+ }
2680
+ break;
2681
+ }
2682
+ // invalid function match
2683
+ if (curr.length > 0 && curr[0].endsWith('(') && curr.at(-1) != ')') {
2684
+ return null;
2685
+ }
2686
+ if (curr.length == 1 && combinators.includes(curr[0].charAt(0))) {
2687
+ return null;
2688
+ }
2689
+ if (hasCompoundSelector && curr.length > 0) {
2690
+ hasCompoundSelector = !['&'].concat(combinators).includes(curr[0].charAt(0));
2691
+ }
2692
+ if (curr[0] == ':is(') {
2693
+ let inFunction = 0;
2694
+ let canReduce = true;
2695
+ const isCompound = curr.reduce((acc, token, index) => {
2696
+ if (index == 0) {
2697
+ inFunction++;
2698
+ canReduce = curr[1] == '&';
2699
+ }
2700
+ else if (token.endsWith('(')) {
2701
+ if (inFunction == 0) {
2702
+ canReduce = false;
2703
+ }
2704
+ inFunction++;
2705
+ }
2706
+ else if (token == ')') {
2707
+ inFunction--;
2708
+ }
2709
+ else if (token == ',') {
2710
+ if (!canReduce) {
2711
+ canReduce = curr[index + 1] == '&';
2712
+ }
2713
+ acc.push([]);
2714
+ }
2715
+ else
2716
+ acc.at(-1)?.push(token);
2717
+ return acc;
2718
+ }, [[]]);
2719
+ if (inFunction > 0) {
2720
+ canReduce = false;
2721
+ }
2722
+ if (canReduce) {
2723
+ curr = isCompound.reduce((acc, curr) => {
2724
+ if (acc.length > 0) {
2725
+ acc.push(',');
2726
+ }
2727
+ acc.push(...curr);
2728
+ return acc;
2729
+ }, []);
2730
+ }
2731
+ }
2732
+ // @todo: check hasCompoundSelector && curr[0] == '&' && curr[1] == ' '
2733
+ acc.push(match.length == 0 ? ['&'] : (hasCompoundSelector && curr[0] != '&' && (curr.length == 0 || !combinators.includes(curr[0].charAt(0))) ? ['&'].concat(curr) : curr));
2734
+ return acc;
2735
+ }
2736
+ // @ts-ignore
2737
+ selector1 = selector1.reduce(reduce, []);
2738
+ // @ts-ignore
2739
+ selector2 = selector2.reduce(reduce, []);
2740
+ return selector1 == null || selector2 == null ? null : {
2741
+ eq: eq(selector1, selector2),
2742
+ match,
2743
+ selector1,
2744
+ selector2
2745
+ };
2275
2746
  }
2276
- // @ts-ignore
2277
- ast.chi.splice(i, 1, wrapper);
2278
- // @ts-ignore
2279
- ast.chi.splice(nodeIndex, 1);
2280
- // @ts-ignore
2281
- previous.sel = pSel;
2282
- // @ts-ignore
2283
- previous.raw = match.selector1;
2284
- // @ts-ignore
2285
- node.sel = nSel;
2286
- // @ts-ignore
2287
- node.raw = match.selector2;
2288
- reduceRuleSelector(wrapper);
2289
- return wrapper;
2290
- }
2291
- function deduplicate(ast, options = {}, recursive = false) {
2292
2747
  // @ts-ignore
2293
2748
  if (('chi' in ast) && ast.chi?.length > 0) {
2294
2749
  let i = 0;
@@ -2328,7 +2783,8 @@
2328
2783
  // @ts-ignore
2329
2784
  if (options.nestingRules) {
2330
2785
  // @ts-ignore
2331
- if (previous != null && previous.typ == 'Rule') {
2786
+ if (previous?.typ == 'Rule') {
2787
+ // @ts-ignore
2332
2788
  reduceRuleSelector(previous);
2333
2789
  // @ts-ignore
2334
2790
  match = matchSelectors(previous.raw, node.raw, ast.typ);
@@ -2367,7 +2823,7 @@
2367
2823
  nodeIndex = --i;
2368
2824
  // @ts-ignore
2369
2825
  previous = ast.chi[nodeIndex];
2370
- deduplicate(wrapper, options, recursive);
2826
+ minify(wrapper, options, recursive);
2371
2827
  continue;
2372
2828
  }
2373
2829
  // @ts-ignore
@@ -2416,13 +2872,24 @@
2416
2872
  }
2417
2873
  else if (combinators.includes(curr[0])) {
2418
2874
  curr.unshift('&');
2875
+ wrap = false;
2419
2876
  }
2420
2877
  // @ts-ignore
2421
- acc.push(curr.map(t => t.replaceAll('&', node.optimized.optimized[0])).join(''));
2878
+ acc.push(curr);
2422
2879
  return acc;
2423
2880
  }, []);
2881
+ if (!wrap) {
2882
+ wrap = selector.some(s => s[0] != '&');
2883
+ }
2884
+ const rule = selector.map(s => {
2885
+ if (s[0] == '&') {
2886
+ // @ts-ignore
2887
+ s[0] = node.optimized.optimized[0];
2888
+ }
2889
+ return s.join('');
2890
+ }).join(',');
2424
2891
  // @ts-ignore
2425
- node.sel = (wrap ? node.optimized.optimized[0] : '') + `:is(${selector.join(',')})`;
2892
+ node.sel = wrap ? node.optimized.optimized[0] + `:is(${rule})` : rule;
2426
2893
  }
2427
2894
  }
2428
2895
  // @ts-ignore
@@ -2453,10 +2920,10 @@
2453
2920
  // @ts-ignore
2454
2921
  if (hasDeclaration(node)) {
2455
2922
  // @ts-ignore
2456
- deduplicateRule(node);
2923
+ minifyRule(node);
2457
2924
  }
2458
2925
  else {
2459
- deduplicate(node, options, recursive);
2926
+ minify(node, options, recursive);
2460
2927
  }
2461
2928
  i--;
2462
2929
  previous = node;
@@ -2498,10 +2965,10 @@
2498
2965
  // @ts-ignore
2499
2966
  if (hasDeclaration(previous)) {
2500
2967
  // @ts-ignore
2501
- deduplicateRule(previous);
2968
+ minifyRule(previous);
2502
2969
  }
2503
2970
  else {
2504
- deduplicate(previous, options, recursive);
2971
+ minify(previous, options, recursive);
2505
2972
  }
2506
2973
  }
2507
2974
  }
@@ -2512,18 +2979,97 @@
2512
2979
  if (recursive && node != null && ('chi' in node)) {
2513
2980
  // @ts-ignore
2514
2981
  if (node.chi.some(n => n.typ == 'Declaration')) {
2515
- deduplicateRule(node);
2982
+ minifyRule(node);
2516
2983
  }
2517
2984
  else {
2518
2985
  // @ts-ignore
2519
2986
  if (!(node.typ == 'AtRule' && node.nam != 'font-face')) {
2520
- deduplicate(node, options, recursive);
2987
+ minify(node, options, recursive);
2521
2988
  }
2522
2989
  }
2523
2990
  }
2524
2991
  }
2525
2992
  return ast;
2526
2993
  }
2994
+ function reduceSelector(selector) {
2995
+ if (selector.length == 0) {
2996
+ return null;
2997
+ }
2998
+ const optimized = [];
2999
+ const k = selector.reduce((acc, curr) => acc == 0 ? curr.length : (curr.length == 0 ? acc : Math.min(acc, curr.length)), 0);
3000
+ let i = 0;
3001
+ let j;
3002
+ let match;
3003
+ for (; i < k; i++) {
3004
+ const item = selector[0][i];
3005
+ match = true;
3006
+ for (j = 1; j < selector.length; j++) {
3007
+ if (item != selector[j][i]) {
3008
+ match = false;
3009
+ break;
3010
+ }
3011
+ }
3012
+ if (!match) {
3013
+ break;
3014
+ }
3015
+ optimized.push(item);
3016
+ }
3017
+ while (optimized.length > 0) {
3018
+ const last = optimized.at(-1);
3019
+ if ((last == ' ' || combinators.includes(last))) {
3020
+ optimized.pop();
3021
+ continue;
3022
+ }
3023
+ break;
3024
+ }
3025
+ selector.forEach((selector) => selector.splice(0, optimized.length));
3026
+ // combinator
3027
+ if (combinators.includes(optimized.at(-1))) {
3028
+ const combinator = optimized.pop();
3029
+ selector.forEach(selector => selector.unshift(combinator));
3030
+ }
3031
+ let reducible = optimized.length == 1;
3032
+ if (optimized[0] == '&' && optimized[1] == ' ') {
3033
+ optimized.splice(0, 2);
3034
+ }
3035
+ if (optimized.length == 0 ||
3036
+ (optimized[0].charAt(0) == '&' ||
3037
+ selector.length == 1)) {
3038
+ return {
3039
+ match: false,
3040
+ optimized,
3041
+ selector: selector.map(selector => selector[0] == '&' && selector[1] == ' ' ? selector.slice(2) : selector),
3042
+ reducible: selector.length > 1 && selector.every((selector) => !combinators.includes(selector[0]))
3043
+ };
3044
+ }
3045
+ return {
3046
+ match: true,
3047
+ optimized,
3048
+ selector: selector.reduce((acc, curr) => {
3049
+ let hasCompound = true;
3050
+ if (hasCompound && curr.length > 0) {
3051
+ hasCompound = !['&'].concat(combinators).includes(curr[0].charAt(0));
3052
+ }
3053
+ // @ts-ignore
3054
+ if (hasCompound && curr[0] == ' ') {
3055
+ hasCompound = false;
3056
+ curr.unshift('&');
3057
+ }
3058
+ if (curr.length == 0) {
3059
+ curr.push('&');
3060
+ hasCompound = false;
3061
+ }
3062
+ if (reducible) {
3063
+ const chr = curr[0].charAt(0);
3064
+ // @ts-ignore
3065
+ reducible = chr == '.' || chr == ':' || isIdentStart(chr.codePointAt(0));
3066
+ }
3067
+ acc.push(hasCompound ? ['&'].concat(curr) : curr);
3068
+ return acc;
3069
+ }, []),
3070
+ reducible: selector.every((selector) => !['>', '+', '~', '&'].includes(selector[0]))
3071
+ };
3072
+ }
2527
3073
  function hasOnlyDeclarations(node) {
2528
3074
  let k = node.chi.length;
2529
3075
  while (k--) {
@@ -2546,7 +3092,7 @@
2546
3092
  }
2547
3093
  return true;
2548
3094
  }
2549
- function deduplicateRule(ast) {
3095
+ function minifyRule(ast) {
2550
3096
  // @ts-ignore
2551
3097
  if (!('chi' in ast) || ast.chi?.length <= 1) {
2552
3098
  return ast;
@@ -2554,45 +3100,19 @@
2554
3100
  // @ts-ignore
2555
3101
  const j = ast.chi.length;
2556
3102
  let k = 0;
2557
- let map = new Map;
3103
+ let properties = new PropertyList();
2558
3104
  // @ts-ignore
2559
3105
  for (; k < j; k++) {
2560
3106
  // @ts-ignore
2561
3107
  const node = ast.chi[k];
2562
- if (node.typ == 'Comment') {
2563
- // @ts-ignore
2564
- map.set(node, node);
3108
+ if (node.typ == 'Comment' || node.typ == 'Declaration') {
3109
+ properties.add(node);
2565
3110
  continue;
2566
3111
  }
2567
- else if (node.typ != 'Declaration') {
2568
- break;
2569
- }
2570
- if (node.nam in configuration.map ||
2571
- node.nam in configuration.properties) {
2572
- // @ts-ignore
2573
- const shorthand = node.nam in configuration.map ? configuration.map[node.nam].shorthand : configuration.properties[node.nam].shorthand;
2574
- if (!map.has(shorthand)) {
2575
- map.set(shorthand, new PropertyList());
2576
- }
2577
- map.get(shorthand).add(node);
2578
- }
2579
- else {
2580
- map.set(node.nam, node);
2581
- }
2582
- }
2583
- const children = [];
2584
- for (let child of map.values()) {
2585
- if (child instanceof PropertyList) {
2586
- // @ts-ignore
2587
- children.push(...child);
2588
- }
2589
- else {
2590
- // @ts-ignore
2591
- children.push(child);
2592
- }
3112
+ break;
2593
3113
  }
2594
3114
  // @ts-ignore
2595
- ast.chi = children.concat(ast.chi?.slice(k));
3115
+ ast.chi = [...properties].concat(ast.chi.slice(k));
2596
3116
  return ast;
2597
3117
  }
2598
3118
  function splitRule(buffer) {
@@ -2718,345 +3238,482 @@
2718
3238
  }
2719
3239
  // }
2720
3240
  }
2721
- function diff(n1, n2, options = {}) {
2722
- let node1 = n1;
2723
- let node2 = n2;
2724
- let exchanged = false;
2725
- if (node1.chi.length > node2.chi.length) {
2726
- const t = node1;
2727
- node1 = node2;
2728
- node2 = t;
2729
- exchanged = true;
2730
- }
2731
- let i = node1.chi.length;
2732
- let j = node2.chi.length;
2733
- if (i == 0 || j == 0) {
2734
- // @ts-ignore
2735
- return null;
2736
- }
2737
- // @ts-ignore
2738
- const raw1 = node1.raw;
2739
- // @ts-ignore
2740
- // const optimized1 = node1.optimized;
2741
- // @ts-ignore
2742
- const raw2 = node2.raw;
3241
+
3242
+ function* walk(node) {
2743
3243
  // @ts-ignore
2744
- // const optimized2 = node2.optimized;
2745
- node1 = { ...node1, chi: node1.chi.slice() };
2746
- node2 = { ...node2, chi: node2.chi.slice() };
2747
- if (raw1 != null) {
2748
- Object.defineProperty(node1, 'raw', { enumerable: false, writable: true, value: raw1 });
2749
- }
2750
- // if (optimized1 != null) {
2751
- // Object.defineProperty(node1, 'optimized', {enumerable: false, writable: true, value: optimized1});
2752
- // }
2753
- if (raw2 != null) {
2754
- Object.defineProperty(node2, 'raw', { enumerable: false, writable: true, value: raw2 });
2755
- }
2756
- // if (optimized2 != null) {
2757
- // Object.defineProperty(node2, 'optimized', {enumerable: false, writable: true, value: optimized2});
2758
- // }
2759
- const intersect = [];
2760
- while (i--) {
2761
- if (node1.chi[i].typ == 'Comment') {
2762
- continue;
2763
- }
2764
- j = node2.chi.length;
2765
- if (j == 0) {
2766
- break;
3244
+ yield* doWalk(node, null, null);
3245
+ }
3246
+ function* doWalk(node, parent, root) {
3247
+ yield { node, parent, root };
3248
+ if ('chi' in node) {
3249
+ for (const child of node.chi) {
3250
+ yield* doWalk(child, node, (root ?? node));
2767
3251
  }
2768
- while (j--) {
2769
- if (node2.chi[j].typ == 'Comment') {
2770
- continue;
2771
- }
2772
- if (node1.chi[i].nam == node2.chi[j].nam) {
2773
- if (eq(node1.chi[i], node2.chi[j])) {
2774
- intersect.push(node1.chi[i]);
2775
- node1.chi.splice(i, 1);
2776
- node2.chi.splice(j, 1);
2777
- break;
2778
- }
2779
- }
3252
+ }
3253
+ }
3254
+
3255
+ function* tokenize(iterator) {
3256
+ let ind = -1;
3257
+ let lin = 1;
3258
+ let col = 0;
3259
+ const position = {
3260
+ ind: Math.max(ind, 0),
3261
+ lin: lin,
3262
+ col: Math.max(col, 1)
3263
+ };
3264
+ let value;
3265
+ let buffer = '';
3266
+ function consumeWhiteSpace() {
3267
+ let count = 0;
3268
+ while (isWhiteSpace(iterator.charAt(count + ind + 1).charCodeAt(0))) {
3269
+ count++;
2780
3270
  }
3271
+ next(count);
3272
+ return count;
2781
3273
  }
2782
- // @ts-ignore
2783
- const result = (intersect.length == 0 ? null : {
2784
- ...node1,
2785
- // @ts-ignore
2786
- sel: [...new Set([...(n1?.raw?.reduce(reducer, []) || splitRule(n1.sel)).concat(n2?.raw?.reduce(reducer, []) || splitRule(n2.sel))])].join(','),
2787
- chi: intersect.reverse()
2788
- });
2789
- if (result == null || [n1, n2].reduce((acc, curr) => curr.chi.length == 0 ? acc : acc + render(curr, options).code.length, 0) <= [node1, node2, result].reduce((acc, curr) => curr.chi.length == 0 ? acc : acc + render(curr, options).code.length, 0)) {
2790
- // @ts-ignore
2791
- return null;
3274
+ function pushToken(token, hint) {
3275
+ const result = { token, hint, position: { ...position }, bytesIn: ind };
3276
+ position.ind = ind;
3277
+ position.lin = lin;
3278
+ position.col = col == 0 ? 1 : col;
3279
+ return result;
2792
3280
  }
2793
- return { result, node1: exchanged ? node2 : node1, node2: exchanged ? node2 : node2 };
2794
- }
2795
- function matchSelectors(selector1, selector2, parentType) {
2796
- let match = [[]];
2797
- const j = Math.min(selector1.reduce((acc, curr) => Math.min(acc, curr.length), selector1.length > 0 ? selector1[0].length : 0), selector2.reduce((acc, curr) => Math.min(acc, curr.length), selector2.length > 0 ? selector2[0].length : 0));
2798
- let i = 0;
2799
- let k;
2800
- let l;
2801
- let token;
2802
- let matching = true;
2803
- let matchFunction = 0;
2804
- let inAttr = 0;
2805
- for (; i < j; i++) {
2806
- k = 0;
2807
- token = selector1[0][i];
2808
- for (; k < selector1.length; k++) {
2809
- if (selector1[k][i] != token) {
2810
- matching = false;
3281
+ function* consumeString(quoteStr) {
3282
+ const quote = quoteStr;
3283
+ let value;
3284
+ let hasNewLine = false;
3285
+ if (buffer.length > 0) {
3286
+ yield pushToken(buffer);
3287
+ buffer = '';
3288
+ }
3289
+ buffer += quoteStr;
3290
+ while (value = peek()) {
3291
+ if (ind >= iterator.length) {
3292
+ yield pushToken(buffer, hasNewLine ? 'Bad-string' : 'Unclosed-string');
2811
3293
  break;
2812
3294
  }
2813
- }
2814
- if (matching) {
2815
- l = 0;
2816
- for (; l < selector2.length; l++) {
2817
- if (selector2[l][i] != token) {
2818
- matching = false;
3295
+ if (value == '\\') {
3296
+ const sequence = peek(6);
3297
+ let escapeSequence = '';
3298
+ let codepoint;
3299
+ let i;
3300
+ for (i = 1; i < sequence.length; i++) {
3301
+ codepoint = sequence.charCodeAt(i);
3302
+ if (codepoint == 0x20 ||
3303
+ (codepoint >= 0x61 && codepoint <= 0x66) ||
3304
+ (codepoint >= 0x41 && codepoint <= 0x46) ||
3305
+ (codepoint >= 0x30 && codepoint <= 0x39)) {
3306
+ escapeSequence += sequence[i];
3307
+ if (codepoint == 0x20) {
3308
+ break;
3309
+ }
3310
+ continue;
3311
+ }
2819
3312
  break;
2820
3313
  }
3314
+ // not hex or new line
3315
+ // @ts-ignore
3316
+ if (i == 1 && !isNewLine(codepoint)) {
3317
+ buffer += sequence[i];
3318
+ next(2);
3319
+ continue;
3320
+ }
3321
+ if (escapeSequence.trimEnd().length > 0) {
3322
+ const codepoint = Number(`0x${escapeSequence.trimEnd()}`);
3323
+ if (codepoint == 0 ||
3324
+ // leading surrogate
3325
+ (0xD800 <= codepoint && codepoint <= 0xDBFF) ||
3326
+ // trailing surrogate
3327
+ (0xDC00 <= codepoint && codepoint <= 0xDFFF)) {
3328
+ buffer += String.fromCodePoint(0xFFFD);
3329
+ }
3330
+ else {
3331
+ buffer += String.fromCodePoint(codepoint);
3332
+ }
3333
+ next(escapeSequence.length + 1);
3334
+ continue;
3335
+ }
3336
+ // buffer += value;
3337
+ if (ind >= iterator.length) {
3338
+ // drop '\\' at the end
3339
+ yield pushToken(buffer);
3340
+ break;
3341
+ }
3342
+ buffer += next(2);
3343
+ continue;
2821
3344
  }
2822
- }
2823
- if (!matching) {
2824
- break;
2825
- }
2826
- if (token == ',') {
2827
- match.push([]);
2828
- }
2829
- else {
2830
- if (token.endsWith('(')) {
2831
- matchFunction++;
2832
- }
2833
- if (token.endsWith('[')) {
2834
- inAttr++;
3345
+ if (value == quote) {
3346
+ buffer += value;
3347
+ yield pushToken(buffer, hasNewLine ? 'Bad-string' : 'String');
3348
+ next();
3349
+ // i += value.length;
3350
+ buffer = '';
3351
+ break;
2835
3352
  }
2836
- else if (token == ')') {
2837
- matchFunction--;
3353
+ if (isNewLine(value.charCodeAt(0))) {
3354
+ hasNewLine = true;
2838
3355
  }
2839
- else if (token == ']') {
2840
- inAttr--;
3356
+ if (hasNewLine && value == ';') {
3357
+ yield pushToken(buffer, 'Bad-string');
3358
+ buffer = '';
3359
+ break;
2841
3360
  }
2842
- match.at(-1).push(token);
3361
+ buffer += value;
3362
+ // i += value.length;
3363
+ next();
2843
3364
  }
2844
3365
  }
2845
- // invalid function
2846
- if (matchFunction != 0 || inAttr != 0) {
2847
- return null;
2848
- }
2849
- if (parentType != 'Rule') {
2850
- for (const part of match) {
2851
- if (part.length > 0 && combinators.includes(part[0].charAt(0))) {
2852
- return null;
2853
- }
3366
+ function peek(count = 1) {
3367
+ if (count == 1) {
3368
+ return iterator.charAt(ind + 1);
2854
3369
  }
3370
+ return iterator.slice(ind + 1, ind + count + 1);
2855
3371
  }
2856
- if (match.length > 1) {
2857
- console.error(`unsupported multilevel matching`);
2858
- console.error({ match, selector1, selector2 });
2859
- return null;
3372
+ function prev(count = 1) {
3373
+ if (count == 1) {
3374
+ return ind == 0 ? '' : iterator.charAt(ind - 1);
3375
+ }
3376
+ return iterator.slice(ind - 1 - count, ind - 1);
2860
3377
  }
2861
- for (const part of match) {
2862
- while (part.length > 0) {
2863
- const token = part.at(-1);
2864
- if (token == ' ' || combinators.includes(token) || notEndingWith.includes(token.at(-1))) {
2865
- part.pop();
2866
- continue;
3378
+ function next(count = 1) {
3379
+ let char = '';
3380
+ while (count-- > 0 && ind < iterator.length) {
3381
+ const codepoint = iterator.charCodeAt(++ind);
3382
+ if (isNaN(codepoint)) {
3383
+ return char;
3384
+ }
3385
+ char += iterator.charAt(ind);
3386
+ if (isNewLine(codepoint)) {
3387
+ lin++;
3388
+ col = 0;
3389
+ }
3390
+ else {
3391
+ col++;
2867
3392
  }
2868
- break;
2869
3393
  }
3394
+ return char;
2870
3395
  }
2871
- if (match.every(t => t.length == 0)) {
2872
- return null;
2873
- }
2874
- if (eq([['&']], match)) {
2875
- return null;
2876
- }
2877
- function reduce(acc, curr) {
2878
- if (acc === null) {
2879
- return null;
2880
- }
2881
- let hasCompoundSelector = true;
2882
- curr = curr.slice(match[0].length);
2883
- while (curr.length > 0) {
2884
- if (curr[0] == ' ') {
2885
- hasCompoundSelector = false;
2886
- curr.unshift('&');
2887
- continue;
3396
+ while (value = next()) {
3397
+ if (ind >= iterator.length) {
3398
+ if (buffer.length > 0) {
3399
+ yield pushToken(buffer);
3400
+ buffer = '';
2888
3401
  }
2889
3402
  break;
2890
3403
  }
2891
- // invalid function match
2892
- if (curr.length > 0 && curr[0].endsWith('(') && curr.at(-1) != ')') {
2893
- return null;
2894
- }
2895
- if (curr.length == 1 && combinators.includes(curr[0].charAt(0))) {
2896
- return null;
2897
- }
2898
- if (hasCompoundSelector && curr.length > 0) {
2899
- hasCompoundSelector = !['&'].concat(combinators).includes(curr[0].charAt(0));
3404
+ if (isWhiteSpace(value.charCodeAt(0))) {
3405
+ if (buffer.length > 0) {
3406
+ yield pushToken(buffer);
3407
+ buffer = '';
3408
+ }
3409
+ while (value = next()) {
3410
+ if (ind >= iterator.length) {
3411
+ break;
3412
+ }
3413
+ if (!isWhiteSpace(value.charCodeAt(0))) {
3414
+ break;
3415
+ }
3416
+ }
3417
+ yield pushToken('', 'Whitespace');
3418
+ buffer = '';
3419
+ if (ind >= iterator.length) {
3420
+ break;
3421
+ }
2900
3422
  }
2901
- if (curr[0] == ':is(') {
2902
- let inFunction = 0;
2903
- let canReduce = true;
2904
- const isCompound = curr.reduce((acc, token, index) => {
2905
- if (index == 0) {
2906
- inFunction++;
2907
- canReduce = curr[1] == '&';
3423
+ switch (value) {
3424
+ case '/':
3425
+ if (buffer.length > 0) {
3426
+ yield pushToken(buffer);
3427
+ buffer = '';
3428
+ if (peek() != '*') {
3429
+ yield pushToken(value);
3430
+ break;
3431
+ }
2908
3432
  }
2909
- else if (token.endsWith('(')) {
2910
- if (inFunction == 0) {
2911
- canReduce = false;
3433
+ buffer += value;
3434
+ if (peek() == '*') {
3435
+ buffer += '*';
3436
+ // i++;
3437
+ next();
3438
+ while (value = next()) {
3439
+ if (ind >= iterator.length) {
3440
+ yield pushToken(buffer, 'Bad-comment');
3441
+ break;
3442
+ }
3443
+ if (value == '\\') {
3444
+ buffer += value;
3445
+ value = next();
3446
+ if (ind >= iterator.length) {
3447
+ yield pushToken(buffer, 'Bad-comment');
3448
+ break;
3449
+ }
3450
+ buffer += value;
3451
+ continue;
3452
+ }
3453
+ if (value == '*') {
3454
+ buffer += value;
3455
+ value = next();
3456
+ if (ind >= iterator.length) {
3457
+ yield pushToken(buffer, 'Bad-comment');
3458
+ break;
3459
+ }
3460
+ buffer += value;
3461
+ if (value == '/') {
3462
+ yield pushToken(buffer, 'Comment');
3463
+ buffer = '';
3464
+ break;
3465
+ }
3466
+ }
3467
+ else {
3468
+ buffer += value;
3469
+ }
2912
3470
  }
2913
- inFunction++;
2914
3471
  }
2915
- else if (token == ')') {
2916
- inFunction--;
3472
+ break;
3473
+ case '<':
3474
+ if (buffer.length > 0) {
3475
+ yield pushToken(buffer);
3476
+ buffer = '';
2917
3477
  }
2918
- else if (token == ',') {
2919
- if (!canReduce) {
2920
- canReduce = curr[index + 1] == '&';
2921
- }
2922
- acc.push([]);
3478
+ buffer += value;
3479
+ value = next();
3480
+ if (ind >= iterator.length) {
3481
+ break;
2923
3482
  }
2924
- else
2925
- acc.at(-1)?.push(token);
2926
- return acc;
2927
- }, [[]]);
2928
- if (inFunction > 0) {
2929
- canReduce = false;
2930
- }
2931
- if (canReduce) {
2932
- curr = isCompound.reduce((acc, curr) => {
2933
- if (acc.length > 0) {
2934
- acc.push(',');
3483
+ if (peek(3) == '!--') {
3484
+ while (value = next()) {
3485
+ if (ind >= iterator.length) {
3486
+ break;
3487
+ }
3488
+ buffer += value;
3489
+ if (value == '>' && prev(2) == '--') {
3490
+ yield pushToken(buffer, 'CDOCOMM');
3491
+ buffer = '';
3492
+ break;
3493
+ }
2935
3494
  }
2936
- acc.push(...curr);
2937
- return acc;
2938
- }, []);
2939
- }
2940
- }
2941
- // @todo: check hasCompoundSelector && curr[0] == '&' && curr[1] == ' '
2942
- acc.push(match.length == 0 ? ['&'] : (hasCompoundSelector && curr[0] != '&' && (curr.length == 0 || !combinators.includes(curr[0].charAt(0))) ? ['&'].concat(curr) : curr));
2943
- return acc;
2944
- }
2945
- // @ts-ignore
2946
- selector1 = selector1.reduce(reduce, []);
2947
- // @ts-ignore
2948
- selector2 = selector2.reduce(reduce, []);
2949
- return selector1 == null || selector2 == null ? null : {
2950
- eq: eq(selector1, selector2),
2951
- match,
2952
- selector1,
2953
- selector2
2954
- };
2955
- }
2956
- function reduceSelector(selector) {
2957
- if (selector.length == 0) {
2958
- return null;
2959
- }
2960
- const optimized = [];
2961
- const k = selector.reduce((acc, curr) => acc == 0 ? curr.length : (curr.length == 0 ? acc : Math.min(acc, curr.length)), 0);
2962
- let i = 0;
2963
- let j;
2964
- let match;
2965
- for (; i < k; i++) {
2966
- const item = selector[0][i];
2967
- match = true;
2968
- for (j = 1; j < selector.length; j++) {
2969
- if (item != selector[j][i]) {
2970
- match = false;
3495
+ }
3496
+ if (ind >= iterator.length) {
3497
+ yield pushToken(buffer, 'BADCDO');
3498
+ buffer = '';
3499
+ }
2971
3500
  break;
2972
- }
2973
- }
2974
- if (!match) {
2975
- break;
2976
- }
2977
- optimized.push(item);
2978
- }
2979
- while (optimized.length > 0) {
2980
- const last = optimized.at(-1);
2981
- if ((last == ' ' || combinators.includes(last))) {
2982
- optimized.pop();
2983
- continue;
2984
- }
2985
- break;
2986
- }
2987
- selector.forEach((selector) => selector.splice(0, optimized.length));
2988
- // combinator
2989
- if (combinators.includes(optimized.at(-1))) {
2990
- const combinator = optimized.pop();
2991
- selector.forEach(selector => selector.unshift(combinator));
2992
- }
2993
- let reducible = optimized.length == 1;
2994
- if (optimized[0] == '&' && optimized[1] == ' ') {
2995
- optimized.splice(0, 2);
2996
- }
2997
- if (optimized.length == 0 ||
2998
- (optimized[0].charAt(0) == '&' ||
2999
- selector.length == 1)) {
3000
- return {
3001
- match: false,
3002
- optimized,
3003
- selector: selector.map(selector => selector[0] == '&' && selector[1] == ' ' ? selector.slice(2) : selector),
3004
- reducible: selector.length > 1 && selector.every((selector) => !combinators.includes(selector[0]))
3005
- };
3006
- }
3007
- return {
3008
- match: true,
3009
- optimized,
3010
- selector: selector.reduce((acc, curr) => {
3011
- let hasCompound = true;
3012
- if (hasCompound && curr.length > 0) {
3013
- hasCompound = !['&'].concat(combinators).includes(curr[0].charAt(0));
3014
- }
3015
- // @ts-ignore
3016
- if (hasCompound && curr[0] == ' ') {
3017
- hasCompound = false;
3018
- curr.unshift('&');
3019
- }
3020
- if (curr.length == 0) {
3021
- curr.push('&');
3022
- hasCompound = false;
3023
- }
3024
- if (reducible) {
3025
- const chr = curr[0].charAt(0);
3501
+ case '\\':
3502
+ value = next();
3503
+ // EOF
3504
+ if (ind + 1 >= iterator.length) {
3505
+ // end of stream ignore \\
3506
+ yield pushToken(buffer);
3507
+ buffer = '';
3508
+ break;
3509
+ }
3510
+ buffer += value;
3511
+ break;
3512
+ case '"':
3513
+ case "'":
3514
+ yield* consumeString(value);
3515
+ break;
3516
+ case '~':
3517
+ case '|':
3518
+ if (buffer.length > 0) {
3519
+ yield pushToken(buffer);
3520
+ buffer = '';
3521
+ }
3522
+ buffer += value;
3523
+ value = next();
3524
+ if (ind >= iterator.length) {
3525
+ yield pushToken(buffer);
3526
+ buffer = '';
3527
+ break;
3528
+ }
3529
+ if (value == '=') {
3530
+ buffer += value;
3531
+ yield pushToken(buffer, buffer[0] == '~' ? 'Includes' : 'Dash-matches');
3532
+ buffer = '';
3533
+ break;
3534
+ }
3535
+ yield pushToken(buffer);
3536
+ while (isWhiteSpace(value.charCodeAt(0))) {
3537
+ value = next();
3538
+ }
3539
+ buffer = value;
3540
+ break;
3541
+ case '>':
3542
+ if (buffer !== '') {
3543
+ yield pushToken(buffer);
3544
+ buffer = '';
3545
+ }
3546
+ yield pushToken('', 'Gt');
3547
+ consumeWhiteSpace();
3548
+ break;
3549
+ case '.':
3550
+ const codepoint = peek().charCodeAt(0);
3551
+ if (!isDigit(codepoint) && buffer !== '') {
3552
+ yield pushToken(buffer);
3553
+ buffer = value;
3554
+ break;
3555
+ }
3556
+ buffer += value;
3557
+ break;
3558
+ case '+':
3559
+ case ':':
3560
+ case ',':
3561
+ case '=':
3562
+ if (buffer.length > 0) {
3563
+ yield pushToken(buffer);
3564
+ buffer = '';
3565
+ }
3566
+ if (value == ':' && ':' == peek()) {
3567
+ buffer += value + next();
3568
+ break;
3569
+ }
3570
+ yield pushToken(value);
3571
+ buffer = '';
3572
+ if (value == '+' && isWhiteSpace(peek().charCodeAt(0))) {
3573
+ yield pushToken(next());
3574
+ }
3575
+ while (isWhiteSpace(peek().charCodeAt(0))) {
3576
+ next();
3577
+ }
3578
+ break;
3579
+ case ')':
3580
+ if (buffer.length > 0) {
3581
+ yield pushToken(buffer);
3582
+ buffer = '';
3583
+ }
3584
+ yield pushToken('', 'End-parens');
3585
+ break;
3586
+ case '(':
3587
+ if (buffer.length == 0) {
3588
+ yield pushToken('', 'Start-parens');
3589
+ break;
3590
+ }
3591
+ buffer += value;
3026
3592
  // @ts-ignore
3027
- reducible = chr == '.' || chr == ':' || isIdentStart(chr.codePointAt(0));
3028
- }
3029
- acc.push(hasCompound ? ['&'].concat(curr) : curr);
3030
- return acc;
3031
- }, []),
3032
- reducible: selector.every((selector) => !['>', '+', '~', '&'].includes(selector[0]))
3033
- };
3034
- }
3035
- function reducer(acc, curr, index, array) {
3036
- // trim :is()
3037
- if (array.length == 1 && array[0][0] == ':is(' && array[0].at(-1) == ')') {
3038
- curr = curr.slice(1, -1);
3039
- }
3040
- if (curr[0] == '&') {
3041
- if (curr[1] == ' ') {
3042
- curr.splice(0, 2);
3043
- }
3044
- else if (combinators.includes(curr[1])) {
3045
- curr.splice(0, 1);
3593
+ if (buffer == 'url(') {
3594
+ yield pushToken(buffer);
3595
+ buffer = '';
3596
+ // consume either string or url token
3597
+ let whitespace = '';
3598
+ value = peek();
3599
+ while (isWhiteSpace(value.charCodeAt(0))) {
3600
+ whitespace += value;
3601
+ }
3602
+ if (whitespace.length > 0) {
3603
+ next(whitespace.length);
3604
+ }
3605
+ value = peek();
3606
+ if (value == '"' || value == "'") {
3607
+ yield* consumeString(next());
3608
+ break;
3609
+ }
3610
+ else {
3611
+ buffer = '';
3612
+ do {
3613
+ let cp = value.charCodeAt(0);
3614
+ // EOF -
3615
+ if (cp == null) {
3616
+ yield pushToken('', 'Bad-url-token');
3617
+ break;
3618
+ }
3619
+ // ')'
3620
+ if (cp == 0x29 || cp == null) {
3621
+ if (buffer.length == 0) {
3622
+ yield pushToken(buffer, 'Bad-url-token');
3623
+ }
3624
+ else {
3625
+ yield pushToken(buffer, 'Url-token');
3626
+ }
3627
+ if (cp != null) {
3628
+ yield pushToken(next());
3629
+ }
3630
+ break;
3631
+ }
3632
+ if (isWhiteSpace(cp)) {
3633
+ whitespace = next();
3634
+ while (true) {
3635
+ value = peek();
3636
+ cp = value.charCodeAt(0);
3637
+ if (isWhiteSpace(cp)) {
3638
+ whitespace += value;
3639
+ continue;
3640
+ }
3641
+ break;
3642
+ }
3643
+ if (cp == null || cp == 0x29) {
3644
+ continue;
3645
+ }
3646
+ // bad url token
3647
+ buffer += next(whitespace.length);
3648
+ do {
3649
+ value = peek();
3650
+ cp = value.charCodeAt(0);
3651
+ if (cp == null || cp == 0x29) {
3652
+ break;
3653
+ }
3654
+ buffer += next();
3655
+ } while (true);
3656
+ yield pushToken(buffer, 'Bad-url-token');
3657
+ continue;
3658
+ }
3659
+ buffer += next();
3660
+ value = peek();
3661
+ } while (true);
3662
+ buffer = '';
3663
+ }
3664
+ break;
3665
+ }
3666
+ yield pushToken(buffer);
3667
+ buffer = '';
3668
+ break;
3669
+ case '[':
3670
+ case ']':
3671
+ case '{':
3672
+ case '}':
3673
+ case ';':
3674
+ if (buffer.length > 0) {
3675
+ yield pushToken(buffer);
3676
+ buffer = '';
3677
+ }
3678
+ yield pushToken(value);
3679
+ break;
3680
+ case '!':
3681
+ if (buffer.length > 0) {
3682
+ yield pushToken(buffer);
3683
+ buffer = '';
3684
+ }
3685
+ const important = peek(9);
3686
+ if (important == 'important') {
3687
+ yield pushToken('', 'Important');
3688
+ next(9);
3689
+ buffer = '';
3690
+ break;
3691
+ }
3692
+ buffer = '!';
3693
+ break;
3694
+ default:
3695
+ buffer += value;
3696
+ break;
3046
3697
  }
3047
3698
  }
3048
- acc.push(curr.join(''));
3049
- return acc;
3699
+ if (buffer.length > 0) {
3700
+ yield pushToken(buffer);
3701
+ }
3050
3702
  }
3051
3703
 
3052
3704
  const urlTokenMatcher = /^(["']?)[a-zA-Z0-9_/.-][a-zA-Z0-9_/:.#?-]+(\1)$/;
3053
3705
  const funcLike = ['Start-parens', 'Func', 'UrlFunc', 'Pseudo-class-func'];
3706
+ /**
3707
+ *
3708
+ * @param iterator
3709
+ * @param opt
3710
+ */
3054
3711
  async function parse$1(iterator, opt = {}) {
3055
3712
  const errors = [];
3056
3713
  const options = {
3057
3714
  src: '',
3058
3715
  sourcemap: false,
3059
- compress: false,
3716
+ minify: true,
3060
3717
  nestingRules: false,
3061
3718
  resolveImport: false,
3062
3719
  resolveUrls: false,
@@ -3066,208 +3723,64 @@
3066
3723
  if (options.resolveImport) {
3067
3724
  options.resolveUrls = true;
3068
3725
  }
3069
- let ind = -1;
3070
- let lin = 1;
3071
- let col = 0;
3072
- const tokens = [];
3073
3726
  const src = options.src;
3074
3727
  const stack = [];
3075
3728
  const ast = {
3076
3729
  typ: "StyleSheet",
3077
3730
  chi: []
3078
3731
  };
3079
- const position = {
3080
- ind: Math.max(ind, 0),
3081
- lin: lin,
3082
- col: Math.max(col, 1)
3083
- };
3084
- let value;
3085
- let buffer = '';
3086
- let total = iterator.length;
3087
- let bytesIn = total;
3732
+ let tokens = [];
3088
3733
  let map = new Map;
3734
+ let bytesIn = 0;
3089
3735
  let context = ast;
3090
3736
  if (options.sourcemap) {
3091
3737
  ast.loc = {
3092
3738
  sta: {
3093
- ind: ind,
3094
- lin: lin,
3095
- col: col
3739
+ ind: 0,
3740
+ lin: 1,
3741
+ col: 1
3096
3742
  },
3097
3743
  src: ''
3098
3744
  };
3099
3745
  }
3100
- function getType(val) {
3101
- if (val === '') {
3102
- throw new Error('empty string?');
3103
- }
3104
- if (val == ':') {
3105
- return { typ: 'Colon' };
3106
- }
3107
- if (val == ')') {
3108
- return { typ: 'End-parens' };
3109
- }
3110
- if (val == '(') {
3111
- return { typ: 'Start-parens' };
3112
- }
3113
- if (val == '=') {
3114
- return { typ: 'Delim', val };
3115
- }
3116
- if (val == ';') {
3117
- return { typ: 'Semi-colon' };
3746
+ async function parseNode(results) {
3747
+ let tokens = results.map(mapToken);
3748
+ let i;
3749
+ let loc;
3750
+ for (i = 0; i < tokens.length; i++) {
3751
+ if (tokens[i].typ == 'Comment') {
3752
+ // @ts-ignore
3753
+ context.chi.push(tokens[i]);
3754
+ const position = map.get(tokens[i]);
3755
+ loc = {
3756
+ sta: position,
3757
+ src
3758
+ };
3759
+ if (options.sourcemap) {
3760
+ tokens[i].loc = loc;
3761
+ }
3762
+ }
3763
+ else if (tokens[i].typ != 'Whitespace') {
3764
+ break;
3765
+ }
3118
3766
  }
3119
- if (val == ',') {
3120
- return { typ: 'Comma' };
3767
+ tokens = tokens.slice(i);
3768
+ if (tokens.length == 0) {
3769
+ return null;
3121
3770
  }
3122
- if (val == '<') {
3123
- return { typ: 'Lt' };
3771
+ let delim = tokens.at(-1);
3772
+ if (delim.typ == 'Semi-colon' || delim.typ == 'Block-start' || delim.typ == 'Block-end') {
3773
+ tokens.pop();
3124
3774
  }
3125
- if (val == '>') {
3126
- return { typ: 'Gt' };
3775
+ else {
3776
+ delim = { typ: 'Semi-colon' };
3127
3777
  }
3128
- if (isPseudo(val)) {
3129
- return val.endsWith('(') ? {
3130
- typ: 'Pseudo-class-func',
3131
- val: val.slice(0, -1),
3132
- chi: []
3133
- }
3134
- : {
3135
- typ: 'Pseudo-class',
3136
- val
3137
- };
3778
+ // @ts-ignore
3779
+ while (['Whitespace', 'Bad-string', 'Bad-comment'].includes(tokens.at(-1)?.typ)) {
3780
+ tokens.pop();
3138
3781
  }
3139
- if (isAtKeyword(val)) {
3140
- return {
3141
- typ: 'At-rule',
3142
- val: val.slice(1)
3143
- };
3144
- }
3145
- if (isFunction(val)) {
3146
- val = val.slice(0, -1);
3147
- return {
3148
- typ: val == 'url' ? 'UrlFunc' : 'Func',
3149
- val,
3150
- chi: []
3151
- };
3152
- }
3153
- if (isNumber(val)) {
3154
- return {
3155
- typ: 'Number',
3156
- val
3157
- };
3158
- }
3159
- if (isDimension(val)) {
3160
- return parseDimension(val);
3161
- }
3162
- if (isPercentage(val)) {
3163
- return {
3164
- typ: 'Perc',
3165
- val: val.slice(0, -1)
3166
- };
3167
- }
3168
- if (val == 'currentColor') {
3169
- return {
3170
- typ: 'Color',
3171
- val,
3172
- kin: 'lit'
3173
- };
3174
- }
3175
- if (isIdent(val)) {
3176
- return {
3177
- typ: 'Iden',
3178
- val
3179
- };
3180
- }
3181
- if (val.charAt(0) == '#' && isHash(val)) {
3182
- return {
3183
- typ: 'Hash',
3184
- val
3185
- };
3186
- }
3187
- if ('"\''.includes(val.charAt(0))) {
3188
- return {
3189
- typ: 'Unclosed-string',
3190
- val
3191
- };
3192
- }
3193
- return {
3194
- typ: 'Literal',
3195
- val
3196
- };
3197
- }
3198
- // consume and throw away
3199
- function consume(open, close) {
3200
- let count = 1;
3201
- let chr;
3202
- while (true) {
3203
- chr = next();
3204
- if (chr == '\\') {
3205
- if (peek() === '') {
3206
- break;
3207
- }
3208
- continue;
3209
- }
3210
- else if (chr == '/' && peek() == '*') {
3211
- next();
3212
- while (true) {
3213
- chr = next();
3214
- if (chr === '') {
3215
- break;
3216
- }
3217
- if (chr == '*' && peek() == '/') {
3218
- next();
3219
- break;
3220
- }
3221
- }
3222
- }
3223
- else if (chr == close) {
3224
- count--;
3225
- }
3226
- else if (chr == open) {
3227
- count++;
3228
- }
3229
- if (chr === '' || count == 0) {
3230
- break;
3231
- }
3232
- }
3233
- }
3234
- async function parseNode(tokens) {
3235
- let i;
3236
- let loc;
3237
- for (i = 0; i < tokens.length; i++) {
3238
- if (tokens[i].typ == 'Comment') {
3239
- // @ts-ignore
3240
- context.chi.push(tokens[i]);
3241
- const position = map.get(tokens[i]);
3242
- loc = {
3243
- sta: position,
3244
- src
3245
- };
3246
- if (options.sourcemap) {
3247
- tokens[i].loc = loc;
3248
- }
3249
- }
3250
- else if (tokens[i].typ != 'Whitespace') {
3251
- break;
3252
- }
3253
- }
3254
- tokens = tokens.slice(i);
3255
- if (tokens.length == 0) {
3256
- return null;
3257
- }
3258
- let delim = tokens.at(-1);
3259
- if (delim.typ == 'Semi-colon' || delim.typ == 'Block-start' || delim.typ == 'Block-end') {
3260
- tokens.pop();
3261
- }
3262
- else {
3263
- delim = { typ: 'Semi-colon' };
3264
- }
3265
- // @ts-ignore
3266
- while (['Whitespace', 'Bad-string', 'Bad-comment'].includes(tokens.at(-1)?.typ)) {
3267
- tokens.pop();
3268
- }
3269
- if (tokens.length == 0) {
3270
- return null;
3782
+ if (tokens.length == 0) {
3783
+ return null;
3271
3784
  }
3272
3785
  if (tokens[0]?.typ == 'At-rule') {
3273
3786
  const atRule = tokens.shift();
@@ -3329,7 +3842,7 @@
3329
3842
  // @ts-ignore
3330
3843
  const root = await options.load(url, options.src).then((src) => {
3331
3844
  return parse$1(src, Object.assign({}, options, {
3332
- compress: false,
3845
+ minify: false,
3333
3846
  // @ts-ignore
3334
3847
  src: options.resolve(url, options.src).absolute
3335
3848
  }));
@@ -3380,626 +3893,336 @@
3380
3893
  // rule
3381
3894
  if (delim.typ == 'Block-start') {
3382
3895
  const position = map.get(tokens[0]);
3383
- if (context.typ == 'Rule') {
3384
- if (tokens[0]?.typ == 'Iden') {
3385
- errors.push({ action: 'drop', message: 'invalid nesting rule', location: { src, ...position } });
3386
- return null;
3387
- }
3388
- }
3896
+ // if (context.typ == 'Rule') {
3897
+ //
3898
+ // if (tokens[0]?.typ == 'Iden') {
3899
+ // errors.push({action: 'drop', message: 'invalid nesting rule', location: {src, ...position}});
3900
+ // return null;
3901
+ // }
3902
+ // }
3389
3903
  const uniq = new Map;
3390
- parseTokens(tokens, 'Rule', { compress: options.compress }).reduce((acc, curr, index, array) => {
3904
+ parseTokens(tokens, { minify: options.minify }).reduce((acc, curr, index, array) => {
3391
3905
  if (curr.typ == 'Whitespace') {
3392
- if (array[index - 1]?.val == '+' || array[index + 1]?.val == '+') {
3906
+ if (array[index - 1]?.typ == 'Gt' ||
3907
+ array[index + 1]?.typ == 'Gt' ||
3908
+ combinators.includes(array[index - 1]?.val) ||
3909
+ combinators.includes(array[index + 1]?.val)) {
3393
3910
  return acc;
3394
3911
  }
3395
3912
  }
3396
- let t = renderToken(curr, { compress: true });
3913
+ let t = renderToken(curr, { minify: true });
3397
3914
  if (t == ',') {
3398
3915
  acc.push([]);
3399
3916
  }
3400
- else {
3401
- acc[acc.length - 1].push(t);
3402
- }
3403
- return acc;
3404
- }, [[]]).reduce((acc, curr) => {
3405
- acc.set(curr.join(''), curr);
3406
- return acc;
3407
- }, uniq);
3408
- const node = {
3409
- typ: 'Rule',
3410
- // @ts-ignore
3411
- sel: [...uniq.keys()].join(','),
3412
- chi: []
3413
- };
3414
- let raw = [...uniq.values()];
3415
- Object.defineProperty(node, 'raw', { enumerable: false, writable: true, value: raw });
3416
- loc = {
3417
- sta: position,
3418
- src
3419
- };
3420
- if (options.sourcemap) {
3421
- node.loc = loc;
3422
- }
3423
- // @ts-ignore
3424
- context.chi.push(node);
3425
- return node;
3426
- }
3427
- else {
3428
- // declaration
3429
- // @ts-ignore
3430
- let name = null;
3431
- // @ts-ignore
3432
- let value = null;
3433
- for (let i = 0; i < tokens.length; i++) {
3434
- if (tokens[i].typ == 'Comment') {
3435
- continue;
3436
- }
3437
- if (tokens[i].typ == 'Colon') {
3438
- name = tokens.slice(0, i);
3439
- value = parseTokens(tokens.slice(i + 1), 'Declaration', {
3440
- parseColor: true,
3441
- src: options.src,
3442
- resolveUrls: options.resolveUrls,
3443
- resolve: options.resolve,
3444
- cwd: options.cwd
3445
- });
3446
- }
3447
- }
3448
- if (name == null) {
3449
- name = tokens;
3450
- }
3451
- const position = map.get(name[0]);
3452
- if (name.length > 0) {
3453
- for (let i = 1; i < name.length; i++) {
3454
- if (name[i].typ != 'Whitespace' && name[i].typ != 'Comment') {
3455
- errors.push({
3456
- action: 'drop',
3457
- message: 'invalid declaration',
3458
- location: { src, ...position }
3459
- });
3460
- return null;
3461
- }
3462
- }
3463
- }
3464
- if (value == null) {
3465
- errors.push({ action: 'drop', message: 'invalid declaration', location: { src, ...position } });
3466
- return null;
3467
- }
3468
- if (value.length == 0) {
3469
- errors.push({ action: 'drop', message: 'invalid declaration', location: { src, ...position } });
3470
- return null;
3471
- }
3472
- const node = {
3473
- typ: 'Declaration',
3474
- // @ts-ignore
3475
- nam: renderToken(name.shift(), { removeComments: true }),
3476
- // @ts-ignore
3477
- val: value
3478
- };
3479
- while (node.val[0]?.typ == 'Whitespace') {
3480
- node.val.shift();
3481
- }
3482
- if (node.val.length == 0) {
3483
- errors.push({ action: 'drop', message: 'invalid declaration', location: { src, ...position } });
3484
- return null;
3485
- }
3486
- // @ts-ignore
3487
- context.chi.push(node);
3488
- return null;
3489
- }
3490
- }
3491
- }
3492
- function peek(count = 1) {
3493
- if (count == 1) {
3494
- return iterator.charAt(ind + 1);
3495
- }
3496
- return iterator.slice(ind + 1, ind + count + 1);
3497
- }
3498
- function prev(count = 1) {
3499
- if (count == 1) {
3500
- return ind == 0 ? '' : iterator.charAt(ind - 1);
3501
- }
3502
- return iterator.slice(ind - 1 - count, ind - 1);
3503
- }
3504
- function next(count = 1) {
3505
- let char = '';
3506
- while (count-- > 0 && ind < total) {
3507
- const codepoint = iterator.charCodeAt(++ind);
3508
- if (isNaN(codepoint)) {
3509
- return char;
3510
- }
3511
- char += iterator.charAt(ind);
3512
- if (isNewLine(codepoint)) {
3513
- lin++;
3514
- col = 0;
3515
- }
3516
- else {
3517
- col++;
3518
- }
3519
- }
3520
- return char;
3521
- }
3522
- function pushToken(token) {
3523
- tokens.push(token);
3524
- map.set(token, { ...position });
3525
- position.ind = ind;
3526
- position.lin = lin;
3527
- position.col = col == 0 ? 1 : col;
3528
- }
3529
- function consumeWhiteSpace() {
3530
- let count = 0;
3531
- while (isWhiteSpace(iterator.charAt(count + ind + 1).charCodeAt(0))) {
3532
- count++;
3533
- }
3534
- next(count);
3535
- return count;
3536
- }
3537
- function consumeString(quoteStr) {
3538
- const quote = quoteStr;
3539
- let value;
3540
- let hasNewLine = false;
3541
- if (buffer.length > 0) {
3542
- pushToken(getType(buffer));
3543
- buffer = '';
3544
- }
3545
- buffer += quoteStr;
3546
- while (ind < total) {
3547
- value = peek();
3548
- if (ind >= total) {
3549
- pushToken({ typ: hasNewLine ? 'Bad-string' : 'Unclosed-string', val: buffer });
3550
- break;
3551
- }
3552
- if (value == '\\') {
3553
- const sequence = peek(6);
3554
- let escapeSequence = '';
3555
- let codepoint;
3556
- let i;
3557
- for (i = 1; i < sequence.length; i++) {
3558
- codepoint = sequence.charCodeAt(i);
3559
- if (codepoint == 0x20 ||
3560
- (codepoint >= 0x61 && codepoint <= 0x66) ||
3561
- (codepoint >= 0x41 && codepoint <= 0x46) ||
3562
- (codepoint >= 0x30 && codepoint <= 0x39)) {
3563
- escapeSequence += sequence[i];
3564
- if (codepoint == 0x20) {
3565
- break;
3566
- }
3567
- continue;
3568
- }
3569
- break;
3570
- }
3571
- // not hex or new line
3572
- // @ts-ignore
3573
- if (i == 1 && !isNewLine(codepoint)) {
3574
- buffer += sequence[i];
3575
- next(2);
3576
- continue;
3577
- }
3578
- if (escapeSequence.trimEnd().length > 0) {
3579
- const codepoint = Number(`0x${escapeSequence.trimEnd()}`);
3580
- if (codepoint == 0 ||
3581
- // leading surrogate
3582
- (0xD800 <= codepoint && codepoint <= 0xDBFF) ||
3583
- // trailing surrogate
3584
- (0xDC00 <= codepoint && codepoint <= 0xDFFF)) {
3585
- buffer += String.fromCodePoint(0xFFFD);
3586
- }
3587
- else {
3588
- buffer += String.fromCodePoint(codepoint);
3589
- }
3590
- next(escapeSequence.length + 1);
3591
- continue;
3592
- }
3593
- // buffer += value;
3594
- if (ind >= total) {
3595
- // drop '\\' at the end
3596
- pushToken(getType(buffer));
3597
- break;
3598
- }
3599
- buffer += next(2);
3600
- continue;
3601
- }
3602
- if (value == quote) {
3603
- buffer += value;
3604
- pushToken({ typ: hasNewLine ? 'Bad-string' : 'String', val: buffer });
3605
- next();
3606
- // i += value.length;
3607
- buffer = '';
3608
- break;
3609
- }
3610
- if (isNewLine(value.charCodeAt(0))) {
3611
- hasNewLine = true;
3612
- }
3613
- if (hasNewLine && value == ';') {
3614
- pushToken({ typ: 'Bad-string', val: buffer });
3615
- buffer = '';
3616
- break;
3617
- }
3618
- buffer += value;
3619
- // i += value.length;
3620
- next();
3621
- }
3622
- }
3623
- while (ind < total) {
3624
- value = next();
3625
- if (ind >= total) {
3626
- if (buffer.length > 0) {
3627
- pushToken(getType(buffer));
3628
- buffer = '';
3629
- }
3630
- break;
3631
- }
3632
- if (isWhiteSpace(value.charCodeAt(0))) {
3633
- if (buffer.length > 0) {
3634
- pushToken(getType(buffer));
3635
- buffer = '';
3636
- }
3637
- while (ind < total) {
3638
- value = next();
3639
- if (ind >= total) {
3640
- break;
3641
- }
3642
- if (!isWhiteSpace(value.charCodeAt(0))) {
3643
- break;
3644
- }
3645
- }
3646
- pushToken({ typ: 'Whitespace' });
3647
- buffer = '';
3648
- if (ind >= total) {
3649
- break;
3650
- }
3651
- }
3652
- switch (value) {
3653
- case '/':
3654
- if (buffer.length > 0 && tokens.at(-1)?.typ == 'Whitespace') {
3655
- pushToken(getType(buffer));
3656
- buffer = '';
3657
- if (peek() != '*') {
3658
- pushToken(getType(value));
3659
- break;
3660
- }
3661
- }
3662
- buffer += value;
3663
- if (peek() == '*') {
3664
- buffer += '*';
3665
- // i++;
3666
- next();
3667
- while (ind < total) {
3668
- value = next();
3669
- if (ind >= total) {
3670
- pushToken({
3671
- typ: 'Bad-comment', val: buffer
3672
- });
3673
- break;
3674
- }
3675
- if (value == '\\') {
3676
- buffer += value;
3677
- value = next();
3678
- if (ind >= total) {
3679
- pushToken({
3680
- typ: 'Bad-comment',
3681
- val: buffer
3682
- });
3683
- break;
3684
- }
3685
- buffer += value;
3686
- continue;
3687
- }
3688
- if (value == '*') {
3689
- buffer += value;
3690
- value = next();
3691
- if (ind >= total) {
3692
- pushToken({
3693
- typ: 'Bad-comment', val: buffer
3694
- });
3695
- break;
3696
- }
3697
- buffer += value;
3698
- if (value == '/') {
3699
- pushToken({ typ: 'Comment', val: buffer });
3700
- buffer = '';
3701
- break;
3702
- }
3703
- }
3704
- else {
3705
- buffer += value;
3706
- }
3707
- }
3708
- }
3709
- break;
3710
- case '<':
3711
- if (buffer.length > 0) {
3712
- pushToken(getType(buffer));
3713
- buffer = '';
3714
- }
3715
- buffer += value;
3716
- value = next();
3717
- if (ind >= total) {
3718
- break;
3719
- }
3720
- if (peek(3) == '!--') {
3721
- while (ind < total) {
3722
- value = next();
3723
- if (ind >= total) {
3724
- break;
3725
- }
3726
- buffer += value;
3727
- if (value == '>' && prev(2) == '--') {
3728
- pushToken({
3729
- typ: 'CDOCOMM',
3730
- val: buffer
3731
- });
3732
- buffer = '';
3733
- break;
3734
- }
3735
- }
3736
- }
3737
- if (ind >= total) {
3738
- pushToken({ typ: 'BADCDO', val: buffer });
3739
- buffer = '';
3740
- }
3741
- break;
3742
- case '\\':
3743
- value = next();
3744
- // EOF
3745
- if (ind + 1 >= total) {
3746
- // end of stream ignore \\
3747
- pushToken(getType(buffer));
3748
- buffer = '';
3749
- break;
3750
- }
3751
- buffer += value;
3752
- break;
3753
- case '"':
3754
- case "'":
3755
- consumeString(value);
3756
- break;
3757
- case '~':
3758
- case '|':
3759
- if (tokens.at(-1)?.typ == 'Whitespace') {
3760
- tokens.pop();
3761
- }
3762
- if (buffer.length > 0) {
3763
- pushToken(getType(buffer));
3764
- buffer = '';
3765
- }
3766
- buffer += value;
3767
- value = next();
3768
- if (ind >= total) {
3769
- pushToken(getType(buffer));
3770
- buffer = '';
3771
- break;
3772
- }
3773
- if (value == '=') {
3774
- buffer += value;
3775
- pushToken({
3776
- typ: buffer[0] == '~' ? 'Includes' : 'Dash-matches',
3777
- val: buffer
3778
- });
3779
- buffer = '';
3780
- break;
3781
- }
3782
- pushToken(getType(buffer));
3783
- while (isWhiteSpace(value.charCodeAt(0))) {
3784
- value = next();
3785
- }
3786
- buffer = value;
3787
- break;
3788
- case '>':
3789
- if (buffer !== '') {
3790
- pushToken(getType(buffer));
3791
- buffer = '';
3792
- }
3793
- if (tokens[tokens.length - 1]?.typ == 'Whitespace') {
3794
- tokens.pop();
3795
- }
3796
- pushToken({ typ: 'Gt' });
3797
- consumeWhiteSpace();
3798
- break;
3799
- case '.':
3800
- const codepoint = peek().charCodeAt(0);
3801
- if (!isDigit(codepoint) && buffer !== '') {
3802
- pushToken(getType(buffer));
3803
- buffer = value;
3804
- break;
3805
- }
3806
- buffer += value;
3807
- break;
3808
- case '+':
3809
- case ':':
3810
- case ',':
3811
- case '=':
3812
- if (buffer.length > 0) {
3813
- pushToken(getType(buffer));
3814
- buffer = '';
3815
- }
3816
- if (value == ':' && ':' == peek()) {
3817
- buffer += value + next();
3818
- break;
3819
- }
3820
- pushToken(getType(value));
3821
- buffer = '';
3822
- if (value == '+' && isWhiteSpace(peek().charCodeAt(0))) {
3823
- pushToken(getType(next()));
3824
- }
3825
- while (isWhiteSpace(peek().charCodeAt(0))) {
3826
- next();
3917
+ else {
3918
+ acc[acc.length - 1].push(t);
3919
+ }
3920
+ return acc;
3921
+ }, [[]]).reduce((acc, curr) => {
3922
+ acc.set(curr.join(''), curr);
3923
+ return acc;
3924
+ }, uniq);
3925
+ const node = {
3926
+ typ: 'Rule',
3927
+ // @ts-ignore
3928
+ sel: [...uniq.keys()].join(','),
3929
+ chi: []
3930
+ };
3931
+ let raw = [...uniq.values()];
3932
+ Object.defineProperty(node, 'raw', { enumerable: false, writable: true, value: raw });
3933
+ loc = {
3934
+ sta: position,
3935
+ src
3936
+ };
3937
+ if (options.sourcemap) {
3938
+ node.loc = loc;
3827
3939
  }
3828
- break;
3829
- case ')':
3830
- if (buffer.length > 0) {
3831
- pushToken(getType(buffer));
3832
- buffer = '';
3940
+ // @ts-ignore
3941
+ context.chi.push(node);
3942
+ return node;
3943
+ }
3944
+ else {
3945
+ // declaration
3946
+ // @ts-ignore
3947
+ let name = null;
3948
+ // @ts-ignore
3949
+ let value = null;
3950
+ for (let i = 0; i < tokens.length; i++) {
3951
+ if (tokens[i].typ == 'Comment') {
3952
+ continue;
3953
+ }
3954
+ if (tokens[i].typ == 'Colon') {
3955
+ name = tokens.slice(0, i);
3956
+ value = parseTokens(tokens.slice(i + 1), {
3957
+ parseColor: true,
3958
+ src: options.src,
3959
+ resolveUrls: options.resolveUrls,
3960
+ resolve: options.resolve,
3961
+ cwd: options.cwd
3962
+ });
3963
+ }
3833
3964
  }
3834
- pushToken({ typ: 'End-parens' });
3835
- break;
3836
- case '(':
3837
- if (buffer.length == 0) {
3838
- pushToken({ typ: 'Start-parens' });
3965
+ if (name == null) {
3966
+ name = tokens;
3839
3967
  }
3840
- else {
3841
- buffer += value;
3842
- pushToken(getType(buffer));
3843
- buffer = '';
3844
- const token = tokens[tokens.length - 1];
3845
- if (token.typ == 'UrlFunc') {
3846
- // consume either string or url token
3847
- let whitespace = '';
3848
- value = peek();
3849
- while (isWhiteSpace(value.charCodeAt(0))) {
3850
- whitespace += value;
3851
- }
3852
- if (whitespace.length > 0) {
3853
- next(whitespace.length);
3854
- }
3855
- value = peek();
3856
- if (value == '"' || value == "'") {
3857
- consumeString(next());
3858
- let token = tokens[tokens.length - 1];
3859
- if (['String', 'Literal'].includes(token.typ) && urlTokenMatcher.test(token.val)) {
3860
- if (token.val.slice(1, 6) != 'data:') {
3861
- if (token.typ == 'String') {
3862
- token.val = token.val.slice(1, -1);
3863
- }
3864
- // @ts-ignore
3865
- token.typ = 'Url-token';
3866
- }
3867
- }
3868
- break;
3869
- }
3870
- else {
3871
- buffer = '';
3872
- do {
3873
- let cp = value.charCodeAt(0);
3874
- // EOF -
3875
- if (cp == null) {
3876
- pushToken({ typ: 'Bad-url-token', val: buffer });
3877
- break;
3878
- }
3879
- // ')'
3880
- if (cp == 0x29 || cp == null) {
3881
- if (buffer.length == 0) {
3882
- pushToken({ typ: 'Bad-url-token', val: '' });
3883
- }
3884
- else {
3885
- pushToken({ typ: 'Url-token', val: buffer });
3886
- }
3887
- if (cp != null) {
3888
- pushToken(getType(next()));
3889
- }
3890
- break;
3891
- }
3892
- if (isWhiteSpace(cp)) {
3893
- whitespace = next();
3894
- while (true) {
3895
- value = peek();
3896
- cp = value.charCodeAt(0);
3897
- if (isWhiteSpace(cp)) {
3898
- whitespace += value;
3899
- continue;
3900
- }
3901
- break;
3902
- }
3903
- if (cp == null || cp == 0x29) {
3904
- continue;
3905
- }
3906
- // bad url token
3907
- buffer += next(whitespace.length);
3908
- do {
3909
- value = peek();
3910
- cp = value.charCodeAt(0);
3911
- if (cp == null || cp == 0x29) {
3912
- break;
3913
- }
3914
- buffer += next();
3915
- } while (true);
3916
- pushToken({ typ: 'Bad-url-token', val: buffer });
3917
- continue;
3918
- }
3919
- buffer += next();
3920
- value = peek();
3921
- } while (true);
3922
- buffer = '';
3968
+ const position = map.get(name[0]);
3969
+ if (name.length > 0) {
3970
+ for (let i = 1; i < name.length; i++) {
3971
+ if (name[i].typ != 'Whitespace' && name[i].typ != 'Comment') {
3972
+ errors.push({
3973
+ action: 'drop',
3974
+ message: 'invalid declaration',
3975
+ location: { src, ...position }
3976
+ });
3977
+ return null;
3923
3978
  }
3924
3979
  }
3925
3980
  }
3926
- break;
3927
- case '[':
3928
- case ']':
3929
- case '{':
3930
- case '}':
3931
- case ';':
3932
- if (buffer.length > 0) {
3933
- pushToken(getType(buffer));
3934
- buffer = '';
3981
+ if (value == null) {
3982
+ errors.push({
3983
+ action: 'drop',
3984
+ message: 'invalid declaration',
3985
+ location: { src, ...position }
3986
+ });
3987
+ return null;
3935
3988
  }
3936
- pushToken(getBlockType(value));
3937
- let node = null;
3938
- if (value == '{' || value == ';') {
3939
- node = await parseNode(tokens);
3940
- if (node != null) {
3941
- stack.push(node);
3942
- // @ts-ignore
3943
- context = node;
3944
- }
3945
- else if (value == '{') {
3946
- // node == null
3947
- // consume and throw away until the closing '}' or EOF
3948
- consume('{', '}');
3949
- }
3950
- tokens.length = 0;
3951
- map.clear();
3989
+ if (value.length == 0) {
3990
+ errors.push({
3991
+ action: 'drop',
3992
+ message: 'invalid declaration',
3993
+ location: { src, ...position }
3994
+ });
3995
+ return null;
3952
3996
  }
3953
- else if (value == '}') {
3954
- await parseNode(tokens);
3955
- const previousNode = stack.pop();
3997
+ const node = {
3998
+ typ: 'Declaration',
3956
3999
  // @ts-ignore
3957
- context = stack[stack.length - 1] || ast;
4000
+ nam: renderToken(name.shift(), { removeComments: true }),
3958
4001
  // @ts-ignore
3959
- if (options.removeEmpty && previousNode != null && previousNode.chi.length == 0 && context.chi[context.chi.length - 1] == previousNode) {
3960
- context.chi.pop();
3961
- }
3962
- tokens.length = 0;
3963
- map.clear();
3964
- buffer = '';
3965
- }
3966
- break;
3967
- case '!':
3968
- if (buffer.length > 0) {
3969
- pushToken(getType(buffer));
3970
- buffer = '';
4002
+ val: value
4003
+ };
4004
+ while (node.val[0]?.typ == 'Whitespace') {
4005
+ node.val.shift();
3971
4006
  }
3972
- const important = peek(9);
3973
- if (important == 'important') {
3974
- if (tokens[tokens.length - 1]?.typ == 'Whitespace') {
3975
- tokens.pop();
3976
- }
3977
- pushToken({ typ: 'Important' });
3978
- next(9);
3979
- buffer = '';
3980
- break;
4007
+ if (node.val.length == 0) {
4008
+ errors.push({
4009
+ action: 'drop',
4010
+ message: 'invalid declaration',
4011
+ location: { src, ...position }
4012
+ });
4013
+ return null;
3981
4014
  }
3982
- buffer = '!';
3983
- break;
3984
- default:
3985
- buffer += value;
3986
- break;
4015
+ // @ts-ignore
4016
+ context.chi.push(node);
4017
+ return null;
4018
+ }
3987
4019
  }
3988
4020
  }
3989
- if (buffer.length > 0) {
3990
- pushToken(getType(buffer));
4021
+ function mapToken(token) {
4022
+ const node = getTokenType(token.token, token.hint);
4023
+ map.set(node, token.position);
4024
+ return node;
4025
+ }
4026
+ const iter = tokenize(iterator);
4027
+ let item;
4028
+ while (true) {
4029
+ item = iter.next().value;
4030
+ if (item == null) {
4031
+ break;
4032
+ }
4033
+ tokens.push(item);
4034
+ bytesIn = item.bytesIn;
4035
+ if (item.token == ';' || item.token == '{') {
4036
+ let node = await parseNode(tokens);
4037
+ if (node != null) {
4038
+ stack.push(node);
4039
+ // @ts-ignore
4040
+ context = node;
4041
+ }
4042
+ else if (item.token == '{') {
4043
+ // node == null
4044
+ // consume and throw away until the closing '}' or EOF
4045
+ let inBlock = 1;
4046
+ do {
4047
+ item = iter.next().value;
4048
+ if (item == null) {
4049
+ break;
4050
+ }
4051
+ if (item.token == '{') {
4052
+ inBlock++;
4053
+ }
4054
+ else if (item.token == '}') {
4055
+ inBlock--;
4056
+ }
4057
+ } while (inBlock != 0);
4058
+ }
4059
+ tokens = [];
4060
+ map = new Map;
4061
+ }
4062
+ else if (item.token == '}') {
4063
+ await parseNode(tokens);
4064
+ const previousNode = stack.pop();
4065
+ // @ts-ignore
4066
+ context = stack[stack.length - 1] || ast;
4067
+ // @ts-ignore
4068
+ if (options.removeEmpty && previousNode != null && previousNode.chi.length == 0 && context.chi[context.chi.length - 1] == previousNode) {
4069
+ context.chi.pop();
4070
+ }
4071
+ tokens = [];
4072
+ map = new Map;
4073
+ }
3991
4074
  }
3992
4075
  if (tokens.length > 0) {
3993
4076
  await parseNode(tokens);
3994
4077
  }
3995
- if (options.compress) {
4078
+ if (options.minify) {
3996
4079
  if (ast.chi.length > 0) {
3997
- deduplicate(ast, options, true);
4080
+ minify(ast, options, true);
3998
4081
  }
3999
4082
  }
4000
4083
  return { ast, errors, bytesIn };
4001
4084
  }
4002
- function parseTokens(tokens, nodeType, options = {}) {
4085
+ function parseString(src, options = { location: false }) {
4086
+ return [...tokenize(src)].map(t => {
4087
+ const token = getTokenType(t.token, t.hint);
4088
+ if (options.location) {
4089
+ Object.assign(token, { loc: t.position });
4090
+ }
4091
+ return token;
4092
+ });
4093
+ }
4094
+ function getTokenType(val, hint) {
4095
+ if (val === '' && hint == null) {
4096
+ throw new Error('empty string?');
4097
+ }
4098
+ if (hint != null) {
4099
+ return ([
4100
+ 'Whitespace', 'Semi-colon', 'Colon', 'Block-start',
4101
+ 'Block-start', 'Attr-start', 'Attr-end', 'Start-parens', 'End-parens',
4102
+ 'Comma', 'Gt', 'Lt'
4103
+ ].includes(hint) ? { typ: hint } : { typ: hint, val });
4104
+ }
4105
+ if (val == ' ') {
4106
+ return { typ: 'Whitespace' };
4107
+ }
4108
+ if (val == ';') {
4109
+ return { typ: 'Semi-colon' };
4110
+ }
4111
+ if (val == '{') {
4112
+ return { typ: 'Block-start' };
4113
+ }
4114
+ if (val == '}') {
4115
+ return { typ: 'Block-end' };
4116
+ }
4117
+ if (val == '[') {
4118
+ return { typ: 'Attr-start' };
4119
+ }
4120
+ if (val == ']') {
4121
+ return { typ: 'Attr-end' };
4122
+ }
4123
+ if (val == ':') {
4124
+ return { typ: 'Colon' };
4125
+ }
4126
+ if (val == ')') {
4127
+ return { typ: 'End-parens' };
4128
+ }
4129
+ if (val == '(') {
4130
+ return { typ: 'Start-parens' };
4131
+ }
4132
+ if (val == '=') {
4133
+ return { typ: 'Delim', val };
4134
+ }
4135
+ if (val == ';') {
4136
+ return { typ: 'Semi-colon' };
4137
+ }
4138
+ if (val == ',') {
4139
+ return { typ: 'Comma' };
4140
+ }
4141
+ if (val == '<') {
4142
+ return { typ: 'Lt' };
4143
+ }
4144
+ if (val == '>') {
4145
+ return { typ: 'Gt' };
4146
+ }
4147
+ if (isPseudo(val)) {
4148
+ return val.endsWith('(') ? {
4149
+ typ: 'Pseudo-class-func',
4150
+ val: val.slice(0, -1),
4151
+ chi: []
4152
+ }
4153
+ : {
4154
+ typ: 'Pseudo-class',
4155
+ val
4156
+ };
4157
+ }
4158
+ if (isAtKeyword(val)) {
4159
+ return {
4160
+ typ: 'At-rule',
4161
+ val: val.slice(1)
4162
+ };
4163
+ }
4164
+ if (isFunction(val)) {
4165
+ val = val.slice(0, -1);
4166
+ return {
4167
+ typ: val == 'url' ? 'UrlFunc' : 'Func',
4168
+ val,
4169
+ chi: []
4170
+ };
4171
+ }
4172
+ if (isNumber(val)) {
4173
+ return {
4174
+ typ: 'Number',
4175
+ val
4176
+ };
4177
+ }
4178
+ if (isDimension(val)) {
4179
+ return parseDimension(val);
4180
+ }
4181
+ if (isPercentage(val)) {
4182
+ return {
4183
+ typ: 'Perc',
4184
+ val: val.slice(0, -1)
4185
+ };
4186
+ }
4187
+ const v = val.toLowerCase();
4188
+ if (v == 'currentcolor' || val == 'transparent' || v in COLORS_NAMES) {
4189
+ return {
4190
+ typ: 'Color',
4191
+ val,
4192
+ kin: 'lit'
4193
+ };
4194
+ }
4195
+ if (isIdent(val)) {
4196
+ return {
4197
+ typ: 'Iden',
4198
+ val
4199
+ };
4200
+ }
4201
+ if (val.charAt(0) == '#' && isHexColor(val)) {
4202
+ return {
4203
+ typ: 'Color',
4204
+ val,
4205
+ kin: 'hex'
4206
+ };
4207
+ }
4208
+ if (val.charAt(0) == '#' && isHash(val)) {
4209
+ return {
4210
+ typ: 'Hash',
4211
+ val
4212
+ };
4213
+ }
4214
+ if ('"\''.includes(val.charAt(0))) {
4215
+ return {
4216
+ typ: 'Unclosed-string',
4217
+ val
4218
+ };
4219
+ }
4220
+ return {
4221
+ typ: 'Literal',
4222
+ val
4223
+ };
4224
+ }
4225
+ function parseTokens(tokens, options = {}) {
4003
4226
  for (let i = 0; i < tokens.length; i++) {
4004
4227
  const t = tokens[i];
4005
4228
  if (t.typ == 'Whitespace' && ((i == 0 ||
@@ -4053,7 +4276,7 @@
4053
4276
  if (t.chi.length > 1) {
4054
4277
  /*(<AttrToken>t).chi =*/
4055
4278
  // @ts-ignore
4056
- parseTokens(t.chi, t.typ, options);
4279
+ parseTokens(t.chi, t.typ);
4057
4280
  }
4058
4281
  // @ts-ignore
4059
4282
  t.chi.forEach(val => {
@@ -4165,8 +4388,8 @@
4165
4388
  // @ts-ignore
4166
4389
  if (t.chi.length > 0) {
4167
4390
  // @ts-ignore
4168
- parseTokens(t.chi, t.typ, options);
4169
- if (t.typ == 'Pseudo-class-func' && t.val == ':is' && options.compress) {
4391
+ parseTokens(t.chi, t.typ);
4392
+ if (t.typ == 'Pseudo-class-func' && t.val == ':is' && options.minify) {
4170
4393
  //
4171
4394
  const count = t.chi.filter(t => t.typ != 'Comment').length;
4172
4395
  if (count == 1 ||
@@ -4204,40 +4427,9 @@
4204
4427
  }
4205
4428
  return tokens;
4206
4429
  }
4207
- function getBlockType(chr) {
4208
- if (chr == ';') {
4209
- return { typ: 'Semi-colon' };
4210
- }
4211
- if (chr == '{') {
4212
- return { typ: 'Block-start' };
4213
- }
4214
- if (chr == '}') {
4215
- return { typ: 'Block-end' };
4216
- }
4217
- if (chr == '[') {
4218
- return { typ: 'Attr-start' };
4219
- }
4220
- if (chr == ']') {
4221
- return { typ: 'Attr-end' };
4222
- }
4223
- throw new Error(`unhandled token: '${chr}'`);
4224
- }
4225
-
4226
- function* walk(node) {
4227
- // @ts-ignore
4228
- yield* doWalk(node, null, null);
4229
- }
4230
- function* doWalk(node, parent, root) {
4231
- yield { node, parent, root };
4232
- if ('chi' in node) {
4233
- for (const child of node.chi) {
4234
- yield* doWalk(child, node, (root ?? node));
4235
- }
4236
- }
4237
- }
4238
4430
 
4239
4431
  async function transform$1(css, options = {}) {
4240
- options = { compress: true, removeEmpty: true, ...options };
4432
+ options = { minify: true, removeEmpty: true, ...options };
4241
4433
  const startTime = performance.now();
4242
4434
  const parseResult = await parse$1(css, options);
4243
4435
  const renderTime = performance.now();
@@ -4385,18 +4577,44 @@
4385
4577
  }));
4386
4578
  }
4387
4579
 
4388
- exports.deduplicate = deduplicate;
4389
- exports.deduplicateRule = deduplicateRule;
4580
+ exports.combinators = combinators;
4390
4581
  exports.dirname = dirname;
4582
+ exports.getConfig = getConfig;
4391
4583
  exports.hasDeclaration = hasDeclaration;
4584
+ exports.isAngle = isAngle;
4585
+ exports.isAtKeyword = isAtKeyword;
4586
+ exports.isDigit = isDigit;
4587
+ exports.isDimension = isDimension;
4588
+ exports.isFrequency = isFrequency;
4589
+ exports.isFunction = isFunction;
4590
+ exports.isHash = isHash;
4591
+ exports.isHexColor = isHexColor;
4592
+ exports.isHexDigit = isHexDigit;
4593
+ exports.isIdent = isIdent;
4594
+ exports.isIdentCodepoint = isIdentCodepoint;
4595
+ exports.isIdentStart = isIdentStart;
4596
+ exports.isLength = isLength;
4597
+ exports.isNewLine = isNewLine;
4598
+ exports.isNumber = isNumber;
4599
+ exports.isPercentage = isPercentage;
4600
+ exports.isPseudo = isPseudo;
4601
+ exports.isResolution = isResolution;
4602
+ exports.isTime = isTime;
4603
+ exports.isWhiteSpace = isWhiteSpace;
4392
4604
  exports.load = load;
4393
4605
  exports.matchUrl = matchUrl;
4606
+ exports.minify = minify;
4607
+ exports.minifyRule = minifyRule;
4394
4608
  exports.parse = parse;
4609
+ exports.parseDimension = parseDimension;
4610
+ exports.parseString = parseString;
4395
4611
  exports.reduceSelector = reduceSelector;
4396
4612
  exports.render = render;
4397
4613
  exports.renderToken = renderToken;
4398
4614
  exports.resolve = resolve;
4615
+ exports.tokenize = tokenize;
4399
4616
  exports.transform = transform;
4617
+ exports.urlTokenMatcher = urlTokenMatcher;
4400
4618
  exports.walk = walk;
4401
4619
 
4402
4620
  }));