@tbela99/css-parser 0.9.1 → 1.1.0

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.
Files changed (99) hide show
  1. package/CHANGELOG.md +265 -0
  2. package/LICENSE.md +1 -1
  3. package/README.md +29 -17
  4. package/dist/index-umd-web.js +7461 -4360
  5. package/dist/index.cjs +8608 -5507
  6. package/dist/index.d.ts +203 -61
  7. package/dist/lib/ast/expand.js +2 -1
  8. package/dist/lib/ast/features/calc.js +19 -11
  9. package/dist/lib/ast/features/index.js +1 -0
  10. package/dist/lib/ast/features/inlinecssvariables.js +47 -29
  11. package/dist/lib/ast/features/prefix.js +117 -91
  12. package/dist/lib/ast/features/shorthand.js +34 -14
  13. package/dist/lib/ast/features/transform.js +67 -0
  14. package/dist/lib/ast/features/type.js +7 -0
  15. package/dist/lib/ast/math/expression.js +20 -10
  16. package/dist/lib/ast/math/math.js +20 -2
  17. package/dist/lib/ast/minify.js +209 -80
  18. package/dist/lib/ast/transform/compute.js +337 -0
  19. package/dist/lib/ast/transform/convert.js +33 -0
  20. package/dist/lib/ast/transform/matrix.js +112 -0
  21. package/dist/lib/ast/transform/minify.js +296 -0
  22. package/dist/lib/ast/transform/perspective.js +10 -0
  23. package/dist/lib/ast/transform/rotate.js +40 -0
  24. package/dist/lib/ast/transform/scale.js +32 -0
  25. package/dist/lib/ast/transform/skew.js +23 -0
  26. package/dist/lib/ast/transform/translate.js +32 -0
  27. package/dist/lib/ast/transform/utils.js +198 -0
  28. package/dist/lib/ast/types.js +18 -15
  29. package/dist/lib/ast/walk.js +54 -22
  30. package/dist/lib/fs/resolve.js +10 -0
  31. package/dist/lib/parser/declaration/list.js +48 -45
  32. package/dist/lib/parser/declaration/map.js +1 -0
  33. package/dist/lib/parser/declaration/set.js +2 -1
  34. package/dist/lib/parser/parse.js +449 -340
  35. package/dist/lib/parser/tokenize.js +147 -72
  36. package/dist/lib/parser/utils/declaration.js +5 -4
  37. package/dist/lib/parser/utils/type.js +2 -1
  38. package/dist/lib/renderer/color/a98rgb.js +2 -1
  39. package/dist/lib/renderer/color/{colormix.js → color-mix.js} +16 -7
  40. package/dist/lib/renderer/color/color.js +264 -170
  41. package/dist/lib/renderer/color/hex.js +19 -8
  42. package/dist/lib/renderer/color/hsl.js +9 -3
  43. package/dist/lib/renderer/color/hwb.js +2 -1
  44. package/dist/lib/renderer/color/lab.js +10 -1
  45. package/dist/lib/renderer/color/lch.js +10 -1
  46. package/dist/lib/renderer/color/oklab.js +10 -1
  47. package/dist/lib/renderer/color/oklch.js +10 -1
  48. package/dist/lib/renderer/color/p3.js +2 -1
  49. package/dist/lib/renderer/color/rec2020.js +2 -1
  50. package/dist/lib/renderer/color/relativecolor.js +27 -32
  51. package/dist/lib/renderer/color/rgb.js +14 -10
  52. package/dist/lib/renderer/color/srgb.js +48 -23
  53. package/dist/lib/renderer/color/utils/components.js +18 -6
  54. package/dist/lib/renderer/color/utils/constants.js +47 -3
  55. package/dist/lib/renderer/color/xyz.js +2 -1
  56. package/dist/lib/renderer/color/xyzd50.js +2 -1
  57. package/dist/lib/renderer/render.js +108 -43
  58. package/dist/lib/syntax/syntax.js +267 -136
  59. package/dist/lib/validation/at-rules/container.js +81 -103
  60. package/dist/lib/validation/at-rules/counter-style.js +9 -8
  61. package/dist/lib/validation/at-rules/custom-media.js +13 -15
  62. package/dist/lib/validation/at-rules/document.js +22 -27
  63. package/dist/lib/validation/at-rules/font-feature-values.js +8 -8
  64. package/dist/lib/validation/at-rules/import.js +30 -81
  65. package/dist/lib/validation/at-rules/keyframes.js +19 -23
  66. package/dist/lib/validation/at-rules/layer.js +5 -5
  67. package/dist/lib/validation/at-rules/media.js +42 -53
  68. package/dist/lib/validation/at-rules/namespace.js +19 -23
  69. package/dist/lib/validation/at-rules/page-margin-box.js +15 -18
  70. package/dist/lib/validation/at-rules/page.js +8 -7
  71. package/dist/lib/validation/at-rules/supports.js +73 -82
  72. package/dist/lib/validation/at-rules/when.js +32 -36
  73. package/dist/lib/validation/atrule.js +15 -18
  74. package/dist/lib/validation/config.js +24 -1
  75. package/dist/lib/validation/config.json.js +563 -63
  76. package/dist/lib/validation/parser/parse.js +196 -185
  77. package/dist/lib/validation/parser/types.js +1 -1
  78. package/dist/lib/validation/selector.js +8 -5
  79. package/dist/lib/validation/syntax.js +724 -1405
  80. package/dist/lib/validation/syntaxes/complex-selector-list.js +10 -11
  81. package/dist/lib/validation/syntaxes/complex-selector.js +10 -11
  82. package/dist/lib/validation/syntaxes/compound-selector.js +40 -50
  83. package/dist/lib/validation/syntaxes/family-name.js +9 -8
  84. package/dist/lib/validation/syntaxes/keyframe-block-list.js +6 -5
  85. package/dist/lib/validation/syntaxes/keyframe-selector.js +23 -105
  86. package/dist/lib/validation/syntaxes/layer-name.js +6 -5
  87. package/dist/lib/validation/syntaxes/relative-selector-list.js +7 -6
  88. package/dist/lib/validation/syntaxes/relative-selector.js +17 -15
  89. package/dist/lib/validation/syntaxes/url.js +18 -22
  90. package/dist/lib/validation/utils/list.js +20 -2
  91. package/dist/lib/validation/utils/whitespace.js +2 -1
  92. package/dist/node/index.js +4 -2
  93. package/dist/node/load.js +6 -1
  94. package/dist/web/index.js +4 -2
  95. package/dist/web/load.js +5 -0
  96. package/package.json +16 -15
  97. package/dist/lib/renderer/color/prophotoRgb.js +0 -56
  98. package/dist/lib/validation/declaration.js +0 -94
  99. package/dist/lib/validation/syntaxes/image.js +0 -29
@@ -2,8 +2,9 @@ import { EnumToken } from '../../../ast/types.js';
2
2
  import '../../../ast/minify.js';
3
3
  import '../../../ast/walk.js';
4
4
  import '../../../parser/parse.js';
5
- import '../../sourcemap/lib/encode.js';
5
+ import '../../../parser/tokenize.js';
6
6
  import '../../../parser/utils/config.js';
7
+ import '../../sourcemap/lib/encode.js';
7
8
 
8
9
  const colorRange = {
9
10
  lab: {
@@ -27,8 +28,51 @@ const colorRange = {
27
28
  b: [0, 0.4]
28
29
  }
29
30
  };
31
+ // xyz-d65 is an alias for xyz
32
+ // display-p3 is an alias for srgb
33
+ var ColorKind;
34
+ (function (ColorKind) {
35
+ ColorKind[ColorKind["SYS"] = 0] = "SYS";
36
+ ColorKind[ColorKind["DPSYS"] = 1] = "DPSYS";
37
+ ColorKind[ColorKind["LIT"] = 2] = "LIT";
38
+ ColorKind[ColorKind["HEX"] = 3] = "HEX";
39
+ ColorKind[ColorKind["RGB"] = 4] = "RGB";
40
+ ColorKind[ColorKind["RGBA"] = 5] = "RGBA";
41
+ ColorKind[ColorKind["HSL"] = 6] = "HSL";
42
+ ColorKind[ColorKind["HSLA"] = 7] = "HSLA";
43
+ ColorKind[ColorKind["HWB"] = 8] = "HWB";
44
+ ColorKind[ColorKind["DEVICE_CMYK"] = 9] = "DEVICE_CMYK";
45
+ ColorKind[ColorKind["OKLAB"] = 10] = "OKLAB";
46
+ ColorKind[ColorKind["OKLCH"] = 11] = "OKLCH";
47
+ ColorKind[ColorKind["LAB"] = 12] = "LAB";
48
+ ColorKind[ColorKind["LCH"] = 13] = "LCH";
49
+ ColorKind[ColorKind["COLOR"] = 14] = "COLOR";
50
+ ColorKind[ColorKind["SRGB"] = 15] = "SRGB";
51
+ ColorKind[ColorKind["PROPHOTO_RGB"] = 16] = "PROPHOTO_RGB";
52
+ ColorKind[ColorKind["A98_RGB"] = 17] = "A98_RGB";
53
+ ColorKind[ColorKind["REC2020"] = 18] = "REC2020";
54
+ ColorKind[ColorKind["DISPLAY_P3"] = 19] = "DISPLAY_P3";
55
+ ColorKind[ColorKind["SRGB_LINEAR"] = 20] = "SRGB_LINEAR";
56
+ ColorKind[ColorKind["XYZ"] = 21] = "XYZ";
57
+ ColorKind[ColorKind["XYZ_D50"] = 22] = "XYZ_D50";
58
+ ColorKind[ColorKind["XYZ_D65"] = 23] = "XYZ_D65";
59
+ ColorKind[ColorKind["LIGHT_DARK"] = 24] = "LIGHT_DARK";
60
+ ColorKind[ColorKind["COLOR_MIX"] = 25] = "COLOR_MIX";
61
+ })(ColorKind || (ColorKind = {}));
62
+ const generalEnclosedFunc = ['selector', 'font-tech', 'font-format', 'media', 'supports'];
63
+ const funcLike = [
64
+ EnumToken.ParensTokenType,
65
+ EnumToken.FunctionTokenType,
66
+ EnumToken.UrlFunctionTokenType,
67
+ EnumToken.StartParensTokenType,
68
+ EnumToken.ImageFunctionTokenType,
69
+ EnumToken.TimingFunctionTokenType,
70
+ EnumToken.TimingFunctionTokenType,
71
+ EnumToken.PseudoClassFuncTokenType,
72
+ EnumToken.GridTemplateFuncTokenType
73
+ ];
74
+ const colorsFunc = ['rgb', 'rgba', 'hsl', 'hsla', 'hwb', 'device-cmyk', 'color-mix', 'color', 'oklab', 'lab', 'oklch', 'lch', 'light-dark'];
30
75
  const colorFuncColorSpace = ['srgb', 'srgb-linear', 'display-p3', 'prophoto-rgb', 'a98-rgb', 'rec2020', 'xyz', 'xyz-d65', 'xyz-d50'];
31
- ({ typ: EnumToken.IdenTokenType});
32
76
  const D50 = [0.3457 / 0.3585, 1.00000, (1.0 - 0.3457 - 0.3585) / 0.3585];
33
77
  const k = Math.pow(29, 3) / Math.pow(3, 3);
34
78
  const e = Math.pow(6, 3) / Math.pow(29, 3);
@@ -194,4 +238,4 @@ const NAMES_COLORS = Object.seal(Object.entries(COLORS_NAMES).reduce((acc, [key,
194
238
  return acc;
195
239
  }, Object.create(null)));
196
240
 
197
- export { COLORS_NAMES, D50, NAMES_COLORS, colorFuncColorSpace, colorRange, deprecatedSystemColors, e, k, systemColors };
241
+ export { COLORS_NAMES, ColorKind, D50, NAMES_COLORS, colorFuncColorSpace, colorRange, colorsFunc, deprecatedSystemColors, e, funcLike, generalEnclosedFunc, k, systemColors };
@@ -4,9 +4,10 @@ import '../../ast/types.js';
4
4
  import '../../ast/minify.js';
5
5
  import '../../ast/walk.js';
6
6
  import '../../parser/parse.js';
7
+ import '../../parser/tokenize.js';
8
+ import '../../parser/utils/config.js';
7
9
  import { srgb2lsrgbvalues } from './srgb.js';
8
10
  import '../sourcemap/lib/encode.js';
9
- import '../../parser/utils/config.js';
10
11
 
11
12
  function XYZ_to_lin_sRGB(x, y, z) {
12
13
  // convert XYZ to linear-light sRGB
@@ -5,11 +5,12 @@ import '../../ast/types.js';
5
5
  import '../../ast/minify.js';
6
6
  import '../../ast/walk.js';
7
7
  import '../../parser/parse.js';
8
+ import '../../parser/tokenize.js';
9
+ import '../../parser/utils/config.js';
8
10
  import { xyz2lab } from './lab.js';
9
11
  import { lab2lchvalues } from './lch.js';
10
12
  import { XYZ_D50_to_D65 } from './xyz.js';
11
13
  import '../sourcemap/lib/encode.js';
12
- import '../../parser/utils/config.js';
13
14
 
14
15
  /*
15
16
  */
@@ -1,17 +1,16 @@
1
1
  import { getAngle, color2srgbvalues, clamp } from './color/color.js';
2
- import { colorFuncColorSpace, COLORS_NAMES } from './color/utils/constants.js';
2
+ import { colorsFunc, ColorKind, colorFuncColorSpace, COLORS_NAMES, funcLike } from './color/utils/constants.js';
3
3
  import { getComponents } from './color/utils/components.js';
4
4
  import { reduceHexValue, srgb2hexvalues, rgb2hex, hsl2hex, hwb2hex, cmyk2hex, oklab2hex, oklch2hex, lab2hex, lch2hex } from './color/hex.js';
5
5
  import { EnumToken } from '../ast/types.js';
6
6
  import '../ast/minify.js';
7
7
  import '../ast/walk.js';
8
8
  import { expand } from '../ast/expand.js';
9
- import { colorMix } from './color/colormix.js';
9
+ import { colorMix } from './color/color-mix.js';
10
10
  import { parseRelativeColor } from './color/relativecolor.js';
11
11
  import { SourceMap } from './sourcemap/sourcemap.js';
12
12
  import { isColor, pseudoElements, mathFuncs, isNewLine } from '../syntax/syntax.js';
13
13
 
14
- const colorsFunc = ['rgb', 'rgba', 'hsl', 'hsla', 'hwb', 'device-cmyk', 'color-mix', 'color', 'oklab', 'lab', 'oklch', 'lch', 'light-dark'];
15
14
  function reduceNumber(val) {
16
15
  val = String(+val);
17
16
  if (val === '0') {
@@ -59,7 +58,8 @@ function doRender(data, options = {}) {
59
58
  }),
60
59
  ...(minify ? {
61
60
  removeEmpty: true,
62
- removeComments: true
61
+ removeComments: true,
62
+ minify: true
63
63
  } : {
64
64
  removeEmpty: false,
65
65
  removeComments: false,
@@ -105,11 +105,17 @@ function doRender(data, options = {}) {
105
105
  }
106
106
  if (sourcemap != null) {
107
107
  result.map = sourcemap;
108
+ if (options.sourcemap === 'inline') {
109
+ result.code += `\n/*# sourceMappingURL=data:application/json,${encodeURIComponent(JSON.stringify(result.map))} */`;
110
+ }
108
111
  }
109
112
  return result;
110
113
  }
111
114
  function updateSourceMap(node, options, cache, sourcemap, position, str) {
112
- if ([EnumToken.RuleNodeType, EnumToken.AtRuleNodeType, EnumToken.KeyFrameRuleNodeType].includes(node.typ)) {
115
+ if ([
116
+ EnumToken.RuleNodeType, EnumToken.AtRuleNodeType,
117
+ EnumToken.KeyFrameRuleNodeType, EnumToken.KeyframeAtRuleNodeType
118
+ ].includes(node.typ)) {
113
119
  let src = node.loc?.src ?? '';
114
120
  let output = options.output ?? '';
115
121
  if (!(src in cache)) {
@@ -152,7 +158,7 @@ function renderAstNode(data, options, sourcemap, position, errors, reducer, cach
152
158
  const indentSub = indents[level + 1];
153
159
  switch (data.typ) {
154
160
  case EnumToken.DeclarationNodeType:
155
- return `${data.nam}:${options.indent}${data.val.reduce(reducer, '')}`;
161
+ return `${data.nam}:${options.indent}${(options.minify ? filterValues(data.val) : data.val).reduce(reducer, '')}`;
156
162
  case EnumToken.CommentNodeType:
157
163
  case EnumToken.CDOCOMMNodeType:
158
164
  if (data.val.startsWith('/*# sourceMappingURL=')) {
@@ -181,7 +187,8 @@ function renderAstNode(data, options, sourcemap, position, errors, reducer, cach
181
187
  case EnumToken.AtRuleNodeType:
182
188
  case EnumToken.RuleNodeType:
183
189
  case EnumToken.KeyFrameRuleNodeType:
184
- if (data.typ == EnumToken.AtRuleNodeType && !('chi' in data)) {
190
+ case EnumToken.KeyframeAtRuleNodeType:
191
+ if ([EnumToken.AtRuleNodeType, EnumToken.KeyframeAtRuleNodeType].includes(data.typ) && !('chi' in data)) {
185
192
  return `${indent}@${data.nam}${data.val === '' ? '' : options.indent || ' '}${data.val};`;
186
193
  }
187
194
  // @ts-ignore
@@ -191,7 +198,7 @@ function renderAstNode(data, options, sourcemap, position, errors, reducer, cach
191
198
  str = options.removeComments && (!options.preserveLicense || !node.val.startsWith('/*!')) ? '' : node.val;
192
199
  }
193
200
  else if (node.typ == EnumToken.DeclarationNodeType) {
194
- if (node.val.length == 0) {
201
+ if (!node.nam.startsWith('--') && node.val.length == 0) {
195
202
  // @ts-ignore
196
203
  errors.push({
197
204
  action: 'ignore',
@@ -200,7 +207,7 @@ function renderAstNode(data, options, sourcemap, position, errors, reducer, cach
200
207
  });
201
208
  return '';
202
209
  }
203
- str = `${node.nam}:${options.indent}${node.val.reduce(reducer, '').trimEnd()};`;
210
+ str = `${node.nam}:${options.indent}${(options.minify ? filterValues(node.val) : node.val).reduce(reducer, '').trimEnd()};`;
204
211
  }
205
212
  else if (node.typ == EnumToken.AtRuleNodeType && !('chi' in node)) {
206
213
  str = `${data.val === '' ? '' : options.indent || ' '}${data.val};`;
@@ -222,10 +229,11 @@ function renderAstNode(data, options, sourcemap, position, errors, reducer, cach
222
229
  if (children.endsWith(';')) {
223
230
  children = children.slice(0, -1);
224
231
  }
225
- if (data.typ == EnumToken.AtRuleNodeType) {
232
+ if ([EnumToken.AtRuleNodeType, EnumToken.KeyframeAtRuleNodeType].includes(data.typ)) {
226
233
  return `@${data.nam}${data.val === '' ? '' : options.indent || ' '}${data.val}${options.indent}{${options.newLine}` + (children === '' ? '' : indentSub + children + options.newLine) + indent + `}`;
227
234
  }
228
235
  return data.sel + `${options.indent}{${options.newLine}` + (children === '' ? '' : indentSub + children + options.newLine) + indent + `}`;
236
+ case EnumToken.InvalidDeclarationNodeType:
229
237
  case EnumToken.InvalidRuleTokenType:
230
238
  case EnumToken.InvalidAtRuleTokenType:
231
239
  return '';
@@ -258,20 +266,25 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
258
266
  if (isColor(token)) {
259
267
  // @ts-ignore
260
268
  token.typ = EnumToken.ColorTokenType;
269
+ // @ts-ignore
261
270
  if (token.chi[0].typ == EnumToken.IdenTokenType && token.chi[0].val == 'from') {
262
271
  // @ts-ignore
263
272
  token.cal = 'rel';
264
273
  }
265
- else if (token.val == 'color-mix' && token.chi[0].typ == EnumToken.IdenTokenType && token.chi[0].val == 'in') {
266
- // @ts-ignore
267
- token.cal = 'mix';
268
- }
269
- else {
270
- if (token.val == 'color') {
274
+ else { // @ts-ignore
275
+ if (token.val == 'color-mix' && token.chi[0].typ == EnumToken.IdenTokenType && token.chi[0].val == 'in') {
276
+ // @ts-ignore
277
+ token.cal = 'mix';
278
+ }
279
+ else {
280
+ // @ts-ignore
281
+ if (token.val == 'color') {
282
+ // @ts-ignore
283
+ token.cal = 'col';
284
+ }
271
285
  // @ts-ignore
272
- token.cal = 'col';
286
+ token.chi = token.chi.filter((t) => ![EnumToken.WhitespaceTokenType, EnumToken.CommaTokenType, EnumToken.CommentTokenType].includes(t.typ));
273
287
  }
274
- token.chi = token.chi.filter((t) => ![EnumToken.WhitespaceTokenType, EnumToken.CommaTokenType, EnumToken.CommentTokenType].includes(t.typ));
275
288
  }
276
289
  }
277
290
  }
@@ -318,7 +331,7 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
318
331
  case EnumToken.Div:
319
332
  return '/';
320
333
  case EnumToken.ColorTokenType:
321
- if (token.kin == 'light-dark') {
334
+ if (token.kin == ColorKind.LIGHT_DARK || ('chi' in token && !options.convertColor)) {
322
335
  return token.val + '(' + token.chi.reduce((acc, curr) => acc + renderToken(curr, options, cache), '') + ')';
323
336
  }
324
337
  if (options.convertColor) {
@@ -328,7 +341,7 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
328
341
  acc.push([t]);
329
342
  }
330
343
  else {
331
- if (![EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType].includes(t.typ)) {
344
+ if (![EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType, EnumToken.CommaTokenType].includes(t.typ)) {
332
345
  acc[acc.length - 1].push(t);
333
346
  }
334
347
  }
@@ -338,22 +351,36 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
338
351
  if (value != null) {
339
352
  token = value;
340
353
  }
354
+ else if (!token.chi.some(t => t.typ == EnumToken.CommaTokenType)) {
355
+ token.chi = children.reduce((acc, curr, index) => {
356
+ if (acc.length > 0) {
357
+ acc.push({ typ: EnumToken.CommaTokenType });
358
+ }
359
+ acc.push(...curr);
360
+ return acc;
361
+ }, []);
362
+ }
341
363
  }
342
364
  if (token.cal == 'rel' && ['rgb', 'hsl', 'hwb', 'lab', 'lch', 'oklab', 'oklch', 'color'].includes(token.val)) {
343
365
  const chi = getComponents(token);
344
366
  const offset = token.val == 'color' ? 2 : 1;
345
- // @ts-ignore
346
- const color = chi[1];
347
- const components = parseRelativeColor(token.val == 'color' ? chi[offset].val : token.val, color, chi[offset + 1], chi[offset + 2], chi[offset + 3], chi[offset + 4]);
348
- if (components != null) {
349
- token.chi = [...(token.val == 'color' ? [chi[offset]] : []), ...Object.values(components)];
350
- delete token.cal;
367
+ if (chi != null) {
368
+ // @ts-ignore
369
+ const color = chi[1];
370
+ const components = parseRelativeColor(token.val == 'color' ? chi[offset].val : token.val, color, chi[offset + 1], chi[offset + 2], chi[offset + 3], chi[offset + 4]);
371
+ if (components != null) {
372
+ token.chi = [...(token.val == 'color' ? [chi[offset]] : []), ...Object.values(components)];
373
+ delete token.cal;
374
+ }
351
375
  }
352
376
  }
353
377
  if (token.val == 'color') {
354
378
  if (token.chi[0].typ == EnumToken.IdenTokenType && colorFuncColorSpace.includes(token.chi[0].val.toLowerCase())) {
355
- // @ts-ignore
356
- return reduceHexValue(srgb2hexvalues(...color2srgbvalues(token)));
379
+ const values = color2srgbvalues(token);
380
+ if (Array.isArray(values) && values.every(t => !Number.isNaN(t))) {
381
+ // @ts-ignore
382
+ return reduceHexValue(srgb2hexvalues(...values));
383
+ }
357
384
  }
358
385
  }
359
386
  if (token.cal != null) {
@@ -369,23 +396,45 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
369
396
  }
370
397
  return clamp(token).val + '(' + (slice ? token.chi.slice(0, -2) : token.chi).reduce((acc, curr) => {
371
398
  const val = renderToken(curr, options, cache);
372
- if ([EnumToken.LiteralTokenType, EnumToken.CommaTokenType].includes(curr.typ)) {
373
- return acc + val;
399
+ if (curr.typ == EnumToken.LiteralTokenType && curr.val == '/') {
400
+ return acc.trimEnd() + '/';
401
+ }
402
+ if (curr.typ == EnumToken.CommaTokenType) {
403
+ return acc.trimEnd() + ',';
404
+ }
405
+ if (curr.typ == EnumToken.WhitespaceTokenType) {
406
+ const v = acc.at(-1);
407
+ if (v == ' ' || v == ',' || v == '/') {
408
+ return acc.trimEnd();
409
+ }
410
+ return acc.trimEnd() + ' ';
374
411
  }
375
412
  if (acc.length > 0) {
376
- return acc + (['/', ','].includes(acc.at(-1)) ? '' : ' ') + val;
413
+ return acc + (['/', ',', ' '].includes(acc.at(-1)) ? '' : ' ') + val;
377
414
  }
378
415
  return val;
379
416
  }, '') + ')';
380
417
  }
381
- if (token.kin == 'lit' && token.val.localeCompare('currentcolor', undefined, { sensitivity: 'base' }) == 0) {
418
+ if (token.kin == ColorKind.LIT && token.val.localeCompare('currentcolor', undefined, { sensitivity: 'base' }) == 0) {
382
419
  return 'currentcolor';
383
420
  }
384
421
  clamp(token);
385
422
  if (Array.isArray(token.chi) && token.chi.some((t) => t.typ == EnumToken.FunctionTokenType || (t.typ == EnumToken.ColorTokenType && Array.isArray(t.chi)))) {
386
- return (token.val.endsWith('a') ? token.val.slice(0, -1) : token.val) + '(' + token.chi.reduce((acc, curr) => acc + (acc.length > 0 && !(acc.endsWith('/') || curr.typ == EnumToken.LiteralTokenType) ? ' ' : '') + renderToken(curr, options, cache), '') + ')';
423
+ const replaceSemiColon = /^((rgba?)|(hsla?)|(hwb)|((ok)?lab)|((ok)?lch))$/i.test(token.val);
424
+ return (token.val.endsWith('a') ? token.val.slice(0, -1) : token.val) + '(' + token.chi.reduce((acc, curr, index, array) => {
425
+ if (curr.typ == EnumToken.Literal && curr.val == '/') {
426
+ return acc.trimEnd() + '/';
427
+ }
428
+ if (curr.typ == EnumToken.CommaTokenType) {
429
+ return acc.trimEnd() + (replaceSemiColon ? ' ' : ',');
430
+ }
431
+ if (curr.typ == EnumToken.WhitespaceTokenType) {
432
+ return /[,\/\s]/.test(acc.at(-1)) ? acc.trimEnd() : acc.trimEnd() + ' ';
433
+ }
434
+ return acc + renderToken(curr, options, cache);
435
+ }, '') + ')';
387
436
  }
388
- let value = token.kin == 'hex' ? token.val.toLowerCase() : (token.kin == 'lit' ? COLORS_NAMES[token.val.toLowerCase()] : '');
437
+ let value = token.kin == ColorKind.HEX ? token.val.toLowerCase() : (token.kin == ColorKind.LIT ? COLORS_NAMES[token.val.toLowerCase()] : '');
389
438
  if (token.val == 'rgb' || token.val == 'rgba') {
390
439
  value = rgb2hex(token);
391
440
  }
@@ -410,11 +459,11 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
410
459
  else if (token.val == 'lch') {
411
460
  value = lch2hex(token);
412
461
  }
413
- if (value !== '') {
462
+ if (value !== '' && value != null) {
414
463
  return reduceHexValue(value);
415
464
  }
416
465
  }
417
- if (['hex', 'lit', 'sys', 'dpsys'].includes(token.kin)) {
466
+ if ([ColorKind.HEX, ColorKind.LIT, ColorKind.SYS, ColorKind.DPSYS].includes(token.kin)) {
418
467
  return token.val;
419
468
  }
420
469
  if (Array.isArray(token.chi)) {
@@ -434,9 +483,8 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
434
483
  ![EnumToken.BinaryExpressionTokenType, EnumToken.FractionTokenType, EnumToken.IdenTokenType].includes(token.chi[0].typ) &&
435
484
  // @ts-ignore
436
485
  token.chi[0].val?.typ != EnumToken.FractionTokenType) {
437
- return token.chi.reduce((acc, curr) => acc + renderToken(curr, options, cache, reducer), '');
486
+ return token.val + '(' + token.chi.reduce((acc, curr) => acc + renderToken(curr, options, cache, reducer), '') + ')';
438
487
  }
439
- // @ts-ignore
440
488
  return ( /* options.minify && 'Pseudo-class-func' == token.typ && token.val.slice(0, 2) == '::' ? token.val.slice(1) :*/token.val ?? '') + '(' + token.chi.reduce(reducer, '') + ')';
441
489
  case EnumToken.MatchExpressionTokenType:
442
490
  return renderToken(token.l, options, cache, reducer, errors) +
@@ -576,6 +624,9 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
576
624
  }
577
625
  return val + 's';
578
626
  }
627
+ if (token.typ == EnumToken.ResolutionTokenType && unit == 'dppx') {
628
+ unit = 'x';
629
+ }
579
630
  return val.includes('/') ? val.replace('/', unit + '/') : val + unit;
580
631
  case EnumToken.FlexTokenType:
581
632
  case EnumToken.PercentageTokenType:
@@ -600,7 +651,11 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
600
651
  if (!('original' in token)) {
601
652
  // do not modify original token
602
653
  token = { ...token };
603
- Object.defineProperty(token, 'original', { enumerable: false, writable: false, value: token.val });
654
+ Object.defineProperty(token, 'original', {
655
+ enumerable: false,
656
+ writable: false,
657
+ value: token.val
658
+ });
604
659
  }
605
660
  // @ts-ignore
606
661
  if (!(token.original in cache)) {
@@ -633,7 +688,7 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
633
688
  case EnumToken.InvalidClassSelectorTokenType:
634
689
  return token.val;
635
690
  case EnumToken.DeclarationNodeType:
636
- return token.nam + ':' + token.val.reduce((acc, curr) => acc + renderToken(curr, options, cache), '');
691
+ return token.nam + ':' + (options.minify ? filterValues(token.val) : token.val).reduce((acc, curr) => acc + renderToken(curr, options, cache), '');
637
692
  case EnumToken.MediaQueryConditionTokenType:
638
693
  return renderToken(token.l, options, cache, reducer, errors) + renderToken(token.op, options, cache, reducer, errors) + token.r.reduce((acc, curr) => acc + renderToken(curr, options, cache), '');
639
694
  case EnumToken.MediaFeatureTokenType:
@@ -646,11 +701,21 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer,
646
701
  return 'and';
647
702
  case EnumToken.MediaFeatureOrTokenType:
648
703
  return 'or';
649
- default:
650
- throw new Error(`render: unexpected token ${JSON.stringify(token, null, 1)}`);
651
704
  }
652
705
  errors?.push({ action: 'ignore', message: `render: unexpected token ${JSON.stringify(token, null, 1)}` });
653
706
  return '';
654
707
  }
708
+ function filterValues(values) {
709
+ let i = 0;
710
+ for (; i < values.length; i++) {
711
+ if (values[i].typ == EnumToken.ImportantTokenType && values[i - 1]?.typ == EnumToken.WhitespaceTokenType) {
712
+ values.splice(i - 1, 1);
713
+ }
714
+ else if (funcLike.includes(values[i].typ) && !['var', 'calc'].includes(values[i].val) && values[i + 1]?.typ == EnumToken.WhitespaceTokenType) {
715
+ values.splice(i + 1, 1);
716
+ }
717
+ }
718
+ return values;
719
+ }
655
720
 
656
- export { colorsFunc, doRender, reduceNumber, renderToken };
721
+ export { doRender, filterValues, reduceNumber, renderToken };