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