@tbela99/css-parser 1.0.0 → 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 (86) hide show
  1. package/CHANGELOG.md +265 -0
  2. package/README.md +16 -11
  3. package/dist/index-umd-web.js +3613 -1829
  4. package/dist/index.cjs +3611 -1827
  5. package/dist/index.d.ts +160 -50
  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 +17 -15
  19. package/dist/lib/ast/walk.js +33 -7
  20. package/dist/lib/fs/resolve.js +10 -0
  21. package/dist/lib/parser/declaration/list.js +48 -45
  22. package/dist/lib/parser/declaration/map.js +1 -0
  23. package/dist/lib/parser/declaration/set.js +2 -1
  24. package/dist/lib/parser/parse.js +364 -276
  25. package/dist/lib/parser/tokenize.js +147 -72
  26. package/dist/lib/parser/utils/declaration.js +4 -3
  27. package/dist/lib/parser/utils/type.js +2 -1
  28. package/dist/lib/renderer/color/a98rgb.js +2 -1
  29. package/dist/lib/renderer/color/color-mix.js +10 -7
  30. package/dist/lib/renderer/color/color.js +171 -153
  31. package/dist/lib/renderer/color/hex.js +2 -1
  32. package/dist/lib/renderer/color/hsl.js +2 -1
  33. package/dist/lib/renderer/color/hwb.js +2 -1
  34. package/dist/lib/renderer/color/lab.js +2 -1
  35. package/dist/lib/renderer/color/lch.js +2 -1
  36. package/dist/lib/renderer/color/oklab.js +2 -1
  37. package/dist/lib/renderer/color/oklch.js +2 -1
  38. package/dist/lib/renderer/color/p3.js +2 -1
  39. package/dist/lib/renderer/color/rec2020.js +2 -1
  40. package/dist/lib/renderer/color/relativecolor.js +17 -11
  41. package/dist/lib/renderer/color/rgb.js +4 -3
  42. package/dist/lib/renderer/color/srgb.js +18 -17
  43. package/dist/lib/renderer/color/utils/components.js +6 -5
  44. package/dist/lib/renderer/color/utils/constants.js +47 -3
  45. package/dist/lib/renderer/color/xyz.js +2 -1
  46. package/dist/lib/renderer/color/xyzd50.js +2 -1
  47. package/dist/lib/renderer/render.js +48 -20
  48. package/dist/lib/syntax/syntax.js +253 -140
  49. package/dist/lib/validation/at-rules/container.js +75 -97
  50. package/dist/lib/validation/at-rules/counter-style.js +9 -8
  51. package/dist/lib/validation/at-rules/custom-media.js +13 -15
  52. package/dist/lib/validation/at-rules/document.js +22 -27
  53. package/dist/lib/validation/at-rules/font-feature-values.js +8 -8
  54. package/dist/lib/validation/at-rules/import.js +30 -81
  55. package/dist/lib/validation/at-rules/keyframes.js +18 -22
  56. package/dist/lib/validation/at-rules/layer.js +5 -5
  57. package/dist/lib/validation/at-rules/media.js +42 -52
  58. package/dist/lib/validation/at-rules/namespace.js +19 -23
  59. package/dist/lib/validation/at-rules/page-margin-box.js +15 -18
  60. package/dist/lib/validation/at-rules/page.js +8 -7
  61. package/dist/lib/validation/at-rules/supports.js +73 -82
  62. package/dist/lib/validation/at-rules/when.js +32 -36
  63. package/dist/lib/validation/atrule.js +15 -14
  64. package/dist/lib/validation/config.js +24 -1
  65. package/dist/lib/validation/config.json.js +563 -63
  66. package/dist/lib/validation/parser/parse.js +196 -185
  67. package/dist/lib/validation/parser/types.js +1 -1
  68. package/dist/lib/validation/selector.js +3 -3
  69. package/dist/lib/validation/syntax.js +828 -0
  70. package/dist/lib/validation/syntaxes/complex-selector-list.js +10 -11
  71. package/dist/lib/validation/syntaxes/complex-selector.js +10 -11
  72. package/dist/lib/validation/syntaxes/compound-selector.js +40 -50
  73. package/dist/lib/validation/syntaxes/family-name.js +9 -8
  74. package/dist/lib/validation/syntaxes/keyframe-block-list.js +4 -3
  75. package/dist/lib/validation/syntaxes/keyframe-selector.js +15 -18
  76. package/dist/lib/validation/syntaxes/layer-name.js +6 -5
  77. package/dist/lib/validation/syntaxes/relative-selector-list.js +7 -6
  78. package/dist/lib/validation/syntaxes/relative-selector.js +2 -1
  79. package/dist/lib/validation/syntaxes/url.js +18 -22
  80. package/dist/lib/validation/utils/list.js +2 -1
  81. package/dist/lib/validation/utils/whitespace.js +2 -1
  82. package/dist/node/index.js +4 -2
  83. package/dist/node/load.js +5 -0
  84. package/dist/web/index.js +4 -2
  85. package/dist/web/load.js +5 -0
  86. package/package.json +12 -11
@@ -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
  }
@@ -97,16 +103,22 @@ async function doParse(iterator, options = {}) {
97
103
  lin: 1,
98
104
  col: 1
99
105
  },
106
+ end: {
107
+ ind: 0,
108
+ lin: 1,
109
+ col: 1
110
+ },
100
111
  src: ''
101
112
  };
102
113
  }
103
114
  const iter = tokenize(iterator);
104
115
  let item;
116
+ let node;
105
117
  const rawTokens = [];
118
+ const imports = [];
106
119
  while (item = iter.next().value) {
107
120
  stats.bytesIn = item.bytesIn;
108
121
  rawTokens.push(item);
109
- // doParse error
110
122
  if (item.hint != null && BadTokensTypes.includes(item.hint)) {
111
123
  // bad token
112
124
  continue;
@@ -114,14 +126,23 @@ async function doParse(iterator, options = {}) {
114
126
  if (item.hint != EnumToken.EOFTokenType) {
115
127
  tokens.push(item);
116
128
  }
129
+ else if (ast.loc != null) {
130
+ for (let i = stack.length - 1; i >= 0; i--) {
131
+ stack[i].loc.end = { ...item.end };
132
+ }
133
+ ast.loc.end = item.end;
134
+ }
117
135
  if (item.token == ';' || item.token == '{') {
118
- let node = await parseNode(tokens, context, stats, options, errors, src, map, rawTokens);
136
+ node = parseNode(tokens, context, stats, options, errors, src, map, rawTokens);
119
137
  rawTokens.length = 0;
120
138
  if (node != null) {
121
- // @ts-ignore
122
- stack.push(node);
123
- // @ts-ignore
124
- context = node;
139
+ if ('chi' in node) {
140
+ stack.push(node);
141
+ context = node;
142
+ }
143
+ else if (node.typ == EnumToken.AtRuleNodeType && node.nam == 'import') {
144
+ imports.push(node);
145
+ }
125
146
  }
126
147
  else if (item.token == '{') {
127
148
  let inBlock = 1;
@@ -151,23 +172,20 @@ async function doParse(iterator, options = {}) {
151
172
  map = new Map;
152
173
  }
153
174
  else if (item.token == '}') {
154
- await parseNode(tokens, context, stats, options, errors, src, map, rawTokens);
175
+ parseNode(tokens, context, stats, options, errors, src, map, rawTokens);
155
176
  rawTokens.length = 0;
177
+ if (context.loc != null) {
178
+ context.loc.end = item.end;
179
+ }
156
180
  const previousNode = stack.pop();
157
- // @ts-ignore
158
- context = stack[stack.length - 1] ?? ast;
159
- // @ts-ignore
181
+ context = (stack[stack.length - 1] ?? ast);
160
182
  if (previousNode != null && previousNode.typ == EnumToken.InvalidRuleTokenType) {
161
- // @ts-ignore
162
183
  const index = context.chi.findIndex(node => node == previousNode);
163
184
  if (index > -1) {
164
- // @ts-ignore
165
185
  context.chi.splice(index, 1);
166
186
  }
167
187
  }
168
- // @ts-ignore
169
188
  if (options.removeEmpty && previousNode != null && previousNode.chi.length == 0 && context.chi[context.chi.length - 1] == previousNode) {
170
- // @ts-ignore
171
189
  context.chi.pop();
172
190
  }
173
191
  tokens = [];
@@ -175,8 +193,17 @@ async function doParse(iterator, options = {}) {
175
193
  }
176
194
  }
177
195
  if (tokens.length > 0) {
178
- await parseNode(tokens, context, stats, options, errors, src, map, rawTokens);
196
+ node = parseNode(tokens, context, stats, options, errors, src, map, rawTokens);
179
197
  rawTokens.length = 0;
198
+ if (node != null) {
199
+ if (node.typ == EnumToken.AtRuleNodeType && node.nam == 'import') {
200
+ imports.push(node);
201
+ }
202
+ else if ('chi' in node && node.typ != EnumToken.InvalidRuleTokenType) {
203
+ stack.push(node);
204
+ context = node;
205
+ }
206
+ }
180
207
  if (context != null && context.typ == EnumToken.InvalidRuleTokenType) {
181
208
  // @ts-ignore
182
209
  const index = context.chi.findIndex((node) => node == context);
@@ -185,14 +212,37 @@ async function doParse(iterator, options = {}) {
185
212
  }
186
213
  }
187
214
  }
215
+ if (imports.length > 0 && options.resolveImport) {
216
+ await Promise.all(imports.map(async (node) => {
217
+ const token = node.tokens[0];
218
+ const url = token.typ == EnumToken.StringTokenType ? token.val.slice(1, -1) : token.val;
219
+ try {
220
+ const root = await options.load(url, options.src).then((src) => {
221
+ // console.error({url, src: options.src, resolved: options.resolve!(url, options.src as string)})
222
+ return doParse(src, Object.assign({}, options, {
223
+ minify: false,
224
+ setParent: false,
225
+ src: options.resolve(url, options.src).absolute
226
+ }));
227
+ });
228
+ stats.importedBytesIn += root.stats.bytesIn;
229
+ node.parent.chi.splice(node.parent.chi.indexOf(node), 1, ...root.ast.chi);
230
+ if (root.errors.length > 0) {
231
+ errors.push(...root.errors);
232
+ }
233
+ }
234
+ catch (error) {
235
+ // console.error(error);
236
+ // @ts-ignore
237
+ errors.push({ action: 'ignore', message: 'doParse: ' + error.message, error });
238
+ }
239
+ }));
240
+ }
188
241
  while (stack.length > 0 && context != ast) {
189
242
  const previousNode = stack.pop();
190
- // @ts-ignore
191
- context = stack[stack.length - 1] ?? ast;
243
+ context = (stack[stack.length - 1] ?? ast);
192
244
  // remove empty nodes
193
- // @ts-ignore
194
245
  if (options.removeEmpty && previousNode != null && previousNode.chi.length == 0 && context.chi[context.chi.length - 1] == previousNode) {
195
- // @ts-ignore
196
246
  context.chi.pop();
197
247
  continue;
198
248
  }
@@ -205,14 +255,12 @@ async function doParse(iterator, options = {}) {
205
255
  if (options.visitor != null) {
206
256
  for (const result of walk(ast)) {
207
257
  if (result.node.typ == EnumToken.DeclarationNodeType &&
208
- // @ts-ignore
209
258
  (typeof options.visitor.Declaration == 'function' || options.visitor.Declaration?.[result.node.nam] != null)) {
210
259
  const callable = typeof options.visitor.Declaration == 'function' ? options.visitor.Declaration : options.visitor.Declaration[result.node.nam];
211
260
  const results = await callable(result.node);
212
261
  if (results == null || (Array.isArray(results) && results.length == 0)) {
213
262
  continue;
214
263
  }
215
- // @ts-ignore
216
264
  result.parent.chi.splice(result.parent.chi.indexOf(result.node), 1, ...(Array.isArray(results) ? results : [results]));
217
265
  }
218
266
  else if (options.visitor.Rule != null && result.node.typ == EnumToken.RuleNodeType) {
@@ -220,7 +268,6 @@ async function doParse(iterator, options = {}) {
220
268
  if (results == null || (Array.isArray(results) && results.length == 0)) {
221
269
  continue;
222
270
  }
223
- // @ts-ignore
224
271
  result.parent.chi.splice(result.parent.chi.indexOf(result.node), 1, ...(Array.isArray(results) ? results : [results]));
225
272
  }
226
273
  else if (options.visitor.AtRule != null &&
@@ -232,7 +279,6 @@ async function doParse(iterator, options = {}) {
232
279
  if (results == null || (Array.isArray(results) && results.length == 0)) {
233
280
  continue;
234
281
  }
235
- // @ts-ignore
236
282
  result.parent.chi.splice(result.parent.chi.indexOf(result.node), 1, ...(Array.isArray(results) ? results : [results]));
237
283
  }
238
284
  }
@@ -271,30 +317,27 @@ function getLastNode(context) {
271
317
  }
272
318
  return null;
273
319
  }
274
- async function parseNode(results, context, stats, options, errors, src, map, rawTokens) {
320
+ function parseNode(results, context, stats, options, errors, src, map, rawTokens) {
275
321
  let tokens = [];
276
322
  for (const t of results) {
277
323
  const node = getTokenType(t.token, t.hint);
278
- map.set(node, t.position);
324
+ map.set(node, { sta: t.sta, end: t.end, src });
279
325
  tokens.push(node);
280
326
  }
281
327
  let i;
282
328
  let loc;
283
329
  for (i = 0; i < tokens.length; i++) {
284
330
  if (tokens[i].typ == EnumToken.CommentTokenType || tokens[i].typ == EnumToken.CDOCOMMTokenType) {
285
- const position = map.get(tokens[i]);
331
+ const location = map.get(tokens[i]);
286
332
  if (tokens[i].typ == EnumToken.CDOCOMMTokenType && context.typ != EnumToken.StyleSheetNodeType) {
287
333
  errors.push({
288
334
  action: 'drop',
289
335
  message: `CDOCOMM not allowed here ${JSON.stringify(tokens[i], null, 1)}`,
290
- location: { src, ...position }
336
+ location
291
337
  });
292
338
  continue;
293
339
  }
294
- loc = {
295
- sta: position,
296
- src
297
- };
340
+ loc = location;
298
341
  // @ts-ignore
299
342
  context.chi.push(tokens[i]);
300
343
  if (options.sourcemap) {
@@ -313,10 +356,6 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
313
356
  if (delim.typ == EnumToken.SemiColonTokenType || delim.typ == EnumToken.BlockStartTokenType || delim.typ == EnumToken.BlockEndTokenType) {
314
357
  tokens.pop();
315
358
  }
316
- else {
317
- delim = { typ: EnumToken.SemiColonTokenType };
318
- }
319
- // @ts-ignore
320
359
  while ([EnumToken.WhitespaceTokenType, EnumToken.BadStringTokenType, EnumToken.BadCommentTokenType].includes(tokens.at(-1)?.typ)) {
321
360
  tokens.pop();
322
361
  }
@@ -325,11 +364,12 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
325
364
  }
326
365
  if (tokens[0]?.typ == EnumToken.AtRuleTokenType) {
327
366
  const atRule = tokens.shift();
328
- const position = map.get(atRule);
367
+ const location = map.get(atRule);
329
368
  // @ts-ignore
330
369
  while ([EnumToken.WhitespaceTokenType].includes(tokens[0]?.typ)) {
331
370
  tokens.shift();
332
371
  }
372
+ rawTokens.shift();
333
373
  if (atRule.val == 'import') {
334
374
  // only @charset and @layer are accepted before @import
335
375
  // @ts-ignore
@@ -347,14 +387,14 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
347
387
  if (!(type == EnumToken.InvalidAtRuleTokenType &&
348
388
  // @ts-ignore
349
389
  ['charset', 'layer', 'import'].includes(context.chi[i].nam))) {
350
- errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } });
390
+ errors.push({ action: 'drop', message: 'invalid @import', location });
351
391
  return null;
352
392
  }
353
393
  }
354
394
  // @ts-ignore
355
395
  const name = context.chi[i].nam;
356
396
  if (name != 'charset' && name != 'import' && name != 'layer') {
357
- errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } });
397
+ errors.push({ action: 'drop', message: 'invalid @import', location });
358
398
  return null;
359
399
  }
360
400
  break;
@@ -365,7 +405,7 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
365
405
  errors.push({
366
406
  action: 'drop',
367
407
  message: 'doParse: invalid @import',
368
- location: { src, ...position }
408
+ location
369
409
  });
370
410
  return null;
371
411
  }
@@ -374,7 +414,7 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
374
414
  errors.push({
375
415
  action: 'drop',
376
416
  message: 'doParse: invalid @import',
377
- location: { src, ...position }
417
+ location
378
418
  });
379
419
  return null;
380
420
  }
@@ -400,37 +440,6 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
400
440
  }
401
441
  }
402
442
  }
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
443
  }
435
444
  // https://www.w3.org/TR/css-nesting-1/#conditionals
436
445
  // allowed nesting at-rules
@@ -438,7 +447,7 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
438
447
  if (atRule.val == 'charset') {
439
448
  let spaces = 0;
440
449
  // https://developer.mozilla.org/en-US/docs/Web/CSS/@charset
441
- for (let k = 1; k < rawTokens.length; k++) {
450
+ for (let k = 0; k < rawTokens.length; k++) {
442
451
  if (rawTokens[k].hint == EnumToken.WhitespaceTokenType) {
443
452
  spaces += rawTokens[k].len;
444
453
  continue;
@@ -454,7 +463,7 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
454
463
  action: 'drop',
455
464
  message: '@charset must have only one space',
456
465
  // @ts-ignore
457
- location: { src, ...(map.get(atRule) ?? position) }
466
+ location
458
467
  });
459
468
  return null;
460
469
  }
@@ -462,8 +471,7 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
462
471
  errors.push({
463
472
  action: 'drop',
464
473
  message: '@charset expects a "<charset>"',
465
- // @ts-ignore
466
- location: { src, ...(map.get(atRule) ?? position) }
474
+ location
467
475
  });
468
476
  return null;
469
477
  }
@@ -483,94 +491,75 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
483
491
  const node = {
484
492
  typ: /^(-[a-z]+-)?keyframes$/.test(nam) ? EnumToken.KeyframeAtRuleNodeType : EnumToken.AtRuleNodeType,
485
493
  nam,
486
- // tokens: t,
487
494
  val: raw.join('')
488
495
  };
489
496
  Object.defineProperties(node, {
490
- tokens: { ...definedPropertySettings, enumerable: false, value: tokens.slice() },
497
+ tokens: { ...definedPropertySettings, enumerable: false, value: t.slice() },
491
498
  raw: { ...definedPropertySettings, value: raw }
492
499
  });
493
500
  if (delim.typ == EnumToken.BlockStartTokenType) {
494
501
  node.chi = [];
495
502
  }
496
- loc = {
497
- sta: position,
498
- src
499
- };
503
+ loc = map.get(atRule);
500
504
  if (options.sourcemap) {
501
505
  node.loc = loc;
506
+ node.loc.end = { ...map.get(delim).end };
502
507
  }
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;
508
+ // if (options.validation) {
509
+ let isValid = true;
510
+ if (node.nam == 'else') {
511
+ const prev = getLastNode(context);
512
+ if (prev != null && prev.typ == EnumToken.AtRuleNodeType && ['when', 'else'].includes(prev.nam)) {
513
+ if (prev.nam == 'else') {
514
+ isValid = Array.isArray(prev.tokens) && prev.tokens.length > 0;
514
515
  }
515
516
  }
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
517
  else {
532
- node.val = node.tokens.reduce((acc, curr) => acc + renderToken(curr, {
533
- minify: false,
534
- removeComments: true
535
- }), '');
518
+ isValid = false;
536
519
  }
537
520
  }
538
521
  // @ts-ignore
522
+ const valid = options.validation == ValidationLevel.None ? {
523
+ valid: SyntaxValidationResult.Valid,
524
+ error: '',
525
+ node,
526
+ syntax: '@' + node.nam
527
+ } : isValid ? (node.typ == EnumToken.KeyframeAtRuleNodeType ? validateAtRuleKeyframes(node) : validateAtRule(node, options, context)) : {
528
+ valid: SyntaxValidationResult.Drop,
529
+ node,
530
+ syntax: '@' + node.nam,
531
+ error: '@' + node.nam + ' not allowed here'};
532
+ if (valid.valid == SyntaxValidationResult.Drop) {
533
+ errors.push({
534
+ action: 'drop',
535
+ message: valid.error + ' - "' + tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '') + '"',
536
+ // @ts-ignore
537
+ location: { src, ...(map.get(valid.node) ?? location) }
538
+ });
539
+ // @ts-ignore
540
+ node.typ = EnumToken.InvalidAtRuleTokenType;
541
+ }
542
+ else {
543
+ node.val = node.tokens.reduce((acc, curr) => acc + renderToken(curr, {
544
+ minify: false,
545
+ removeComments: true
546
+ }), '');
547
+ }
548
+ // }
539
549
  context.chi.push(node);
540
- Object.defineProperty(node, 'parent', { ...definedPropertySettings, value: context });
541
- return delim.typ == EnumToken.BlockStartTokenType ? node : null;
550
+ Object.defineProperties(node, { parent: { ...definedPropertySettings, value: context }, validSyntax: { ...definedPropertySettings, value: valid.valid == SyntaxValidationResult.Valid } });
551
+ return node;
542
552
  }
543
553
  else {
544
554
  // rule
545
555
  if (delim.typ == EnumToken.BlockStartTokenType) {
546
- const position = map.get(tokens[0]);
556
+ const location = map.get(tokens[0]);
547
557
  const uniq = new Map;
548
558
  parseTokens(tokens, { minify: true });
549
559
  const ruleType = context.typ == EnumToken.KeyframeAtRuleNodeType ? EnumToken.KeyFrameRuleNodeType : EnumToken.RuleNodeType;
550
560
  if (ruleType == EnumToken.RuleNodeType) {
551
561
  parseSelector(tokens);
552
562
  }
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
563
  const node = {
575
564
  typ: ruleType,
576
565
  sel: [...tokens.reduce((acc, curr, index, array) => {
@@ -625,78 +614,124 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
625
614
  enumerable: false,
626
615
  value: tokens.slice()
627
616
  });
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
- };
617
+ loc = location;
639
618
  if (options.sourcemap) {
640
619
  node.loc = loc;
641
620
  }
642
621
  // @ts-ignore
643
622
  context.chi.push(node);
644
623
  Object.defineProperty(node, 'parent', { ...definedPropertySettings, value: context });
624
+ // if (options.validation) {
625
+ // @ts-ignore
626
+ const valid = options.validation == ValidationLevel.None ? {
627
+ valid: SyntaxValidationResult.Valid,
628
+ error: null
629
+ } : ruleType == EnumToken.KeyFrameRuleNodeType ? validateKeyframeSelector(tokens) : validateSelector(tokens, options, context);
630
+ if (valid.valid != SyntaxValidationResult.Valid) {
631
+ // @ts-ignore
632
+ node.typ = EnumToken.InvalidRuleTokenType;
633
+ node.sel = tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '');
634
+ errors.push({
635
+ action: 'drop',
636
+ message: valid.error + ' - "' + tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '') + '"',
637
+ // @ts-ignore
638
+ location
639
+ });
640
+ }
641
+ // } else {
642
+ //
643
+ // Object.defineProperty(node, 'tokens', {
644
+ // ...definedPropertySettings,
645
+ // enumerable: false,
646
+ // value: tokens.slice()
647
+ // });
648
+ //
649
+ // let raw: string[][] = [...uniq.values()];
650
+ //
651
+ // Object.defineProperty(node, 'raw', {
652
+ // enumerable: false,
653
+ // configurable: true,
654
+ // writable: true,
655
+ // value: raw
656
+ // });
657
+ // }
658
+ Object.defineProperty(node, 'validSyntax', { ...definedPropertySettings, value: valid.valid == SyntaxValidationResult.Valid });
645
659
  return node;
646
660
  }
647
661
  else {
648
662
  let name = null;
649
663
  let value = null;
650
- for (let i = 0; i < tokens.length; i++) {
664
+ let i = 0;
665
+ for (; i < tokens.length; i++) {
666
+ if (tokens[i].typ == EnumToken.LiteralTokenType && tokens[i].val.length > 1) {
667
+ const start = tokens[i].val.charAt(0);
668
+ const val = tokens[i].val.slice(1);
669
+ if (['/', '*'].includes(start) && isNumber(val)) {
670
+ tokens.splice(i, 1, {
671
+ typ: EnumToken.LiteralTokenType,
672
+ val: tokens[i].val.charAt(0)
673
+ }, {
674
+ typ: EnumToken.NumberTokenType,
675
+ val: tokens[i].val.slice(1)
676
+ });
677
+ }
678
+ else if (start == '/' && isFunction(val)) {
679
+ tokens.splice(i, 1, { typ: EnumToken.LiteralTokenType, val: '/' }, getTokenType(val));
680
+ }
681
+ }
682
+ }
683
+ parseTokens(tokens, { ...options, parseColor: true });
684
+ for (i = 0; i < tokens.length; i++) {
651
685
  if (tokens[i].typ == EnumToken.CommentTokenType) {
652
686
  continue;
653
687
  }
654
688
  if (name == null && [EnumToken.IdenTokenType, EnumToken.DashedIdenTokenType].includes(tokens[i].typ)) {
655
689
  name = tokens.slice(0, i + 1);
656
690
  }
691
+ else if (name == null && tokens[i].typ == EnumToken.ColorTokenType && [ColorKind.SYS, ColorKind.DPSYS].includes(tokens[i].kin)) {
692
+ name = tokens.slice(0, i + 1);
693
+ tokens[i].typ = EnumToken.IdenTokenType;
694
+ }
657
695
  else if (name != null && funcLike.concat([
658
696
  EnumToken.LiteralTokenType,
659
697
  EnumToken.IdenTokenType, EnumToken.DashedIdenTokenType,
660
698
  EnumToken.PseudoClassTokenType, EnumToken.PseudoClassFuncTokenType
661
699
  ]).includes(tokens[i].typ)) {
662
- if (tokens[i].val.charAt(0) == ':') {
700
+ if (tokens[i].val?.charAt?.(0) == ':') {
663
701
  Object.assign(tokens[i], getTokenType(tokens[i].val.slice(1)));
702
+ if ('chi' in tokens[i]) {
703
+ tokens[i].typ = EnumToken.FunctionTokenType;
704
+ if (colorsFunc.includes(tokens[i].val) && isColor(tokens[i])) {
705
+ parseColor(tokens[i]);
706
+ }
707
+ }
708
+ tokens.splice(i, 0, { typ: EnumToken.ColonTokenType });
709
+ // i++;
710
+ i--;
711
+ continue;
664
712
  }
665
713
  if ('chi' in tokens[i]) {
666
714
  tokens[i].typ = EnumToken.FunctionTokenType;
667
715
  }
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;
716
+ value = tokens.slice(i);
676
717
  }
677
718
  if (tokens[i].typ == EnumToken.ColonTokenType) {
678
719
  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
- });
720
+ value = tokens.slice(i + 1);
686
721
  break;
687
722
  }
688
723
  }
689
724
  if (name == null) {
690
725
  name = tokens;
691
726
  }
692
- const position = map.get(name[0]);
727
+ const location = map.get(name[0]);
693
728
  if (name.length > 0) {
694
729
  for (let i = 1; i < name.length; i++) {
695
730
  if (name[i].typ != EnumToken.WhitespaceTokenType && name[i].typ != EnumToken.CommentTokenType) {
696
731
  errors.push({
697
732
  action: 'drop',
698
733
  message: 'doParse: invalid declaration',
699
- location: { src, ...position }
734
+ location
700
735
  });
701
736
  return null;
702
737
  }
@@ -707,8 +742,20 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
707
742
  errors.push({
708
743
  action: 'drop',
709
744
  message: 'doParse: invalid declaration',
710
- location: { src, ...position }
745
+ location
711
746
  });
747
+ if (options.lenient) {
748
+ const node = {
749
+ typ: EnumToken.InvalidDeclarationNodeType,
750
+ nam,
751
+ val: []
752
+ };
753
+ if (options.sourcemap) {
754
+ node.loc = location;
755
+ node.loc.end = { ...map.get(delim).end };
756
+ }
757
+ context.chi.push(node);
758
+ }
712
759
  return null;
713
760
  }
714
761
  for (const { value: token } of walkValues(value, null, {
@@ -728,16 +775,42 @@ async function parseNode(results, context, stats, options, errors, src, map, raw
728
775
  }
729
776
  const node = {
730
777
  typ: EnumToken.DeclarationNodeType,
731
- // @ts-ignore
732
778
  nam,
733
- // @ts-ignore
734
779
  val: value
735
780
  };
736
- const result = parseDeclarationNode(node, errors, src, position);
737
- if (result != null) {
781
+ if (options.sourcemap) {
782
+ node.loc = location;
783
+ node.loc.end = { ...map.get(delim).end };
784
+ }
785
+ // do not allow declarations in style sheets
786
+ if (context.typ == EnumToken.StyleSheetNodeType && options.lenient) {
738
787
  // @ts-ignore
788
+ node.typ = EnumToken.InvalidDeclarationNodeType;
789
+ context.chi.push(node);
790
+ return null;
791
+ }
792
+ const result = parseDeclarationNode(node, errors, location);
793
+ Object.defineProperty(result, 'parent', { ...definedPropertySettings, value: context });
794
+ if (result != null) {
795
+ // console.error(doRender(result), result.val, location);
796
+ if (options.validation == ValidationLevel.All) {
797
+ const valid = evaluateSyntax(result, options);
798
+ Object.defineProperty(result, 'validSyntax', { ...definedPropertySettings, value: valid.valid == SyntaxValidationResult.Valid });
799
+ if (valid.valid == SyntaxValidationResult.Drop) {
800
+ errors.push({
801
+ action: 'drop',
802
+ message: valid.error,
803
+ syntax: valid.syntax,
804
+ location: map.get(valid.node) ?? valid.node?.loc ?? result.loc ?? location
805
+ });
806
+ if (!options.lenient) {
807
+ return null;
808
+ }
809
+ // @ts-ignore
810
+ node.typ = EnumToken.InvalidDeclarationNodeType;
811
+ }
812
+ }
739
813
  context.chi.push(result);
740
- Object.defineProperty(result, 'parent', { ...definedPropertySettings, value: context });
741
814
  }
742
815
  return null;
743
816
  }
@@ -756,6 +829,33 @@ function parseAtRulePrelude(tokens, atRule) {
756
829
  value.typ == EnumToken.CommaTokenType) {
757
830
  continue;
758
831
  }
832
+ if (value.typ == EnumToken.PseudoClassFuncTokenType || value.typ == EnumToken.PseudoClassTokenType) {
833
+ if (parent?.typ == EnumToken.ParensTokenType) {
834
+ const index = parent.chi.indexOf(value);
835
+ let i = index;
836
+ while (i--) {
837
+ if (parent.chi[i].typ == EnumToken.IdenTokenType || parent.chi[i].typ == EnumToken.DashedIdenTokenType) {
838
+ break;
839
+ }
840
+ }
841
+ if (i >= 0) {
842
+ const token = getTokenType(parent.chi[index].val.slice(1) + (funcLike.includes(parent.chi[index].typ) ? '(' : ''));
843
+ parent.chi[index].val = token.val;
844
+ parent.chi[index].typ = token.typ;
845
+ if (parent.chi[index].typ == EnumToken.FunctionTokenType && isColor(parent.chi[index])) {
846
+ parseColor(parent.chi[index]);
847
+ }
848
+ parent.chi.splice(i, index - i + 1, {
849
+ typ: EnumToken.MediaQueryConditionTokenType,
850
+ l: parent.chi[i],
851
+ r: parent.chi.slice(index),
852
+ op: {
853
+ typ: EnumToken.ColonTokenType
854
+ }
855
+ });
856
+ }
857
+ }
858
+ }
759
859
  if (atRule.val == 'page' && value.typ == EnumToken.PseudoClassTokenType) {
760
860
  if ([':left', ':right', ':first', ':blank'].includes(value.val)) {
761
861
  // @ts-ignore
@@ -816,6 +916,9 @@ function parseAtRulePrelude(tokens, atRule) {
816
916
  continue;
817
917
  }
818
918
  }
919
+ if (value.typ == EnumToken.FunctionTokenType && value.val == 'selector') {
920
+ parseSelector(value.chi);
921
+ }
819
922
  if (value.typ == EnumToken.ParensTokenType || (value.typ == EnumToken.FunctionTokenType && ['media', 'supports', 'style', 'scroll-state'].includes(value.val))) {
820
923
  let i;
821
924
  let nameIndex = -1;
@@ -837,6 +940,23 @@ function parseAtRulePrelude(tokens, atRule) {
837
940
  if (value.chi[i].typ == EnumToken.CommentTokenType || value.chi[i].typ == EnumToken.WhitespaceTokenType) {
838
941
  continue;
839
942
  }
943
+ if (value.chi[i].typ == EnumToken.LiteralTokenType && value.chi[i].val.startsWith(':') && isDimension(value.chi[i].val.slice(1))) {
944
+ value.chi.splice(i, 1, {
945
+ typ: EnumToken.ColonTokenType,
946
+ }, Object.assign(value.chi[i], parseDimension(value.chi[i].val.slice(1))));
947
+ i--;
948
+ continue;
949
+ }
950
+ if (nameIndex != -1 && value.chi[i].typ == EnumToken.PseudoClassTokenType) {
951
+ value.chi.splice(i, 1, {
952
+ typ: EnumToken.ColonTokenType,
953
+ }, Object.assign(value.chi[i], {
954
+ typ: EnumToken.IdenTokenType,
955
+ val: value.chi[i].val.slice(1)
956
+ }));
957
+ i--;
958
+ continue;
959
+ }
840
960
  valueIndex = i;
841
961
  break;
842
962
  }
@@ -856,7 +976,7 @@ function parseAtRulePrelude(tokens, atRule) {
856
976
  const node = value.chi.splice(nameIndex, 1)[0];
857
977
  // 'background'
858
978
  // @ts-ignore
859
- if (node.typ == EnumToken.ColorTokenType && node.kin == 'dpsys') {
979
+ if (node.typ == EnumToken.ColorTokenType && node.kin == ColorKind.DPSYS) {
860
980
  // @ts-ignore
861
981
  delete node.kin;
862
982
  node.typ = EnumToken.IdenTokenType;
@@ -980,8 +1100,8 @@ function parseSelector(tokens) {
980
1100
  }
981
1101
  }
982
1102
  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') {
1103
+ if (value.kin == ColorKind.LIT || value.kin == ColorKind.HEX || value.kin == ColorKind.SYS || value.kin == ColorKind.DPSYS) {
1104
+ if (value.kin == ColorKind.HEX) {
985
1105
  if (!isIdent(value.val.slice(1))) {
986
1106
  continue;
987
1107
  }
@@ -1026,64 +1146,54 @@ function parseSelector(tokens) {
1026
1146
  // return doParse(`.x{${src}`, options).then((result: ParseResult) => <AstDeclaration[]>(<AstRule>result.ast.chi[0]).chi.filter(t => t.typ == EnumToken.DeclarationNodeType));
1027
1147
  // }
1028
1148
  /**
1029
- * parse string
1149
+ * parse css string
1030
1150
  * @param src
1031
1151
  * @param options
1032
1152
  */
1033
1153
  function parseString(src, options = { location: false }) {
1034
- return parseTokens([...tokenize(src)].map(t => {
1154
+ return parseTokens([...tokenize(src)].reduce((acc, t) => {
1155
+ if (t.hint == EnumToken.EOFTokenType) {
1156
+ return acc;
1157
+ }
1035
1158
  const token = getTokenType(t.token, t.hint);
1036
1159
  if (options.location) {
1037
- Object.assign(token, { loc: t.position });
1160
+ Object.assign(token, { loc: t.sta });
1038
1161
  }
1039
- return token;
1040
- }));
1162
+ acc.push(token);
1163
+ return acc;
1164
+ }, []));
1041
1165
  }
1042
1166
  function getTokenType(val, hint) {
1043
1167
  if (hint != null) {
1044
1168
  return enumTokenHints.has(hint) ? { typ: hint } : { typ: hint, val };
1045
1169
  }
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 };
1170
+ switch (val) {
1171
+ case ' ':
1172
+ return { typ: EnumToken.WhitespaceTokenType };
1173
+ case ';':
1174
+ return { typ: EnumToken.SemiColonTokenType };
1175
+ case '{':
1176
+ return { typ: EnumToken.BlockStartTokenType };
1177
+ case '}':
1178
+ return { typ: EnumToken.BlockEndTokenType };
1179
+ case '[':
1180
+ return { typ: EnumToken.AttrStartTokenType };
1181
+ case ']':
1182
+ return { typ: EnumToken.AttrEndTokenType };
1183
+ case ':':
1184
+ return { typ: EnumToken.ColonTokenType };
1185
+ case ')':
1186
+ return { typ: EnumToken.EndParensTokenType };
1187
+ case '(':
1188
+ return { typ: EnumToken.StartParensTokenType };
1189
+ case '=':
1190
+ return { typ: EnumToken.DelimTokenType };
1191
+ case ',':
1192
+ return { typ: EnumToken.CommaTokenType };
1193
+ case '<':
1194
+ return { typ: EnumToken.LtTokenType };
1195
+ case '>':
1196
+ return { typ: EnumToken.GtTokenType };
1087
1197
  }
1088
1198
  if (isPseudo(val)) {
1089
1199
  return val.endsWith('(') ? {
@@ -1170,22 +1280,22 @@ function getTokenType(val, hint) {
1170
1280
  return {
1171
1281
  typ: EnumToken.ColorTokenType,
1172
1282
  val: v,
1173
- kin: 'lit'
1283
+ kin: ColorKind.LIT
1174
1284
  };
1175
1285
  }
1176
1286
  if (isIdent(val)) {
1177
- if (systemColors.has(val.toLowerCase())) {
1287
+ if (systemColors.has(v)) {
1178
1288
  return {
1179
1289
  typ: EnumToken.ColorTokenType,
1180
1290
  val,
1181
- kin: 'sys'
1291
+ kin: ColorKind.SYS
1182
1292
  };
1183
1293
  }
1184
- if (deprecatedSystemColors.has(val.toLowerCase())) {
1294
+ if (deprecatedSystemColors.has(v)) {
1185
1295
  return {
1186
1296
  typ: EnumToken.ColorTokenType,
1187
1297
  val,
1188
- kin: 'dpsys'
1298
+ kin: ColorKind.DPSYS
1189
1299
  };
1190
1300
  }
1191
1301
  return {
@@ -1197,7 +1307,7 @@ function getTokenType(val, hint) {
1197
1307
  return {
1198
1308
  typ: EnumToken.ColorTokenType,
1199
1309
  val,
1200
- kin: 'hex'
1310
+ kin: ColorKind.HEX
1201
1311
  };
1202
1312
  }
1203
1313
  if (val.charAt(0) == '#' && isHash(val)) {
@@ -1218,23 +1328,13 @@ function getTokenType(val, hint) {
1218
1328
  };
1219
1329
  }
1220
1330
  /**
1221
- * parse token list
1331
+ * parse token array into a tree structure
1222
1332
  * @param tokens
1223
1333
  * @param options
1224
1334
  */
1225
1335
  function parseTokens(tokens, options = {}) {
1226
1336
  for (let i = 0; i < tokens.length; i++) {
1227
1337
  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
1338
  if (t.typ == EnumToken.WhitespaceTokenType && ((i == 0 ||
1239
1339
  i + 1 == tokens.length ||
1240
1340
  [EnumToken.CommaTokenType, EnumToken.GteTokenType, EnumToken.LteTokenType, EnumToken.ColumnCombinatorTokenType].includes(tokens[i + 1].typ)) ||
@@ -1246,13 +1346,9 @@ function parseTokens(tokens, options = {}) {
1246
1346
  const typ = tokens[i + 1]?.typ;
1247
1347
  if (typ != null) {
1248
1348
  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
1349
  tokens[i + 1].typ = EnumToken.PseudoClassFuncTokenType;
1251
1350
  }
1252
1351
  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
1352
  tokens[i + 1].val = ':' + tokens[i + 1].val;
1257
1353
  tokens[i + 1].typ = EnumToken.PseudoClassTokenType;
1258
1354
  }
@@ -1372,6 +1468,12 @@ function parseTokens(tokens, options = {}) {
1372
1468
  l: t.chi[lower],
1373
1469
  r: t.chi[upper]
1374
1470
  };
1471
+ if (isIdentColor(t.chi[m].l)) {
1472
+ t.chi[m].l.typ = EnumToken.IdenTokenType;
1473
+ }
1474
+ if (isIdentColor(t.chi[m].r)) {
1475
+ t.chi[m].r.typ = EnumToken.IdenTokenType;
1476
+ }
1375
1477
  t.chi.splice(upper, 1);
1376
1478
  t.chi.splice(lower, 1);
1377
1479
  upper = m;
@@ -1458,6 +1560,13 @@ function parseTokens(tokens, options = {}) {
1458
1560
  delete value.val;
1459
1561
  }
1460
1562
  }
1563
+ t.chi = splitTokenList(t.chi).reduce((acc, t) => {
1564
+ if (acc.length > 0) {
1565
+ acc.push({ typ: EnumToken.CommaTokenType });
1566
+ }
1567
+ acc.push(buildExpression(t));
1568
+ return acc;
1569
+ }, []);
1461
1570
  }
1462
1571
  else if (t.typ == EnumToken.FunctionTokenType && ['minmax', 'fit-content', 'repeat'].includes(t.val)) {
1463
1572
  // @ts-ignore
@@ -1469,34 +1578,7 @@ function parseTokens(tokens, options = {}) {
1469
1578
  }
1470
1579
  // @ts-ignore
1471
1580
  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));
1581
+ parseColor(t);
1500
1582
  continue;
1501
1583
  }
1502
1584
  if (t.typ == EnumToken.UrlFunctionTokenType) {
@@ -1508,6 +1590,12 @@ function parseTokens(tokens, options = {}) {
1508
1590
  if (t.chi[0].val.slice(1, 5) != 'data:' && urlTokenMatcher.test(value)) {
1509
1591
  // @ts-ignore
1510
1592
  t.chi[0].typ = EnumToken.UrlTokenTokenType;
1593
+ // console.error({t, v: t.chi[0], value,
1594
+ // src: options.src,
1595
+ // resolved: options.src !== '' && options.resolveUrls ? options.resolve(value, options.src).absolute : null,
1596
+ // val2: options.src !== '' && options.resolveUrls ? options.resolve(value, options.src).absolute : value});
1597
+ //
1598
+ // console.error(new Error('resolved'));
1511
1599
  // @ts-ignore
1512
1600
  t.chi[0].val = options.src !== '' && options.resolveUrls ? options.resolve(value, options.src).absolute : value;
1513
1601
  }
@@ -1543,7 +1631,7 @@ function parseTokens(tokens, options = {}) {
1543
1631
  Object.assign(t, {
1544
1632
  typ: EnumToken.ColorTokenType,
1545
1633
  val: COLORS_NAMES[value].length < value.length ? COLORS_NAMES[value] : value,
1546
- kin: 'hex'
1634
+ kin: ColorKind.HEX
1547
1635
  });
1548
1636
  }
1549
1637
  continue;
@@ -1553,11 +1641,11 @@ function parseTokens(tokens, options = {}) {
1553
1641
  // @ts-ignore
1554
1642
  t.typ = EnumToken.ColorTokenType;
1555
1643
  // @ts-ignore
1556
- t.kin = 'hex';
1644
+ t.kin = ColorKind.HEX;
1557
1645
  }
1558
1646
  }
1559
1647
  }
1560
1648
  return tokens;
1561
1649
  }
1562
1650
 
1563
- export { doParse, parseSelector, parseString, parseTokens, urlTokenMatcher };
1651
+ export { doParse, parseAtRulePrelude, parseSelector, parseString, parseTokens, urlTokenMatcher };