@tbela99/css-parser 0.3.0 → 0.4.1

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 (60) hide show
  1. package/{LICENSE → LICENSE.md} +1 -1
  2. package/README.md +191 -80
  3. package/dist/config.json.js +20 -1
  4. package/dist/index-umd-web.js +3210 -1352
  5. package/dist/index.cjs +3211 -1353
  6. package/dist/index.d.ts +910 -0
  7. package/dist/lib/ast/expand.js +1 -1
  8. package/dist/lib/ast/features/calc.js +1 -2
  9. package/dist/lib/ast/features/inlinecssvariables.js +1 -1
  10. package/dist/lib/ast/features/shorthand.js +1 -1
  11. package/dist/lib/ast/math/expression.js +38 -3
  12. package/dist/lib/ast/math/math.js +2 -2
  13. package/dist/lib/ast/minify.js +0 -1
  14. package/dist/lib/ast/types.js +1 -0
  15. package/dist/lib/ast/utils/minifyfeature.js +4 -3
  16. package/dist/lib/parser/declaration/list.js +1 -1
  17. package/dist/lib/parser/declaration/map.js +129 -26
  18. package/dist/lib/parser/declaration/set.js +1 -1
  19. package/dist/lib/parser/parse.js +325 -303
  20. package/dist/lib/parser/tokenize.js +220 -223
  21. package/dist/lib/parser/utils/declaration.js +1 -1
  22. package/dist/lib/parser/utils/syntax.js +159 -23
  23. package/dist/lib/parser/utils/type.js +2 -2
  24. package/dist/lib/renderer/color/a98rgb.js +64 -0
  25. package/dist/lib/renderer/color/color.js +521 -0
  26. package/dist/lib/renderer/color/colormix.js +337 -0
  27. package/dist/lib/renderer/color/hex.js +92 -0
  28. package/dist/lib/renderer/color/hsl.js +118 -0
  29. package/dist/lib/renderer/color/hsv.js +20 -0
  30. package/dist/lib/renderer/color/hwb.js +101 -0
  31. package/dist/lib/renderer/color/lab.js +136 -0
  32. package/dist/lib/renderer/color/lch.js +79 -0
  33. package/dist/lib/renderer/color/oklab.js +121 -0
  34. package/dist/lib/renderer/color/oklch.js +65 -0
  35. package/dist/lib/renderer/color/p3.js +57 -0
  36. package/dist/lib/renderer/color/prophotorgb.js +56 -0
  37. package/dist/lib/renderer/color/rec2020.js +70 -0
  38. package/dist/lib/renderer/color/relativecolor.js +152 -0
  39. package/dist/lib/renderer/color/rgb.js +44 -0
  40. package/dist/lib/renderer/color/srgb.js +261 -0
  41. package/dist/lib/renderer/color/utils/components.js +20 -0
  42. package/dist/lib/renderer/color/utils/constants.js +191 -0
  43. package/dist/lib/renderer/color/utils/matrix.js +35 -0
  44. package/dist/lib/renderer/color/xyz.js +64 -0
  45. package/dist/lib/renderer/color/xyzd50.js +33 -0
  46. package/dist/lib/renderer/render.js +61 -32
  47. package/dist/node/index.js +1 -1
  48. package/dist/node/load.js +1 -1
  49. package/dist/web/index.js +1 -1
  50. package/package.json +15 -14
  51. package/dist/lib/ast/features/utils/math.js +0 -95
  52. package/dist/lib/iterable/set.js +0 -48
  53. package/dist/lib/iterable/weakmap.js +0 -53
  54. package/dist/lib/renderer/utils/calccolor.js +0 -238
  55. package/dist/lib/renderer/utils/color.js +0 -371
  56. package/dist/lib/renderer/utils/hex.js +0 -124
  57. package/dist/lib/renderer/utils/hsl.js +0 -49
  58. package/dist/lib/renderer/utils/hsv.js +0 -15
  59. package/dist/lib/renderer/utils/hwb.js +0 -50
  60. package/dist/lib/renderer/utils/rgb.js +0 -66
@@ -5,7 +5,7 @@ import { walkValues, walk } from '../ast/walk.js';
5
5
  import { expand } from '../ast/expand.js';
6
6
  import { parseDeclaration } from './utils/declaration.js';
7
7
  import { renderToken } from '../renderer/render.js';
8
- import { COLORS_NAMES } from '../renderer/utils/color.js';
8
+ import { COLORS_NAMES } from '../renderer/color/utils/constants.js';
9
9
  import { tokenize } from './tokenize.js';
10
10
 
11
11
  const urlTokenMatcher = /^(["']?)[a-zA-Z0-9_/.-][a-zA-Z0-9_/:.#?-]+(\1)$/;
@@ -50,13 +50,19 @@ async function doParse(iterator, options = {}) {
50
50
  const errors = [];
51
51
  const src = options.src;
52
52
  const stack = [];
53
+ const stats = {
54
+ bytesIn: 0,
55
+ importedBytesIn: 0,
56
+ parse: `0ms`,
57
+ minify: `0ms`,
58
+ total: `0ms`
59
+ };
53
60
  let ast = {
54
61
  typ: EnumToken.StyleSheetNodeType,
55
62
  chi: []
56
63
  };
57
64
  let tokens = [];
58
65
  let map = new Map;
59
- let bytesIn = 0;
60
66
  let context = ast;
61
67
  if (options.sourcemap) {
62
68
  ast.loc = {
@@ -68,307 +74,21 @@ async function doParse(iterator, options = {}) {
68
74
  src: ''
69
75
  };
70
76
  }
71
- async function parseNode(results) {
72
- let tokens = results.map(mapToken);
73
- let i;
74
- let loc;
75
- for (i = 0; i < tokens.length; i++) {
76
- if (tokens[i].typ == EnumToken.CommentTokenType || tokens[i].typ == EnumToken.CDOCOMMTokenType) {
77
- const position = map.get(tokens[i]);
78
- if (tokens[i].typ == EnumToken.CDOCOMMTokenType && context.typ != EnumToken.StyleSheetNodeType) {
79
- errors.push({
80
- action: 'drop',
81
- message: `CDOCOMM not allowed here ${JSON.stringify(tokens[i], null, 1)}`,
82
- location: { src, ...position }
83
- });
84
- continue;
85
- }
86
- loc = {
87
- sta: position,
88
- src
89
- };
90
- // @ts-ignore
91
- context.chi.push(tokens[i]);
92
- if (options.sourcemap) {
93
- tokens[i].loc = loc;
94
- }
95
- }
96
- else if (tokens[i].typ != EnumToken.WhitespaceTokenType) {
97
- break;
98
- }
99
- }
100
- tokens = tokens.slice(i);
101
- if (tokens.length == 0) {
102
- return null;
103
- }
104
- let delim = tokens.at(-1);
105
- if (delim.typ == EnumToken.SemiColonTokenType || delim.typ == EnumToken.BlockStartTokenType || delim.typ == EnumToken.BlockEndTokenType) {
106
- tokens.pop();
107
- }
108
- else {
109
- delim = { typ: EnumToken.SemiColonTokenType };
110
- }
111
- // @ts-ignore
112
- while ([EnumToken.WhitespaceTokenType, EnumToken.BadStringTokenType, EnumToken.BadCommentTokenType].includes(tokens.at(-1)?.typ)) {
113
- tokens.pop();
114
- }
115
- if (tokens.length == 0) {
116
- return null;
117
- }
118
- if (tokens[0]?.typ == EnumToken.AtRuleTokenType) {
119
- const atRule = tokens.shift();
120
- const position = map.get(atRule);
121
- if (atRule.val == 'charset') {
122
- if (position.ind > 0) {
123
- errors.push({
124
- action: 'drop',
125
- message: 'doParse: invalid @charset',
126
- location: { src, ...position }
127
- });
128
- return null;
129
- }
130
- if (options.removeCharset) {
131
- return null;
132
- }
133
- }
134
- // @ts-ignore
135
- while ([EnumToken.WhitespaceTokenType].includes(tokens[0]?.typ)) {
136
- tokens.shift();
137
- }
138
- if (atRule.val == 'import') {
139
- // only @charset and @layer are accepted before @import
140
- if (context.chi.length > 0) {
141
- let i = context.chi.length;
142
- while (i--) {
143
- const type = context.chi[i].typ;
144
- if (type == EnumToken.CommentNodeType) {
145
- continue;
146
- }
147
- if (type != EnumToken.AtRuleNodeType) {
148
- errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } });
149
- return null;
150
- }
151
- const name = context.chi[i].nam;
152
- if (name != 'charset' && name != 'import' && name != 'layer') {
153
- errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } });
154
- return null;
155
- }
156
- break;
157
- }
158
- }
159
- // @ts-ignore
160
- if (tokens[0]?.typ != EnumToken.StringTokenType && tokens[0]?.typ != EnumToken.UrlFunctionTokenType) {
161
- errors.push({
162
- action: 'drop',
163
- message: 'doParse: invalid @import',
164
- location: { src, ...position }
165
- });
166
- return null;
167
- }
168
- // @ts-ignore
169
- if (tokens[0].typ == EnumToken.UrlFunctionTokenType && tokens[1]?.typ != EnumToken.UrlTokenTokenType && tokens[1]?.typ != EnumToken.StringTokenType) {
170
- errors.push({
171
- action: 'drop',
172
- message: 'doParse: invalid @import',
173
- location: { src, ...position }
174
- });
175
- return null;
176
- }
177
- }
178
- if (atRule.val == 'import') {
179
- // @ts-ignore
180
- if (tokens[0].typ == EnumToken.UrlFunctionTokenType && tokens[1].typ == EnumToken.UrlTokenTokenType) {
181
- tokens.shift();
182
- // @ts-ignore
183
- tokens[0].typ = EnumToken.StringTokenType;
184
- // @ts-ignore
185
- tokens[0].val = `"${tokens[0].val}"`;
186
- }
187
- // @ts-ignore
188
- if (tokens[0].typ == EnumToken.StringTokenType) {
189
- if (options.resolveImport) {
190
- const url = tokens[0].val.slice(1, -1);
191
- try {
192
- // @ts-ignore
193
- const root = await options.load(url, options.src).then((src) => {
194
- return doParse(src, Object.assign({}, options, {
195
- minify: false,
196
- // @ts-ignore
197
- src: options.resolve(url, options.src).absolute
198
- }));
199
- });
200
- bytesIn += root.stats.bytesIn;
201
- if (root.ast.chi.length > 0) {
202
- // @todo - filter charset, layer and scope
203
- context.chi.push(...root.ast.chi);
204
- }
205
- if (root.errors.length > 0) {
206
- errors.push(...root.errors);
207
- }
208
- return null;
209
- }
210
- catch (error) {
211
- // @ts-ignore
212
- errors.push({ action: 'ignore', message: 'doParse: ' + error.message, error });
213
- }
214
- }
215
- }
216
- }
217
- // https://www.w3.org/TR/css-nesting-1/#conditionals
218
- // allowed nesting at-rules
219
- // there must be a top level rule in the stack
220
- const raw = parseTokens(tokens, { minify: options.minify }).reduce((acc, curr) => {
221
- acc.push(renderToken(curr, { removeComments: true }));
222
- return acc;
223
- }, []);
224
- const node = {
225
- typ: EnumToken.AtRuleNodeType,
226
- nam: renderToken(atRule, { removeComments: true }),
227
- val: raw.join('')
228
- };
229
- Object.defineProperty(node, 'raw', { enumerable: false, configurable: true, writable: true, value: raw });
230
- if (delim.typ == EnumToken.BlockStartTokenType) {
231
- node.chi = [];
232
- }
233
- loc = {
234
- sta: position,
235
- src
236
- };
237
- if (options.sourcemap) {
238
- node.loc = loc;
239
- }
240
- // @ts-ignore
241
- context.chi.push(node);
242
- return delim.typ == EnumToken.BlockStartTokenType ? node : null;
243
- }
244
- else {
245
- // rule
246
- if (delim.typ == EnumToken.BlockStartTokenType) {
247
- const position = map.get(tokens[0]);
248
- const uniq = new Map;
249
- parseTokens(tokens, { minify: true }).reduce((acc, curr, index, array) => {
250
- if (curr.typ == EnumToken.WhitespaceTokenType) {
251
- if (trimWhiteSpace.includes(array[index - 1]?.typ) ||
252
- trimWhiteSpace.includes(array[index + 1]?.typ) ||
253
- combinators.includes(array[index - 1]?.val) ||
254
- combinators.includes(array[index + 1]?.val)) {
255
- return acc;
256
- }
257
- }
258
- let t = renderToken(curr, { minify: false });
259
- if (t == ',') {
260
- acc.push([]);
261
- }
262
- else {
263
- acc[acc.length - 1].push(t);
264
- }
265
- return acc;
266
- }, [[]]).reduce((acc, curr) => {
267
- acc.set(curr.join(''), curr);
268
- return acc;
269
- }, uniq);
270
- const node = {
271
- typ: EnumToken.RuleNodeType,
272
- // @ts-ignore
273
- sel: [...uniq.keys()].join(','),
274
- chi: []
275
- };
276
- let raw = [...uniq.values()];
277
- Object.defineProperty(node, 'raw', {
278
- enumerable: false,
279
- configurable: true,
280
- writable: true,
281
- value: raw
282
- });
283
- loc = {
284
- sta: position,
285
- src
286
- };
287
- if (options.sourcemap) {
288
- node.loc = loc;
289
- }
290
- // @ts-ignore
291
- context.chi.push(node);
292
- return node;
293
- }
294
- else {
295
- // declaration
296
- // @ts-ignore
297
- let name = null;
298
- // @ts-ignore
299
- let value = null;
300
- for (let i = 0; i < tokens.length; i++) {
301
- if (tokens[i].typ == EnumToken.CommentTokenType) {
302
- continue;
303
- }
304
- if (tokens[i].typ == EnumToken.ColonTokenType) {
305
- name = tokens.slice(0, i);
306
- value = parseTokens(tokens.slice(i + 1), {
307
- parseColor: options.parseColor,
308
- src: options.src,
309
- resolveUrls: options.resolveUrls,
310
- resolve: options.resolve,
311
- cwd: options.cwd
312
- });
313
- }
314
- }
315
- if (name == null) {
316
- name = tokens;
317
- }
318
- const position = map.get(name[0]);
319
- if (name.length > 0) {
320
- for (let i = 1; i < name.length; i++) {
321
- if (name[i].typ != EnumToken.WhitespaceTokenType && name[i].typ != EnumToken.CommentTokenType) {
322
- errors.push({
323
- action: 'drop',
324
- message: 'doParse: invalid declaration',
325
- location: { src, ...position }
326
- });
327
- return null;
328
- }
329
- }
330
- }
331
- if (value == null || value.length == 0) {
332
- errors.push({
333
- action: 'drop',
334
- message: 'doParse: invalid declaration',
335
- location: { src, ...position }
336
- });
337
- return null;
338
- }
339
- const node = {
340
- typ: EnumToken.DeclarationNodeType,
341
- // @ts-ignore
342
- nam: renderToken(name.shift(), { removeComments: true }),
343
- // @ts-ignore
344
- val: value
345
- };
346
- const result = parseDeclaration(node, errors, src, position);
347
- if (result != null) {
348
- // @ts-ignore
349
- context.chi.push(node);
350
- }
351
- return null;
352
- }
353
- }
354
- }
355
- function mapToken(token) {
356
- const node = getTokenType(token.token, token.hint);
357
- map.set(node, token.position);
358
- return node;
359
- }
360
77
  const iter = tokenize(iterator);
361
78
  let item;
362
79
  while (item = iter.next().value) {
363
- bytesIn = item.bytesIn;
80
+ stats.bytesIn = item.bytesIn;
81
+ //
364
82
  // doParse error
365
83
  if (item.hint != null && BadTokensTypes.includes(item.hint)) {
366
84
  // bad token
367
85
  continue;
368
86
  }
369
- tokens.push(item);
87
+ if (item.hint != EnumToken.EOFTokenType) {
88
+ tokens.push(item);
89
+ }
370
90
  if (item.token == ';' || item.token == '{') {
371
- let node = await parseNode(tokens);
91
+ let node = await parseNode(tokens, context, stats, options, errors, src, map);
372
92
  if (node != null) {
373
93
  stack.push(node);
374
94
  // @ts-ignore
@@ -395,7 +115,7 @@ async function doParse(iterator, options = {}) {
395
115
  map = new Map;
396
116
  }
397
117
  else if (item.token == '}') {
398
- await parseNode(tokens);
118
+ await parseNode(tokens, context, stats, options, errors, src, map);
399
119
  const previousNode = stack.pop();
400
120
  // @ts-ignore
401
121
  context = stack[stack.length - 1] || ast;
@@ -408,12 +128,12 @@ async function doParse(iterator, options = {}) {
408
128
  }
409
129
  }
410
130
  if (tokens.length > 0) {
411
- await parseNode(tokens);
131
+ await parseNode(tokens, context, stats, options, errors, src, map);
412
132
  }
413
133
  while (stack.length > 0 && context != ast) {
414
134
  const previousNode = stack.pop();
415
135
  // @ts-ignore
416
- context = stack[stack.length - 1] || ast;
136
+ context = stack[stack.length - 1] ?? ast;
417
137
  // @ts-ignore
418
138
  if (options.removeEmpty && previousNode != null && previousNode.chi.length == 0 && context.chi[context.chi.length - 1] == previousNode) {
419
139
  context.chi.pop();
@@ -431,7 +151,7 @@ async function doParse(iterator, options = {}) {
431
151
  // @ts-ignore
432
152
  (typeof options.visitor.Declaration == 'function' || options.visitor.Declaration?.[result.node.nam] != null)) {
433
153
  const callable = typeof options.visitor.Declaration == 'function' ? options.visitor.Declaration : options.visitor.Declaration[result.node.nam];
434
- const results = callable(result.node);
154
+ const results = await callable(result.node);
435
155
  if (results == null || (Array.isArray(results) && results.length == 0)) {
436
156
  continue;
437
157
  }
@@ -439,7 +159,7 @@ async function doParse(iterator, options = {}) {
439
159
  result.parent.chi.splice(result.parent.chi.indexOf(result.node), 1, ...(Array.isArray(results) ? results : [results]));
440
160
  }
441
161
  else if (options.visitor.Rule != null && result.node.typ == EnumToken.RuleNodeType) {
442
- const results = options.visitor.Rule(result.node);
162
+ const results = await options.visitor.Rule(result.node);
443
163
  if (results == null || (Array.isArray(results) && results.length == 0)) {
444
164
  continue;
445
165
  }
@@ -451,7 +171,7 @@ async function doParse(iterator, options = {}) {
451
171
  // @ts-ignore
452
172
  (typeof options.visitor.AtRule == 'function' || options.visitor.AtRule?.[result.node.nam] != null)) {
453
173
  const callable = typeof options.visitor.AtRule == 'function' ? options.visitor.AtRule : options.visitor.AtRule[result.node.nam];
454
- const results = callable(result.node);
174
+ const results = await callable(result.node);
455
175
  if (results == null || (Array.isArray(results) && results.length == 0)) {
456
176
  continue;
457
177
  }
@@ -469,11 +189,12 @@ async function doParse(iterator, options = {}) {
469
189
  if (options.signal != null) {
470
190
  options.signal.removeEventListener('abort', reject);
471
191
  }
192
+ stats.bytesIn += stats.importedBytesIn;
472
193
  resolve({
473
194
  ast,
474
195
  errors,
475
196
  stats: {
476
- bytesIn,
197
+ ...stats,
477
198
  parse: `${(endParseTime - startTime).toFixed(2)}ms`,
478
199
  minify: `${(endTime - endParseTime).toFixed(2)}ms`,
479
200
  total: `${(endTime - startTime).toFixed(2)}ms`
@@ -481,6 +202,295 @@ async function doParse(iterator, options = {}) {
481
202
  });
482
203
  });
483
204
  }
205
+ async function parseNode(results, context, stats, options, errors, src, map) {
206
+ let tokens = results.map((t) => mapToken(t, map));
207
+ let i;
208
+ let loc;
209
+ for (i = 0; i < tokens.length; i++) {
210
+ if (tokens[i].typ == EnumToken.CommentTokenType || tokens[i].typ == EnumToken.CDOCOMMTokenType) {
211
+ const position = map.get(tokens[i]);
212
+ if (tokens[i].typ == EnumToken.CDOCOMMTokenType && context.typ != EnumToken.StyleSheetNodeType) {
213
+ errors.push({
214
+ action: 'drop',
215
+ message: `CDOCOMM not allowed here ${JSON.stringify(tokens[i], null, 1)}`,
216
+ location: { src, ...position }
217
+ });
218
+ continue;
219
+ }
220
+ loc = {
221
+ sta: position,
222
+ src
223
+ };
224
+ // @ts-ignore
225
+ context.chi.push(tokens[i]);
226
+ if (options.sourcemap) {
227
+ tokens[i].loc = loc;
228
+ }
229
+ }
230
+ else if (tokens[i].typ != EnumToken.WhitespaceTokenType) {
231
+ break;
232
+ }
233
+ }
234
+ tokens = tokens.slice(i);
235
+ if (tokens.length == 0) {
236
+ return null;
237
+ }
238
+ let delim = tokens.at(-1);
239
+ if (delim.typ == EnumToken.SemiColonTokenType || delim.typ == EnumToken.BlockStartTokenType || delim.typ == EnumToken.BlockEndTokenType) {
240
+ tokens.pop();
241
+ }
242
+ else {
243
+ delim = { typ: EnumToken.SemiColonTokenType };
244
+ }
245
+ // @ts-ignore
246
+ while ([EnumToken.WhitespaceTokenType, EnumToken.BadStringTokenType, EnumToken.BadCommentTokenType].includes(tokens.at(-1)?.typ)) {
247
+ tokens.pop();
248
+ }
249
+ if (tokens.length == 0) {
250
+ return null;
251
+ }
252
+ if (tokens[0]?.typ == EnumToken.AtRuleTokenType) {
253
+ const atRule = tokens.shift();
254
+ const position = map.get(atRule);
255
+ if (atRule.val == 'charset') {
256
+ if (position.ind > 0) {
257
+ errors.push({
258
+ action: 'drop',
259
+ message: 'doParse: invalid @charset',
260
+ location: { src, ...position }
261
+ });
262
+ return null;
263
+ }
264
+ if (options.removeCharset) {
265
+ return null;
266
+ }
267
+ }
268
+ // @ts-ignore
269
+ while ([EnumToken.WhitespaceTokenType].includes(tokens[0]?.typ)) {
270
+ tokens.shift();
271
+ }
272
+ if (atRule.val == 'import') {
273
+ // only @charset and @layer are accepted before @import
274
+ if (context.chi.length > 0) {
275
+ let i = context.chi.length;
276
+ while (i--) {
277
+ const type = context.chi[i].typ;
278
+ if (type == EnumToken.CommentNodeType) {
279
+ continue;
280
+ }
281
+ if (type != EnumToken.AtRuleNodeType) {
282
+ errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } });
283
+ return null;
284
+ }
285
+ const name = context.chi[i].nam;
286
+ if (name != 'charset' && name != 'import' && name != 'layer') {
287
+ errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } });
288
+ return null;
289
+ }
290
+ break;
291
+ }
292
+ }
293
+ // @ts-ignore
294
+ if (tokens[0]?.typ != EnumToken.StringTokenType && tokens[0]?.typ != EnumToken.UrlFunctionTokenType) {
295
+ errors.push({
296
+ action: 'drop',
297
+ message: 'doParse: invalid @import',
298
+ location: { src, ...position }
299
+ });
300
+ return null;
301
+ }
302
+ // @ts-ignore
303
+ if (tokens[0].typ == EnumToken.UrlFunctionTokenType && tokens[1]?.typ != EnumToken.UrlTokenTokenType && tokens[1]?.typ != EnumToken.StringTokenType) {
304
+ errors.push({
305
+ action: 'drop',
306
+ message: 'doParse: invalid @import',
307
+ location: { src, ...position }
308
+ });
309
+ return null;
310
+ }
311
+ }
312
+ if (atRule.val == 'import') {
313
+ // @ts-ignore
314
+ if (tokens[0].typ == EnumToken.UrlFunctionTokenType && tokens[1].typ == EnumToken.UrlTokenTokenType) {
315
+ tokens.shift();
316
+ // @ts-ignore
317
+ tokens[0].typ = EnumToken.StringTokenType;
318
+ // @ts-ignore
319
+ tokens[0].val = `"${tokens[0].val}"`;
320
+ }
321
+ // @ts-ignore
322
+ if (tokens[0].typ == EnumToken.StringTokenType) {
323
+ if (options.resolveImport) {
324
+ const url = tokens[0].val.slice(1, -1);
325
+ try {
326
+ // @ts-ignore
327
+ const root = await options.load(url, options.src).then((src) => {
328
+ return doParse(src, Object.assign({}, options, {
329
+ minify: false,
330
+ // @ts-ignore
331
+ src: options.resolve(url, options.src).absolute
332
+ }));
333
+ });
334
+ stats.importedBytesIn += root.stats.bytesIn;
335
+ if (root.ast.chi.length > 0) {
336
+ // @todo - filter charset, layer and scope
337
+ context.chi.push(...root.ast.chi);
338
+ }
339
+ if (root.errors.length > 0) {
340
+ errors.push(...root.errors);
341
+ }
342
+ return null;
343
+ }
344
+ catch (error) {
345
+ // @ts-ignore
346
+ errors.push({ action: 'ignore', message: 'doParse: ' + error.message, error });
347
+ }
348
+ }
349
+ }
350
+ }
351
+ // https://www.w3.org/TR/css-nesting-1/#conditionals
352
+ // allowed nesting at-rules
353
+ // there must be a top level rule in the stack
354
+ const raw = parseTokens(tokens, { minify: options.minify }).reduce((acc, curr) => {
355
+ acc.push(renderToken(curr, { removeComments: true }));
356
+ return acc;
357
+ }, []);
358
+ const node = {
359
+ typ: EnumToken.AtRuleNodeType,
360
+ nam: renderToken(atRule, { removeComments: true }),
361
+ val: raw.join('')
362
+ };
363
+ Object.defineProperty(node, 'raw', { enumerable: false, configurable: true, writable: true, value: raw });
364
+ if (delim.typ == EnumToken.BlockStartTokenType) {
365
+ node.chi = [];
366
+ }
367
+ loc = {
368
+ sta: position,
369
+ src
370
+ };
371
+ if (options.sourcemap) {
372
+ node.loc = loc;
373
+ }
374
+ // @ts-ignore
375
+ context.chi.push(node);
376
+ return delim.typ == EnumToken.BlockStartTokenType ? node : null;
377
+ }
378
+ else {
379
+ // rule
380
+ if (delim.typ == EnumToken.BlockStartTokenType) {
381
+ const position = map.get(tokens[0]);
382
+ const uniq = new Map;
383
+ parseTokens(tokens, { minify: true }).reduce((acc, curr, index, array) => {
384
+ if (curr.typ == EnumToken.WhitespaceTokenType) {
385
+ if (trimWhiteSpace.includes(array[index - 1]?.typ) ||
386
+ trimWhiteSpace.includes(array[index + 1]?.typ) ||
387
+ combinators.includes(array[index - 1]?.val) ||
388
+ combinators.includes(array[index + 1]?.val)) {
389
+ return acc;
390
+ }
391
+ }
392
+ let t = renderToken(curr, { minify: false });
393
+ if (t == ',') {
394
+ acc.push([]);
395
+ }
396
+ else {
397
+ acc[acc.length - 1].push(t);
398
+ }
399
+ return acc;
400
+ }, [[]]).reduce((acc, curr) => {
401
+ acc.set(curr.join(''), curr);
402
+ return acc;
403
+ }, uniq);
404
+ const node = {
405
+ typ: EnumToken.RuleNodeType,
406
+ // @ts-ignore
407
+ sel: [...uniq.keys()].join(','),
408
+ chi: []
409
+ };
410
+ let raw = [...uniq.values()];
411
+ Object.defineProperty(node, 'raw', {
412
+ enumerable: false,
413
+ configurable: true,
414
+ writable: true,
415
+ value: raw
416
+ });
417
+ loc = {
418
+ sta: position,
419
+ src
420
+ };
421
+ if (options.sourcemap) {
422
+ node.loc = loc;
423
+ }
424
+ // @ts-ignore
425
+ context.chi.push(node);
426
+ return node;
427
+ }
428
+ else {
429
+ // declaration
430
+ // @ts-ignore
431
+ let name = null;
432
+ // @ts-ignore
433
+ let value = null;
434
+ for (let i = 0; i < tokens.length; i++) {
435
+ if (tokens[i].typ == EnumToken.CommentTokenType) {
436
+ continue;
437
+ }
438
+ if (tokens[i].typ == EnumToken.ColonTokenType) {
439
+ name = tokens.slice(0, i);
440
+ value = parseTokens(tokens.slice(i + 1), {
441
+ parseColor: options.parseColor,
442
+ src: options.src,
443
+ resolveUrls: options.resolveUrls,
444
+ resolve: options.resolve,
445
+ cwd: options.cwd
446
+ });
447
+ }
448
+ }
449
+ if (name == null) {
450
+ name = tokens;
451
+ }
452
+ const position = map.get(name[0]);
453
+ if (name.length > 0) {
454
+ for (let i = 1; i < name.length; i++) {
455
+ if (name[i].typ != EnumToken.WhitespaceTokenType && name[i].typ != EnumToken.CommentTokenType) {
456
+ errors.push({
457
+ action: 'drop',
458
+ message: 'doParse: invalid declaration',
459
+ location: { src, ...position }
460
+ });
461
+ return null;
462
+ }
463
+ }
464
+ }
465
+ if (value == null || value.length == 0) {
466
+ errors.push({
467
+ action: 'drop',
468
+ message: 'doParse: invalid declaration',
469
+ location: { src, ...position }
470
+ });
471
+ return null;
472
+ }
473
+ const node = {
474
+ typ: EnumToken.DeclarationNodeType,
475
+ // @ts-ignore
476
+ nam: renderToken(name.shift(), { removeComments: true }),
477
+ // @ts-ignore
478
+ val: value
479
+ };
480
+ const result = parseDeclaration(node, errors, src, position);
481
+ if (result != null) {
482
+ // @ts-ignore
483
+ context.chi.push(node);
484
+ }
485
+ return null;
486
+ }
487
+ }
488
+ }
489
+ function mapToken(token, map) {
490
+ const node = getTokenType(token.token, token.hint);
491
+ map.set(node, token.position);
492
+ return node;
493
+ }
484
494
  function parseString(src, options = { location: false }) {
485
495
  return parseTokens([...tokenize(src)].map(t => {
486
496
  const token = getTokenType(t.token, t.hint);
@@ -893,9 +903,21 @@ function parseTokens(tokens, options = {}) {
893
903
  t.typ = EnumToken.ColorTokenType;
894
904
  // @ts-ignore
895
905
  t.kin = t.val;
896
- if (t.chi[0].typ == EnumToken.IdenTokenType && t.chi[0].val == 'from') {
906
+ if (t.chi[0].typ == EnumToken.IdenTokenType) {
907
+ if (t.chi[0].val == 'from') {
908
+ // @ts-ignore
909
+ t.cal = 'rel';
910
+ }
897
911
  // @ts-ignore
898
- t.cal = 'rel';
912
+ else if (t.val == 'color-mix' && t.chi[0].val == 'in') {
913
+ // @ts-ignore
914
+ t.cal = 'mix';
915
+ }
916
+ else if (t.val == 'color') {
917
+ // @ts-ignore
918
+ t.cal = 'col';
919
+ // t.chi = t.chi.filter((t: Token) => [EnumToken.IdenTokenType, EnumToken.NumberTokenType, EnumToken.PercentageTokenType].includes(t.typ));
920
+ }
899
921
  }
900
922
  t.chi = t.chi.filter((t) => ![EnumToken.WhitespaceTokenType, EnumToken.CommaTokenType, EnumToken.CommentTokenType].includes(t.typ));
901
923
  continue;