@tbela99/css-parser 1.0.0 → 1.1.1-alpha4

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 (87) hide show
  1. package/CHANGELOG.md +269 -0
  2. package/README.md +16 -11
  3. package/dist/index-umd-web.js +3805 -1894
  4. package/dist/index.cjs +3806 -1895
  5. package/dist/index.d.ts +184 -57
  6. package/dist/lib/ast/expand.js +2 -1
  7. package/dist/lib/ast/features/calc.js +12 -1
  8. package/dist/lib/ast/features/inlinecssvariables.js +47 -24
  9. package/dist/lib/ast/features/prefix.js +117 -86
  10. package/dist/lib/ast/features/shorthand.js +29 -6
  11. package/dist/lib/ast/features/transform.js +10 -3
  12. package/dist/lib/ast/features/type.js +7 -0
  13. package/dist/lib/ast/math/expression.js +7 -1
  14. package/dist/lib/ast/math/math.js +6 -0
  15. package/dist/lib/ast/minify.js +165 -77
  16. package/dist/lib/ast/transform/compute.js +1 -0
  17. package/dist/lib/ast/transform/matrix.js +1 -0
  18. package/dist/lib/ast/types.js +26 -15
  19. package/dist/lib/ast/utils/utils.js +104 -0
  20. package/dist/lib/ast/walk.js +33 -7
  21. package/dist/lib/fs/resolve.js +10 -0
  22. package/dist/lib/parser/declaration/list.js +48 -45
  23. package/dist/lib/parser/declaration/map.js +1 -0
  24. package/dist/lib/parser/declaration/set.js +2 -1
  25. package/dist/lib/parser/parse.js +350 -279
  26. package/dist/lib/parser/tokenize.js +147 -72
  27. package/dist/lib/parser/utils/declaration.js +4 -3
  28. package/dist/lib/parser/utils/type.js +2 -1
  29. package/dist/lib/renderer/color/a98rgb.js +2 -1
  30. package/dist/lib/renderer/color/color-mix.js +10 -7
  31. package/dist/lib/renderer/color/color.js +171 -153
  32. package/dist/lib/renderer/color/hex.js +2 -1
  33. package/dist/lib/renderer/color/hsl.js +2 -1
  34. package/dist/lib/renderer/color/hwb.js +2 -1
  35. package/dist/lib/renderer/color/lab.js +2 -1
  36. package/dist/lib/renderer/color/lch.js +2 -1
  37. package/dist/lib/renderer/color/oklab.js +2 -1
  38. package/dist/lib/renderer/color/oklch.js +2 -1
  39. package/dist/lib/renderer/color/p3.js +2 -1
  40. package/dist/lib/renderer/color/rec2020.js +2 -1
  41. package/dist/lib/renderer/color/relativecolor.js +17 -11
  42. package/dist/lib/renderer/color/rgb.js +4 -3
  43. package/dist/lib/renderer/color/srgb.js +18 -17
  44. package/dist/lib/renderer/color/utils/components.js +6 -5
  45. package/dist/lib/renderer/color/utils/constants.js +47 -3
  46. package/dist/lib/renderer/color/xyz.js +2 -1
  47. package/dist/lib/renderer/color/xyzd50.js +2 -1
  48. package/dist/lib/renderer/render.js +48 -20
  49. package/dist/lib/syntax/syntax.js +257 -140
  50. package/dist/lib/validation/at-rules/container.js +75 -97
  51. package/dist/lib/validation/at-rules/counter-style.js +9 -8
  52. package/dist/lib/validation/at-rules/custom-media.js +13 -15
  53. package/dist/lib/validation/at-rules/document.js +22 -27
  54. package/dist/lib/validation/at-rules/font-feature-values.js +8 -8
  55. package/dist/lib/validation/at-rules/import.js +30 -81
  56. package/dist/lib/validation/at-rules/keyframes.js +18 -22
  57. package/dist/lib/validation/at-rules/layer.js +5 -5
  58. package/dist/lib/validation/at-rules/media.js +42 -52
  59. package/dist/lib/validation/at-rules/namespace.js +19 -23
  60. package/dist/lib/validation/at-rules/page-margin-box.js +15 -18
  61. package/dist/lib/validation/at-rules/page.js +8 -7
  62. package/dist/lib/validation/at-rules/supports.js +73 -82
  63. package/dist/lib/validation/at-rules/when.js +32 -36
  64. package/dist/lib/validation/atrule.js +15 -14
  65. package/dist/lib/validation/config.js +24 -1
  66. package/dist/lib/validation/config.json.js +611 -111
  67. package/dist/lib/validation/parser/parse.js +206 -212
  68. package/dist/lib/validation/parser/types.js +1 -1
  69. package/dist/lib/validation/selector.js +3 -3
  70. package/dist/lib/validation/syntax.js +984 -0
  71. package/dist/lib/validation/syntaxes/complex-selector-list.js +10 -11
  72. package/dist/lib/validation/syntaxes/complex-selector.js +10 -11
  73. package/dist/lib/validation/syntaxes/compound-selector.js +40 -50
  74. package/dist/lib/validation/syntaxes/family-name.js +9 -8
  75. package/dist/lib/validation/syntaxes/keyframe-block-list.js +4 -3
  76. package/dist/lib/validation/syntaxes/keyframe-selector.js +15 -18
  77. package/dist/lib/validation/syntaxes/layer-name.js +6 -5
  78. package/dist/lib/validation/syntaxes/relative-selector-list.js +7 -6
  79. package/dist/lib/validation/syntaxes/relative-selector.js +2 -1
  80. package/dist/lib/validation/syntaxes/url.js +18 -22
  81. package/dist/lib/validation/utils/list.js +2 -1
  82. package/dist/lib/validation/utils/whitespace.js +2 -1
  83. package/dist/node/index.js +4 -2
  84. package/dist/node/load.js +5 -0
  85. package/dist/web/index.js +4 -2
  86. package/dist/web/load.js +5 -0
  87. package/package.json +14 -13
@@ -1,20 +1,23 @@
1
- import { webkitPseudoAliasMap, isIdentStart, isIdent, mathFuncs, isColor, isHexColor, isPseudo, pseudoElements, isAtKeyword, isFunction, isNumber, isPercentage, isFlex, isDimension, parseDimension, isHash, mediaTypes } from '../syntax/syntax.js';
1
+ import { isColor, parseColor, isIdent, mediaTypes, isDimension, parseDimension, isPseudo, pseudoElements, isAtKeyword, isFunction, isNumber, isPercentage, isFlex, isHexColor, isHash, isIdentStart, isIdentColor, mathFuncs } from '../syntax/syntax.js';
2
2
  import './utils/config.js';
3
- import { EnumToken, funcLike, ValidationLevel } from '../ast/types.js';
3
+ import { EnumToken, ValidationLevel, SyntaxValidationResult } from '../ast/types.js';
4
4
  import { minify, definedPropertySettings, combinators } from '../ast/minify.js';
5
5
  import { walkValues, walk, WalkerOptionEnum } from '../ast/walk.js';
6
6
  import { expand } from '../ast/expand.js';
7
7
  import { parseDeclarationNode } from './utils/declaration.js';
8
8
  import { renderToken } from '../renderer/render.js';
9
- import { COLORS_NAMES, systemColors, deprecatedSystemColors } from '../renderer/color/utils/constants.js';
9
+ import { funcLike, ColorKind, COLORS_NAMES, systemColors, deprecatedSystemColors, colorsFunc } from '../renderer/color/utils/constants.js';
10
+ import { buildExpression } from '../ast/math/expression.js';
10
11
  import { tokenize } from './tokenize.js';
11
12
  import '../validation/config.js';
12
13
  import '../validation/parser/types.js';
13
14
  import '../validation/parser/parse.js';
14
15
  import { validateSelector } from '../validation/selector.js';
15
16
  import { validateAtRule } from '../validation/atrule.js';
17
+ import { splitTokenList } from '../validation/utils/list.js';
16
18
  import '../validation/syntaxes/complex-selector.js';
17
19
  import { validateKeyframeSelector } from '../validation/syntaxes/keyframe-selector.js';
20
+ import { evaluateSyntax } from '../validation/syntax.js';
18
21
  import { validateAtRuleKeyframes } from '../validation/at-rules/keyframes.js';
19
22
 
20
23
  const urlTokenMatcher = /^(["']?)[a-zA-Z0-9_/.-][a-zA-Z0-9_/:.#?-]+(\1)$/;
@@ -62,10 +65,13 @@ async function doParse(iterator, options = {}) {
62
65
  inlineCssVariables: false,
63
66
  setParent: true,
64
67
  removePrefix: false,
65
- validation: true,
68
+ validation: ValidationLevel.Default,
66
69
  lenient: true,
67
70
  ...options
68
71
  };
72
+ if (typeof options.validation == 'boolean') {
73
+ options.validation = options.validation ? ValidationLevel.All : ValidationLevel.None;
74
+ }
69
75
  if (options.expandNestingRules) {
70
76
  options.nestingRules = false;
71
77
  }
@@ -77,11 +83,13 @@ async function doParse(iterator, options = {}) {
77
83
  const src = options.src;
78
84
  const stack = [];
79
85
  const stats = {
86
+ src: options.src ?? '',
80
87
  bytesIn: 0,
81
88
  importedBytesIn: 0,
82
89
  parse: `0ms`,
83
90
  minify: `0ms`,
84
- total: `0ms`
91
+ total: `0ms`,
92
+ imports: []
85
93
  };
86
94
  let ast = {
87
95
  typ: EnumToken.StyleSheetNodeType,
@@ -97,16 +105,22 @@ async function doParse(iterator, options = {}) {
97
105
  lin: 1,
98
106
  col: 1
99
107
  },
108
+ end: {
109
+ ind: 0,
110
+ lin: 1,
111
+ col: 1
112
+ },
100
113
  src: ''
101
114
  };
102
115
  }
103
116
  const iter = tokenize(iterator);
104
117
  let item;
118
+ let node;
105
119
  const rawTokens = [];
120
+ const imports = [];
106
121
  while (item = iter.next().value) {
107
122
  stats.bytesIn = item.bytesIn;
108
123
  rawTokens.push(item);
109
- // doParse error
110
124
  if (item.hint != null && BadTokensTypes.includes(item.hint)) {
111
125
  // bad token
112
126
  continue;
@@ -114,14 +128,23 @@ async function doParse(iterator, options = {}) {
114
128
  if (item.hint != EnumToken.EOFTokenType) {
115
129
  tokens.push(item);
116
130
  }
131
+ else if (ast.loc != null) {
132
+ for (let i = stack.length - 1; i >= 0; i--) {
133
+ stack[i].loc.end = { ...item.end };
134
+ }
135
+ ast.loc.end = item.end;
136
+ }
117
137
  if (item.token == ';' || item.token == '{') {
118
- let node = await parseNode(tokens, context, stats, options, errors, src, map, rawTokens);
138
+ node = parseNode(tokens, context, options, errors, src, map, rawTokens);
119
139
  rawTokens.length = 0;
120
140
  if (node != null) {
121
- // @ts-ignore
122
- stack.push(node);
123
- // @ts-ignore
124
- context = node;
141
+ if ('chi' in node) {
142
+ stack.push(node);
143
+ context = node;
144
+ }
145
+ else if (node.typ == EnumToken.AtRuleNodeType && node.nam == 'import') {
146
+ imports.push(node);
147
+ }
125
148
  }
126
149
  else if (item.token == '{') {
127
150
  let inBlock = 1;
@@ -151,23 +174,20 @@ async function doParse(iterator, options = {}) {
151
174
  map = new Map;
152
175
  }
153
176
  else if (item.token == '}') {
154
- await parseNode(tokens, context, stats, options, errors, src, map, rawTokens);
177
+ parseNode(tokens, context, options, errors, src, map, rawTokens);
155
178
  rawTokens.length = 0;
179
+ if (context.loc != null) {
180
+ context.loc.end = item.end;
181
+ }
156
182
  const previousNode = stack.pop();
157
- // @ts-ignore
158
- context = stack[stack.length - 1] ?? ast;
159
- // @ts-ignore
183
+ context = (stack[stack.length - 1] ?? ast);
160
184
  if (previousNode != null && previousNode.typ == EnumToken.InvalidRuleTokenType) {
161
- // @ts-ignore
162
185
  const index = context.chi.findIndex(node => node == previousNode);
163
186
  if (index > -1) {
164
- // @ts-ignore
165
187
  context.chi.splice(index, 1);
166
188
  }
167
189
  }
168
- // @ts-ignore
169
190
  if (options.removeEmpty && previousNode != null && previousNode.chi.length == 0 && context.chi[context.chi.length - 1] == previousNode) {
170
- // @ts-ignore
171
191
  context.chi.pop();
172
192
  }
173
193
  tokens = [];
@@ -175,8 +195,17 @@ async function doParse(iterator, options = {}) {
175
195
  }
176
196
  }
177
197
  if (tokens.length > 0) {
178
- await parseNode(tokens, context, stats, options, errors, src, map, rawTokens);
198
+ node = parseNode(tokens, context, options, errors, src, map, rawTokens);
179
199
  rawTokens.length = 0;
200
+ if (node != null) {
201
+ if (node.typ == EnumToken.AtRuleNodeType && node.nam == 'import') {
202
+ imports.push(node);
203
+ }
204
+ else if ('chi' in node && node.typ != EnumToken.InvalidRuleTokenType) {
205
+ stack.push(node);
206
+ context = node;
207
+ }
208
+ }
180
209
  if (context != null && context.typ == EnumToken.InvalidRuleTokenType) {
181
210
  // @ts-ignore
182
211
  const index = context.chi.findIndex((node) => node == context);
@@ -185,14 +214,37 @@ async function doParse(iterator, options = {}) {
185
214
  }
186
215
  }
187
216
  }
217
+ if (imports.length > 0 && options.resolveImport) {
218
+ await Promise.all(imports.map(async (node) => {
219
+ const token = node.tokens[0];
220
+ const url = token.typ == EnumToken.StringTokenType ? token.val.slice(1, -1) : token.val;
221
+ try {
222
+ const root = await options.load(url, options.src).then((src) => {
223
+ return doParse(src, Object.assign({}, options, {
224
+ minify: false,
225
+ setParent: false,
226
+ src: options.resolve(url, options.src).absolute
227
+ }));
228
+ });
229
+ stats.importedBytesIn += root.stats.bytesIn;
230
+ stats.imports.push(root.stats);
231
+ node.parent.chi.splice(node.parent.chi.indexOf(node), 1, ...root.ast.chi);
232
+ if (root.errors.length > 0) {
233
+ errors.push(...root.errors);
234
+ }
235
+ }
236
+ catch (error) {
237
+ // console.error(error);
238
+ // @ts-ignore
239
+ errors.push({ action: 'ignore', message: 'doParse: ' + error.message, error });
240
+ }
241
+ }));
242
+ }
188
243
  while (stack.length > 0 && context != ast) {
189
244
  const previousNode = stack.pop();
190
- // @ts-ignore
191
- context = stack[stack.length - 1] ?? ast;
245
+ context = (stack[stack.length - 1] ?? ast);
192
246
  // remove empty nodes
193
- // @ts-ignore
194
247
  if (options.removeEmpty && previousNode != null && previousNode.chi.length == 0 && context.chi[context.chi.length - 1] == previousNode) {
195
- // @ts-ignore
196
248
  context.chi.pop();
197
249
  continue;
198
250
  }
@@ -205,14 +257,12 @@ async function doParse(iterator, options = {}) {
205
257
  if (options.visitor != null) {
206
258
  for (const result of walk(ast)) {
207
259
  if (result.node.typ == EnumToken.DeclarationNodeType &&
208
- // @ts-ignore
209
260
  (typeof options.visitor.Declaration == 'function' || options.visitor.Declaration?.[result.node.nam] != null)) {
210
261
  const callable = typeof options.visitor.Declaration == 'function' ? options.visitor.Declaration : options.visitor.Declaration[result.node.nam];
211
262
  const results = await callable(result.node);
212
263
  if (results == null || (Array.isArray(results) && results.length == 0)) {
213
264
  continue;
214
265
  }
215
- // @ts-ignore
216
266
  result.parent.chi.splice(result.parent.chi.indexOf(result.node), 1, ...(Array.isArray(results) ? results : [results]));
217
267
  }
218
268
  else if (options.visitor.Rule != null && result.node.typ == EnumToken.RuleNodeType) {
@@ -220,7 +270,6 @@ async function doParse(iterator, options = {}) {
220
270
  if (results == null || (Array.isArray(results) && results.length == 0)) {
221
271
  continue;
222
272
  }
223
- // @ts-ignore
224
273
  result.parent.chi.splice(result.parent.chi.indexOf(result.node), 1, ...(Array.isArray(results) ? results : [results]));
225
274
  }
226
275
  else if (options.visitor.AtRule != null &&
@@ -232,7 +281,6 @@ async function doParse(iterator, options = {}) {
232
281
  if (results == null || (Array.isArray(results) && results.length == 0)) {
233
282
  continue;
234
283
  }
235
- // @ts-ignore
236
284
  result.parent.chi.splice(result.parent.chi.indexOf(result.node), 1, ...(Array.isArray(results) ? results : [results]));
237
285
  }
238
286
  }
@@ -271,30 +319,27 @@ function getLastNode(context) {
271
319
  }
272
320
  return null;
273
321
  }
274
- async function parseNode(results, context, stats, options, errors, src, map, rawTokens) {
322
+ function parseNode(results, context, options, errors, src, map, rawTokens) {
275
323
  let tokens = [];
276
324
  for (const t of results) {
277
325
  const node = getTokenType(t.token, t.hint);
278
- map.set(node, t.position);
326
+ map.set(node, { sta: t.sta, end: t.end, src });
279
327
  tokens.push(node);
280
328
  }
281
329
  let i;
282
330
  let loc;
283
331
  for (i = 0; i < tokens.length; i++) {
284
332
  if (tokens[i].typ == EnumToken.CommentTokenType || tokens[i].typ == EnumToken.CDOCOMMTokenType) {
285
- const position = map.get(tokens[i]);
333
+ const location = map.get(tokens[i]);
286
334
  if (tokens[i].typ == EnumToken.CDOCOMMTokenType && context.typ != EnumToken.StyleSheetNodeType) {
287
335
  errors.push({
288
336
  action: 'drop',
289
337
  message: `CDOCOMM not allowed here ${JSON.stringify(tokens[i], null, 1)}`,
290
- location: { src, ...position }
338
+ location
291
339
  });
292
340
  continue;
293
341
  }
294
- loc = {
295
- sta: position,
296
- src
297
- };
342
+ loc = location;
298
343
  // @ts-ignore
299
344
  context.chi.push(tokens[i]);
300
345
  if (options.sourcemap) {
@@ -313,10 +358,6 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
313
358
  if (delim.typ == EnumToken.SemiColonTokenType || delim.typ == EnumToken.BlockStartTokenType || delim.typ == EnumToken.BlockEndTokenType) {
314
359
  tokens.pop();
315
360
  }
316
- else {
317
- delim = { typ: EnumToken.SemiColonTokenType };
318
- }
319
- // @ts-ignore
320
361
  while ([EnumToken.WhitespaceTokenType, EnumToken.BadStringTokenType, EnumToken.BadCommentTokenType].includes(tokens.at(-1)?.typ)) {
321
362
  tokens.pop();
322
363
  }
@@ -325,11 +366,12 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
325
366
  }
326
367
  if (tokens[0]?.typ == EnumToken.AtRuleTokenType) {
327
368
  const atRule = tokens.shift();
328
- const position = map.get(atRule);
369
+ const location = map.get(atRule);
329
370
  // @ts-ignore
330
371
  while ([EnumToken.WhitespaceTokenType].includes(tokens[0]?.typ)) {
331
372
  tokens.shift();
332
373
  }
374
+ rawTokens.shift();
333
375
  if (atRule.val == 'import') {
334
376
  // only @charset and @layer are accepted before @import
335
377
  // @ts-ignore
@@ -347,14 +389,14 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
347
389
  if (!(type == EnumToken.InvalidAtRuleTokenType &&
348
390
  // @ts-ignore
349
391
  ['charset', 'layer', 'import'].includes(context.chi[i].nam))) {
350
- errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } });
392
+ errors.push({ action: 'drop', message: 'invalid @import', location });
351
393
  return null;
352
394
  }
353
395
  }
354
396
  // @ts-ignore
355
397
  const name = context.chi[i].nam;
356
398
  if (name != 'charset' && name != 'import' && name != 'layer') {
357
- errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } });
399
+ errors.push({ action: 'drop', message: 'invalid @import', location });
358
400
  return null;
359
401
  }
360
402
  break;
@@ -365,7 +407,7 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
365
407
  errors.push({
366
408
  action: 'drop',
367
409
  message: 'doParse: invalid @import',
368
- location: { src, ...position }
410
+ location
369
411
  });
370
412
  return null;
371
413
  }
@@ -374,7 +416,7 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
374
416
  errors.push({
375
417
  action: 'drop',
376
418
  message: 'doParse: invalid @import',
377
- location: { src, ...position }
419
+ location
378
420
  });
379
421
  return null;
380
422
  }
@@ -400,37 +442,6 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
400
442
  }
401
443
  }
402
444
  }
403
- // @ts-ignore
404
- if (tokens[0].typ == EnumToken.StringTokenType) {
405
- if (options.resolveImport) {
406
- const url = tokens[0].val.slice(1, -1);
407
- try {
408
- // @ts-ignore
409
- const root = await options.load(url, options.src).then((src) => {
410
- return doParse(src, Object.assign({}, options, {
411
- minify: false,
412
- setParent: false,
413
- // @ts-ignore
414
- src: options.resolve(url, options.src).absolute
415
- }));
416
- });
417
- stats.importedBytesIn += root.stats.bytesIn;
418
- if (root.ast.chi.length > 0) {
419
- // @todo - filter charset, layer and scope
420
- // @ts-ignore
421
- context.chi.push(...root.ast.chi);
422
- }
423
- if (root.errors.length > 0) {
424
- errors.push(...root.errors);
425
- }
426
- return null;
427
- }
428
- catch (error) {
429
- // @ts-ignore
430
- errors.push({ action: 'ignore', message: 'doParse: ' + error.message, error });
431
- }
432
- }
433
- }
434
445
  }
435
446
  // https://www.w3.org/TR/css-nesting-1/#conditionals
436
447
  // allowed nesting at-rules
@@ -438,7 +449,7 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
438
449
  if (atRule.val == 'charset') {
439
450
  let spaces = 0;
440
451
  // https://developer.mozilla.org/en-US/docs/Web/CSS/@charset
441
- for (let k = 1; k < rawTokens.length; k++) {
452
+ for (let k = 0; k < rawTokens.length; k++) {
442
453
  if (rawTokens[k].hint == EnumToken.WhitespaceTokenType) {
443
454
  spaces += rawTokens[k].len;
444
455
  continue;
@@ -454,7 +465,7 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
454
465
  action: 'drop',
455
466
  message: '@charset must have only one space',
456
467
  // @ts-ignore
457
- location: { src, ...(map.get(atRule) ?? position) }
468
+ location
458
469
  });
459
470
  return null;
460
471
  }
@@ -462,8 +473,7 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
462
473
  errors.push({
463
474
  action: 'drop',
464
475
  message: '@charset expects a "<charset>"',
465
- // @ts-ignore
466
- location: { src, ...(map.get(atRule) ?? position) }
476
+ location
467
477
  });
468
478
  return null;
469
479
  }
@@ -483,94 +493,77 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
483
493
  const node = {
484
494
  typ: /^(-[a-z]+-)?keyframes$/.test(nam) ? EnumToken.KeyframeAtRuleNodeType : EnumToken.AtRuleNodeType,
485
495
  nam,
486
- // tokens: t,
487
496
  val: raw.join('')
488
497
  };
489
498
  Object.defineProperties(node, {
490
- tokens: { ...definedPropertySettings, enumerable: false, value: tokens.slice() },
499
+ tokens: { ...definedPropertySettings, enumerable: false, value: t.slice() },
491
500
  raw: { ...definedPropertySettings, value: raw }
492
501
  });
493
502
  if (delim.typ == EnumToken.BlockStartTokenType) {
494
503
  node.chi = [];
495
504
  }
496
- loc = {
497
- sta: position,
498
- src
499
- };
505
+ loc = map.get(atRule);
500
506
  if (options.sourcemap) {
501
507
  node.loc = loc;
508
+ node.loc.end = { ...map.get(delim).end };
502
509
  }
503
- if (options.validation) {
504
- let isValid = true;
505
- if (node.nam == 'else') {
506
- const prev = getLastNode(context);
507
- if (prev != null && prev.typ == EnumToken.AtRuleNodeType && ['when', 'else'].includes(prev.nam)) {
508
- if (prev.nam == 'else') {
509
- isValid = Array.isArray(prev.tokens) && prev.tokens.length > 0;
510
- }
511
- }
512
- else {
513
- isValid = false;
510
+ // if (options.validation) {
511
+ let isValid = true;
512
+ if (node.nam == 'else') {
513
+ const prev = getLastNode(context);
514
+ if (prev != null && prev.typ == EnumToken.AtRuleNodeType && ['when', 'else'].includes(prev.nam)) {
515
+ if (prev.nam == 'else') {
516
+ isValid = Array.isArray(prev.tokens) && prev.tokens.length > 0;
514
517
  }
515
518
  }
516
- const valid = isValid ? (node.typ == EnumToken.KeyframeAtRuleNodeType ? validateAtRuleKeyframes(node) : validateAtRule(node, options, context)) : {
517
- valid: ValidationLevel.Drop,
518
- node,
519
- syntax: '@' + node.nam,
520
- error: '@' + node.nam + ' not allowed here'};
521
- if (valid.valid == ValidationLevel.Drop) {
522
- errors.push({
523
- action: 'drop',
524
- message: valid.error + ' - "' + tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '') + '"',
525
- // @ts-ignore
526
- location: { src, ...(map.get(valid.node) ?? position) }
527
- });
528
- // @ts-ignore
529
- node.typ = EnumToken.InvalidAtRuleTokenType;
530
- }
531
519
  else {
532
- node.val = node.tokens.reduce((acc, curr) => acc + renderToken(curr, {
533
- minify: false,
534
- removeComments: true
535
- }), '');
520
+ isValid = false;
536
521
  }
537
522
  }
538
523
  // @ts-ignore
524
+ const valid = options.validation == ValidationLevel.None ? {
525
+ valid: SyntaxValidationResult.Valid,
526
+ error: '',
527
+ node,
528
+ syntax: '@' + node.nam
529
+ } : isValid ? (node.typ == EnumToken.KeyframeAtRuleNodeType ? validateAtRuleKeyframes(node) : validateAtRule(node, options, context)) : {
530
+ valid: SyntaxValidationResult.Drop,
531
+ node,
532
+ syntax: '@' + node.nam,
533
+ error: '@' + node.nam + ' not allowed here'};
534
+ if (valid.valid == SyntaxValidationResult.Drop) {
535
+ errors.push({
536
+ action: 'drop',
537
+ message: valid.error + ' - "' + tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '') + '"',
538
+ // @ts-ignore
539
+ location: { src, ...(map.get(valid.node) ?? location) }
540
+ });
541
+ // @ts-ignore
542
+ node.typ = EnumToken.InvalidAtRuleTokenType;
543
+ }
544
+ else {
545
+ node.val = node.tokens.reduce((acc, curr) => acc + renderToken(curr, {
546
+ minify: false,
547
+ removeComments: true
548
+ }), '');
549
+ }
539
550
  context.chi.push(node);
540
- Object.defineProperty(node, 'parent', { ...definedPropertySettings, value: context });
541
- return delim.typ == EnumToken.BlockStartTokenType ? node : null;
551
+ Object.defineProperties(node, {
552
+ parent: { ...definedPropertySettings, value: context },
553
+ validSyntax: { ...definedPropertySettings, value: valid.valid == SyntaxValidationResult.Valid }
554
+ });
555
+ return node;
542
556
  }
543
557
  else {
544
558
  // rule
545
559
  if (delim.typ == EnumToken.BlockStartTokenType) {
546
- const position = map.get(tokens[0]);
560
+ const location = map.get(tokens[0]);
547
561
  const uniq = new Map;
548
562
  parseTokens(tokens, { minify: true });
549
563
  const ruleType = context.typ == EnumToken.KeyframeAtRuleNodeType ? EnumToken.KeyFrameRuleNodeType : EnumToken.RuleNodeType;
550
564
  if (ruleType == EnumToken.RuleNodeType) {
551
565
  parseSelector(tokens);
552
566
  }
553
- if (options.validation) {
554
- // @ts-ignore
555
- const valid = ruleType == EnumToken.KeyFrameRuleNodeType ? validateKeyframeSelector(tokens) : validateSelector(tokens, options, context);
556
- if (valid.valid != ValidationLevel.Valid) {
557
- const node = {
558
- typ: EnumToken.InvalidRuleTokenType,
559
- sel: tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), ''),
560
- chi: []
561
- };
562
- errors.push({
563
- action: 'drop',
564
- message: valid.error + ' - "' + tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '') + '"',
565
- // @ts-ignore
566
- location: { src, ...(map.get(valid.node) ?? position) }
567
- });
568
- // @ts-ignore
569
- context.chi.push(node);
570
- Object.defineProperty(node, 'parent', { ...definedPropertySettings, value: context });
571
- return node;
572
- }
573
- }
574
567
  const node = {
575
568
  typ: ruleType,
576
569
  sel: [...tokens.reduce((acc, curr, index, array) => {
@@ -596,11 +589,9 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
596
589
  let t = renderToken(curr, { minify: false });
597
590
  if (t == ',') {
598
591
  acc.push([]);
599
- // uniqTokens.push([]);
600
592
  }
601
593
  else {
602
594
  acc[acc.length - 1].push(t);
603
- // uniqTokens[uniqTokens.length - 1].push(curr);
604
595
  }
605
596
  return acc;
606
597
  }, [[]]).reduce((acc, curr) => {
@@ -625,78 +616,107 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
625
616
  enumerable: false,
626
617
  value: tokens.slice()
627
618
  });
628
- let raw = [...uniq.values()];
629
- Object.defineProperty(node, 'raw', {
630
- enumerable: false,
631
- configurable: true,
632
- writable: true,
633
- value: raw
634
- });
635
- loc = {
636
- sta: position,
637
- src
638
- };
619
+ loc = location;
639
620
  if (options.sourcemap) {
640
621
  node.loc = loc;
641
622
  }
642
623
  // @ts-ignore
643
624
  context.chi.push(node);
644
625
  Object.defineProperty(node, 'parent', { ...definedPropertySettings, value: context });
626
+ // @ts-ignore
627
+ const valid = options.validation == ValidationLevel.None ? {
628
+ valid: SyntaxValidationResult.Valid,
629
+ error: null
630
+ } : ruleType == EnumToken.KeyFrameRuleNodeType ? validateKeyframeSelector(tokens) : validateSelector(tokens, options, context);
631
+ if (valid.valid != SyntaxValidationResult.Valid) {
632
+ // @ts-ignore
633
+ node.typ = EnumToken.InvalidRuleTokenType;
634
+ node.sel = tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '');
635
+ errors.push({
636
+ action: 'drop',
637
+ message: valid.error + ' - "' + tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '') + '"',
638
+ // @ts-ignore
639
+ location
640
+ });
641
+ }
642
+ Object.defineProperty(node, 'validSyntax', {
643
+ ...definedPropertySettings,
644
+ value: valid.valid == SyntaxValidationResult.Valid
645
+ });
645
646
  return node;
646
647
  }
647
648
  else {
648
649
  let name = null;
649
650
  let value = null;
650
- for (let i = 0; i < tokens.length; i++) {
651
+ let i = 0;
652
+ for (; i < tokens.length; i++) {
653
+ if (tokens[i].typ == EnumToken.LiteralTokenType && tokens[i].val.length > 1) {
654
+ const start = tokens[i].val.charAt(0);
655
+ const val = tokens[i].val.slice(1);
656
+ if (['/', '*'].includes(start) && isNumber(val)) {
657
+ tokens.splice(i, 1, {
658
+ typ: EnumToken.LiteralTokenType,
659
+ val: tokens[i].val.charAt(0)
660
+ }, {
661
+ typ: EnumToken.NumberTokenType,
662
+ val: tokens[i].val.slice(1)
663
+ });
664
+ }
665
+ else if (start == '/' && isFunction(val)) {
666
+ tokens.splice(i, 1, { typ: EnumToken.LiteralTokenType, val: '/' }, getTokenType(val));
667
+ }
668
+ }
669
+ }
670
+ parseTokens(tokens, { ...options, parseColor: true });
671
+ for (i = 0; i < tokens.length; i++) {
651
672
  if (tokens[i].typ == EnumToken.CommentTokenType) {
652
673
  continue;
653
674
  }
654
675
  if (name == null && [EnumToken.IdenTokenType, EnumToken.DashedIdenTokenType].includes(tokens[i].typ)) {
655
676
  name = tokens.slice(0, i + 1);
656
677
  }
678
+ else if (name == null && tokens[i].typ == EnumToken.ColorTokenType && [ColorKind.SYS, ColorKind.DPSYS].includes(tokens[i].kin)) {
679
+ name = tokens.slice(0, i + 1);
680
+ tokens[i].typ = EnumToken.IdenTokenType;
681
+ }
657
682
  else if (name != null && funcLike.concat([
658
683
  EnumToken.LiteralTokenType,
659
684
  EnumToken.IdenTokenType, EnumToken.DashedIdenTokenType,
660
685
  EnumToken.PseudoClassTokenType, EnumToken.PseudoClassFuncTokenType
661
686
  ]).includes(tokens[i].typ)) {
662
- if (tokens[i].val.charAt(0) == ':') {
687
+ if (tokens[i].val?.charAt?.(0) == ':') {
663
688
  Object.assign(tokens[i], getTokenType(tokens[i].val.slice(1)));
689
+ if ('chi' in tokens[i]) {
690
+ tokens[i].typ = EnumToken.FunctionTokenType;
691
+ if (colorsFunc.includes(tokens[i].val) && isColor(tokens[i])) {
692
+ parseColor(tokens[i]);
693
+ }
694
+ }
695
+ tokens.splice(i--, 0, { typ: EnumToken.ColonTokenType });
696
+ continue;
664
697
  }
665
698
  if ('chi' in tokens[i]) {
666
699
  tokens[i].typ = EnumToken.FunctionTokenType;
667
700
  }
668
- value = parseTokens(tokens.slice(i), {
669
- parseColor: options.parseColor,
670
- src: options.src,
671
- resolveUrls: options.resolveUrls,
672
- resolve: options.resolve,
673
- cwd: options.cwd
674
- });
675
- break;
701
+ value = tokens.slice(i);
676
702
  }
677
703
  if (tokens[i].typ == EnumToken.ColonTokenType) {
678
704
  name = tokens.slice(0, i);
679
- value = parseTokens(tokens.slice(i + 1), {
680
- parseColor: options.parseColor,
681
- src: options.src,
682
- resolveUrls: options.resolveUrls,
683
- resolve: options.resolve,
684
- cwd: options.cwd
685
- });
705
+ value = tokens.slice(i + 1);
686
706
  break;
687
707
  }
688
708
  }
689
709
  if (name == null) {
690
710
  name = tokens;
691
711
  }
692
- const position = map.get(name[0]);
712
+ const location = map.get(name[0]);
693
713
  if (name.length > 0) {
694
714
  for (let i = 1; i < name.length; i++) {
695
715
  if (name[i].typ != EnumToken.WhitespaceTokenType && name[i].typ != EnumToken.CommentTokenType) {
696
716
  errors.push({
697
717
  action: 'drop',
698
718
  message: 'doParse: invalid declaration',
699
- location: { src, ...position }
719
+ location
700
720
  });
701
721
  return null;
702
722
  }
@@ -707,8 +727,20 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
707
727
  errors.push({
708
728
  action: 'drop',
709
729
  message: 'doParse: invalid declaration',
710
- location: { src, ...position }
730
+ location
711
731
  });
732
+ if (options.lenient) {
733
+ const node = {
734
+ typ: EnumToken.InvalidDeclarationNodeType,
735
+ nam,
736
+ val: []
737
+ };
738
+ if (options.sourcemap) {
739
+ node.loc = location;
740
+ node.loc.end = { ...map.get(delim).end };
741
+ }
742
+ context.chi.push(node);
743
+ }
712
744
  return null;
713
745
  }
714
746
  for (const { value: token } of walkValues(value, null, {
@@ -728,16 +760,46 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
728
760
  }
729
761
  const node = {
730
762
  typ: EnumToken.DeclarationNodeType,
731
- // @ts-ignore
732
763
  nam,
733
- // @ts-ignore
734
764
  val: value
735
765
  };
736
- const result = parseDeclarationNode(node, errors, src, position);
737
- if (result != null) {
766
+ if (options.sourcemap) {
767
+ node.loc = location;
768
+ node.loc.end = { ...map.get(delim).end };
769
+ }
770
+ // do not allow declarations in style sheets
771
+ if (context.typ == EnumToken.StyleSheetNodeType && options.lenient) {
738
772
  // @ts-ignore
773
+ node.typ = EnumToken.InvalidDeclarationNodeType;
774
+ context.chi.push(node);
775
+ return null;
776
+ }
777
+ const result = parseDeclarationNode(node, errors, location);
778
+ Object.defineProperty(result, 'parent', { ...definedPropertySettings, value: context });
779
+ if (result != null) {
780
+ if (options.validation == ValidationLevel.All) {
781
+ const valid = evaluateSyntax(result, options);
782
+ Object.defineProperty(result, 'validSyntax', {
783
+ ...definedPropertySettings,
784
+ value: valid.valid == SyntaxValidationResult.Valid
785
+ });
786
+ if (valid.valid == SyntaxValidationResult.Drop) {
787
+ // console.error({result, valid});
788
+ // console.error(JSON.stringify({result, options, valid}, null, 1));
789
+ errors.push({
790
+ action: 'drop',
791
+ message: valid.error,
792
+ syntax: valid.syntax,
793
+ location: map.get(valid.node) ?? valid.node?.loc ?? result.loc ?? location
794
+ });
795
+ if (!options.lenient) {
796
+ return null;
797
+ }
798
+ // @ts-ignore
799
+ node.typ = EnumToken.InvalidDeclarationNodeType;
800
+ }
801
+ }
739
802
  context.chi.push(result);
740
- Object.defineProperty(result, 'parent', { ...definedPropertySettings, value: context });
741
803
  }
742
804
  return null;
743
805
  }
@@ -756,6 +818,33 @@ function parseAtRulePrelude(tokens, atRule) {
756
818
  value.typ == EnumToken.CommaTokenType) {
757
819
  continue;
758
820
  }
821
+ if (value.typ == EnumToken.PseudoClassFuncTokenType || value.typ == EnumToken.PseudoClassTokenType) {
822
+ if (parent?.typ == EnumToken.ParensTokenType) {
823
+ const index = parent.chi.indexOf(value);
824
+ let i = index;
825
+ while (i--) {
826
+ if (parent.chi[i].typ == EnumToken.IdenTokenType || parent.chi[i].typ == EnumToken.DashedIdenTokenType) {
827
+ break;
828
+ }
829
+ }
830
+ if (i >= 0) {
831
+ const token = getTokenType(parent.chi[index].val.slice(1) + (funcLike.includes(parent.chi[index].typ) ? '(' : ''));
832
+ parent.chi[index].val = token.val;
833
+ parent.chi[index].typ = token.typ;
834
+ if (parent.chi[index].typ == EnumToken.FunctionTokenType && isColor(parent.chi[index])) {
835
+ parseColor(parent.chi[index]);
836
+ }
837
+ parent.chi.splice(i, index - i + 1, {
838
+ typ: EnumToken.MediaQueryConditionTokenType,
839
+ l: parent.chi[i],
840
+ r: parent.chi.slice(index),
841
+ op: {
842
+ typ: EnumToken.ColonTokenType
843
+ }
844
+ });
845
+ }
846
+ }
847
+ }
759
848
  if (atRule.val == 'page' && value.typ == EnumToken.PseudoClassTokenType) {
760
849
  if ([':left', ':right', ':first', ':blank'].includes(value.val)) {
761
850
  // @ts-ignore
@@ -816,6 +905,9 @@ function parseAtRulePrelude(tokens, atRule) {
816
905
  continue;
817
906
  }
818
907
  }
908
+ if (value.typ == EnumToken.FunctionTokenType && value.val == 'selector') {
909
+ parseSelector(value.chi);
910
+ }
819
911
  if (value.typ == EnumToken.ParensTokenType || (value.typ == EnumToken.FunctionTokenType && ['media', 'supports', 'style', 'scroll-state'].includes(value.val))) {
820
912
  let i;
821
913
  let nameIndex = -1;
@@ -837,6 +929,23 @@ function parseAtRulePrelude(tokens, atRule) {
837
929
  if (value.chi[i].typ == EnumToken.CommentTokenType || value.chi[i].typ == EnumToken.WhitespaceTokenType) {
838
930
  continue;
839
931
  }
932
+ if (value.chi[i].typ == EnumToken.LiteralTokenType && value.chi[i].val.startsWith(':') && isDimension(value.chi[i].val.slice(1))) {
933
+ value.chi.splice(i, 1, {
934
+ typ: EnumToken.ColonTokenType,
935
+ }, Object.assign(value.chi[i], parseDimension(value.chi[i].val.slice(1))));
936
+ i--;
937
+ continue;
938
+ }
939
+ if (nameIndex != -1 && value.chi[i].typ == EnumToken.PseudoClassTokenType) {
940
+ value.chi.splice(i, 1, {
941
+ typ: EnumToken.ColonTokenType,
942
+ }, Object.assign(value.chi[i], {
943
+ typ: EnumToken.IdenTokenType,
944
+ val: value.chi[i].val.slice(1)
945
+ }));
946
+ i--;
947
+ continue;
948
+ }
840
949
  valueIndex = i;
841
950
  break;
842
951
  }
@@ -856,7 +965,7 @@ function parseAtRulePrelude(tokens, atRule) {
856
965
  const node = value.chi.splice(nameIndex, 1)[0];
857
966
  // 'background'
858
967
  // @ts-ignore
859
- if (node.typ == EnumToken.ColorTokenType && node.kin == 'dpsys') {
968
+ if (node.typ == EnumToken.ColorTokenType && node.kin == ColorKind.DPSYS) {
860
969
  // @ts-ignore
861
970
  delete node.kin;
862
971
  node.typ = EnumToken.IdenTokenType;
@@ -980,8 +1089,8 @@ function parseSelector(tokens) {
980
1089
  }
981
1090
  }
982
1091
  else if (value.typ == EnumToken.ColorTokenType) {
983
- if (value.kin == 'lit' || value.kin == 'hex' || value.kin == 'sys' || value.kin == 'dpsys') {
984
- if (value.kin == 'hex') {
1092
+ if (value.kin == ColorKind.LIT || value.kin == ColorKind.HEX || value.kin == ColorKind.SYS || value.kin == ColorKind.DPSYS) {
1093
+ if (value.kin == ColorKind.HEX) {
985
1094
  if (!isIdent(value.val.slice(1))) {
986
1095
  continue;
987
1096
  }
@@ -1026,64 +1135,54 @@ function parseSelector(tokens) {
1026
1135
  // return doParse(`.x{${src}`, options).then((result: ParseResult) => <AstDeclaration[]>(<AstRule>result.ast.chi[0]).chi.filter(t => t.typ == EnumToken.DeclarationNodeType));
1027
1136
  // }
1028
1137
  /**
1029
- * parse string
1138
+ * parse css string
1030
1139
  * @param src
1031
1140
  * @param options
1032
1141
  */
1033
1142
  function parseString(src, options = { location: false }) {
1034
- return parseTokens([...tokenize(src)].map(t => {
1143
+ return parseTokens([...tokenize(src)].reduce((acc, t) => {
1144
+ if (t.hint == EnumToken.EOFTokenType) {
1145
+ return acc;
1146
+ }
1035
1147
  const token = getTokenType(t.token, t.hint);
1036
1148
  if (options.location) {
1037
- Object.assign(token, { loc: t.position });
1149
+ Object.assign(token, { loc: t.sta });
1038
1150
  }
1039
- return token;
1040
- }));
1151
+ acc.push(token);
1152
+ return acc;
1153
+ }, []));
1041
1154
  }
1042
1155
  function getTokenType(val, hint) {
1043
1156
  if (hint != null) {
1044
1157
  return enumTokenHints.has(hint) ? { typ: hint } : { typ: hint, val };
1045
1158
  }
1046
- if (val == ' ') {
1047
- return { typ: EnumToken.WhitespaceTokenType };
1048
- }
1049
- if (val == ';') {
1050
- return { typ: EnumToken.SemiColonTokenType };
1051
- }
1052
- if (val == '{') {
1053
- return { typ: EnumToken.BlockStartTokenType };
1054
- }
1055
- if (val == '}') {
1056
- return { typ: EnumToken.BlockEndTokenType };
1057
- }
1058
- if (val == '[') {
1059
- return { typ: EnumToken.AttrStartTokenType };
1060
- }
1061
- if (val == ']') {
1062
- return { typ: EnumToken.AttrEndTokenType };
1063
- }
1064
- if (val == ':') {
1065
- return { typ: EnumToken.ColonTokenType };
1066
- }
1067
- if (val == ')') {
1068
- return { typ: EnumToken.EndParensTokenType };
1069
- }
1070
- if (val == '(') {
1071
- return { typ: EnumToken.StartParensTokenType };
1072
- }
1073
- if (val == '=') {
1074
- return { typ: EnumToken.DelimTokenType };
1075
- }
1076
- if (val == ';') {
1077
- return { typ: EnumToken.SemiColonTokenType };
1078
- }
1079
- if (val == ',') {
1080
- return { typ: EnumToken.CommaTokenType };
1081
- }
1082
- if (val == '<') {
1083
- return { typ: EnumToken.LtTokenType };
1084
- }
1085
- if (val == '>') {
1086
- return { typ: EnumToken.GtTokenType };
1159
+ switch (val) {
1160
+ case ' ':
1161
+ return { typ: EnumToken.WhitespaceTokenType };
1162
+ case ';':
1163
+ return { typ: EnumToken.SemiColonTokenType };
1164
+ case '{':
1165
+ return { typ: EnumToken.BlockStartTokenType };
1166
+ case '}':
1167
+ return { typ: EnumToken.BlockEndTokenType };
1168
+ case '[':
1169
+ return { typ: EnumToken.AttrStartTokenType };
1170
+ case ']':
1171
+ return { typ: EnumToken.AttrEndTokenType };
1172
+ case ':':
1173
+ return { typ: EnumToken.ColonTokenType };
1174
+ case ')':
1175
+ return { typ: EnumToken.EndParensTokenType };
1176
+ case '(':
1177
+ return { typ: EnumToken.StartParensTokenType };
1178
+ case '=':
1179
+ return { typ: EnumToken.DelimTokenType };
1180
+ case ',':
1181
+ return { typ: EnumToken.CommaTokenType };
1182
+ case '<':
1183
+ return { typ: EnumToken.LtTokenType };
1184
+ case '>':
1185
+ return { typ: EnumToken.GtTokenType };
1087
1186
  }
1088
1187
  if (isPseudo(val)) {
1089
1188
  return val.endsWith('(') ? {
@@ -1170,22 +1269,22 @@ function getTokenType(val, hint) {
1170
1269
  return {
1171
1270
  typ: EnumToken.ColorTokenType,
1172
1271
  val: v,
1173
- kin: 'lit'
1272
+ kin: ColorKind.LIT
1174
1273
  };
1175
1274
  }
1176
1275
  if (isIdent(val)) {
1177
- if (systemColors.has(val.toLowerCase())) {
1276
+ if (systemColors.has(v)) {
1178
1277
  return {
1179
1278
  typ: EnumToken.ColorTokenType,
1180
1279
  val,
1181
- kin: 'sys'
1280
+ kin: ColorKind.SYS
1182
1281
  };
1183
1282
  }
1184
- if (deprecatedSystemColors.has(val.toLowerCase())) {
1283
+ if (deprecatedSystemColors.has(v)) {
1185
1284
  return {
1186
1285
  typ: EnumToken.ColorTokenType,
1187
1286
  val,
1188
- kin: 'dpsys'
1287
+ kin: ColorKind.DPSYS
1189
1288
  };
1190
1289
  }
1191
1290
  return {
@@ -1197,7 +1296,7 @@ function getTokenType(val, hint) {
1197
1296
  return {
1198
1297
  typ: EnumToken.ColorTokenType,
1199
1298
  val,
1200
- kin: 'hex'
1299
+ kin: ColorKind.HEX
1201
1300
  };
1202
1301
  }
1203
1302
  if (val.charAt(0) == '#' && isHash(val)) {
@@ -1218,23 +1317,13 @@ function getTokenType(val, hint) {
1218
1317
  };
1219
1318
  }
1220
1319
  /**
1221
- * parse token list
1320
+ * parse token array into a tree structure
1222
1321
  * @param tokens
1223
1322
  * @param options
1224
1323
  */
1225
1324
  function parseTokens(tokens, options = {}) {
1226
1325
  for (let i = 0; i < tokens.length; i++) {
1227
1326
  const t = tokens[i];
1228
- if (t.typ == EnumToken.PseudoClassFuncTokenType) {
1229
- if (t.val.slice(1) in webkitPseudoAliasMap) {
1230
- t.val = ':' + webkitPseudoAliasMap[t.val.slice(1)];
1231
- }
1232
- }
1233
- else if (t.typ == EnumToken.PseudoClassTokenType) {
1234
- if (t.val.slice(1) in webkitPseudoAliasMap) {
1235
- t.val = ':' + webkitPseudoAliasMap[t.val.slice(1)];
1236
- }
1237
- }
1238
1327
  if (t.typ == EnumToken.WhitespaceTokenType && ((i == 0 ||
1239
1328
  i + 1 == tokens.length ||
1240
1329
  [EnumToken.CommaTokenType, EnumToken.GteTokenType, EnumToken.LteTokenType, EnumToken.ColumnCombinatorTokenType].includes(tokens[i + 1].typ)) ||
@@ -1246,13 +1335,9 @@ function parseTokens(tokens, options = {}) {
1246
1335
  const typ = tokens[i + 1]?.typ;
1247
1336
  if (typ != null) {
1248
1337
  if (typ == EnumToken.FunctionTokenType) {
1249
- tokens[i + 1].val = ':' + (tokens[i + 1].val in webkitPseudoAliasMap ? webkitPseudoAliasMap[tokens[i + 1].val] : tokens[i + 1].val);
1250
1338
  tokens[i + 1].typ = EnumToken.PseudoClassFuncTokenType;
1251
1339
  }
1252
1340
  else if (typ == EnumToken.IdenTokenType) {
1253
- if (tokens[i + 1].val in webkitPseudoAliasMap) {
1254
- tokens[i + 1].val = webkitPseudoAliasMap[tokens[i + 1].val];
1255
- }
1256
1341
  tokens[i + 1].val = ':' + tokens[i + 1].val;
1257
1342
  tokens[i + 1].typ = EnumToken.PseudoClassTokenType;
1258
1343
  }
@@ -1372,6 +1457,12 @@ function parseTokens(tokens, options = {}) {
1372
1457
  l: t.chi[lower],
1373
1458
  r: t.chi[upper]
1374
1459
  };
1460
+ if (isIdentColor(t.chi[m].l)) {
1461
+ t.chi[m].l.typ = EnumToken.IdenTokenType;
1462
+ }
1463
+ if (isIdentColor(t.chi[m].r)) {
1464
+ t.chi[m].r.typ = EnumToken.IdenTokenType;
1465
+ }
1375
1466
  t.chi.splice(upper, 1);
1376
1467
  t.chi.splice(lower, 1);
1377
1468
  upper = m;
@@ -1458,6 +1549,13 @@ function parseTokens(tokens, options = {}) {
1458
1549
  delete value.val;
1459
1550
  }
1460
1551
  }
1552
+ t.chi = splitTokenList(t.chi).reduce((acc, t) => {
1553
+ if (acc.length > 0) {
1554
+ acc.push({ typ: EnumToken.CommaTokenType });
1555
+ }
1556
+ acc.push(buildExpression(t));
1557
+ return acc;
1558
+ }, []);
1461
1559
  }
1462
1560
  else if (t.typ == EnumToken.FunctionTokenType && ['minmax', 'fit-content', 'repeat'].includes(t.val)) {
1463
1561
  // @ts-ignore
@@ -1469,34 +1567,7 @@ function parseTokens(tokens, options = {}) {
1469
1567
  }
1470
1568
  // @ts-ignore
1471
1569
  if (options.parseColor && t.typ == EnumToken.FunctionTokenType && isColor(t)) {
1472
- // @ts-ignore
1473
- t.typ = EnumToken.ColorTokenType;
1474
- // @ts-ignore
1475
- t.kin = t.val;
1476
- // @ts-ignore
1477
- if (t.chi[0].typ == EnumToken.IdenTokenType) {
1478
- // @ts-ignore
1479
- if (t.chi[0].val == 'from') {
1480
- // @ts-ignore
1481
- t.cal = 'rel';
1482
- }
1483
- // @ts-ignore
1484
- else if (t.val == 'color-mix' && t.chi[0].val == 'in') {
1485
- // @ts-ignore
1486
- t.cal = 'mix';
1487
- }
1488
- else { // @ts-ignore
1489
- if (t.val == 'color') {
1490
- // @ts-ignore
1491
- t.cal = 'col';
1492
- }
1493
- }
1494
- }
1495
- const filter = [EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType];
1496
- if (t.val != 'light-dark') {
1497
- filter.push(EnumToken.CommaTokenType);
1498
- }
1499
- t.chi = t.chi.filter((t) => !filter.includes(t.typ));
1570
+ parseColor(t);
1500
1571
  continue;
1501
1572
  }
1502
1573
  if (t.typ == EnumToken.UrlFunctionTokenType) {
@@ -1543,7 +1614,7 @@ function parseTokens(tokens, options = {}) {
1543
1614
  Object.assign(t, {
1544
1615
  typ: EnumToken.ColorTokenType,
1545
1616
  val: COLORS_NAMES[value].length < value.length ? COLORS_NAMES[value] : value,
1546
- kin: 'hex'
1617
+ kin: ColorKind.HEX
1547
1618
  });
1548
1619
  }
1549
1620
  continue;
@@ -1553,11 +1624,11 @@ function parseTokens(tokens, options = {}) {
1553
1624
  // @ts-ignore
1554
1625
  t.typ = EnumToken.ColorTokenType;
1555
1626
  // @ts-ignore
1556
- t.kin = 'hex';
1627
+ t.kin = ColorKind.HEX;
1557
1628
  }
1558
1629
  }
1559
1630
  }
1560
1631
  return tokens;
1561
1632
  }
1562
1633
 
1563
- export { doParse, parseSelector, parseString, parseTokens, urlTokenMatcher };
1634
+ export { doParse, getTokenType, parseAtRulePrelude, parseSelector, parseString, parseTokens, urlTokenMatcher };