@tbela99/css-parser 0.2.0 → 0.4.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 (57) hide show
  1. package/{LICENSE → LICENSE.md} +1 -1
  2. package/README.md +250 -77
  3. package/dist/config.json.js +245 -1
  4. package/dist/index-umd-web.js +4241 -1583
  5. package/dist/index.cjs +4242 -1584
  6. package/dist/index.d.ts +71 -23
  7. package/dist/lib/ast/expand.js +1 -1
  8. package/dist/lib/ast/features/calc.js +31 -192
  9. package/dist/lib/ast/features/index.js +3 -3
  10. package/dist/lib/ast/features/inlinecssvariables.js +6 -6
  11. package/dist/lib/ast/features/shorthand.js +5 -6
  12. package/dist/lib/ast/math/expression.js +220 -0
  13. package/dist/lib/ast/{features/utils → math}/math.js +4 -4
  14. package/dist/lib/ast/minify.js +0 -1
  15. package/dist/lib/ast/types.js +31 -13
  16. package/dist/lib/ast/utils/minifyfeature.js +4 -3
  17. package/dist/lib/ast/walk.js +24 -4
  18. package/dist/lib/fs/resolve.js +4 -3
  19. package/dist/lib/parser/declaration/list.js +6 -2
  20. package/dist/lib/parser/declaration/map.js +158 -24
  21. package/dist/lib/parser/declaration/set.js +42 -22
  22. package/dist/lib/parser/parse.js +345 -349
  23. package/dist/lib/parser/tokenize.js +220 -223
  24. package/dist/lib/parser/utils/declaration.js +67 -0
  25. package/dist/lib/parser/utils/syntax.js +172 -6
  26. package/dist/lib/parser/utils/type.js +2 -2
  27. package/dist/lib/renderer/color/a98rgb.js +64 -0
  28. package/dist/lib/renderer/color/color.js +521 -0
  29. package/dist/lib/renderer/color/colormix.js +337 -0
  30. package/dist/lib/renderer/color/hex.js +92 -0
  31. package/dist/lib/renderer/color/hsl.js +118 -0
  32. package/dist/lib/renderer/color/hsv.js +20 -0
  33. package/dist/lib/renderer/color/hwb.js +101 -0
  34. package/dist/lib/renderer/color/lab.js +136 -0
  35. package/dist/lib/renderer/color/lch.js +79 -0
  36. package/dist/lib/renderer/color/oklab.js +121 -0
  37. package/dist/lib/renderer/color/oklch.js +65 -0
  38. package/dist/lib/renderer/color/p3.js +57 -0
  39. package/dist/lib/renderer/color/prophotorgb.js +56 -0
  40. package/dist/lib/renderer/color/rec2020.js +70 -0
  41. package/dist/lib/renderer/color/relativecolor.js +152 -0
  42. package/dist/lib/renderer/color/rgb.js +44 -0
  43. package/dist/lib/renderer/color/srgb.js +261 -0
  44. package/dist/lib/renderer/color/utils/components.js +20 -0
  45. package/dist/lib/renderer/color/utils/constants.js +191 -0
  46. package/dist/lib/renderer/color/utils/matrix.js +35 -0
  47. package/dist/lib/renderer/color/xyz.js +64 -0
  48. package/dist/lib/renderer/color/xyzd50.js +33 -0
  49. package/dist/lib/renderer/render.js +128 -30
  50. package/dist/node/index.js +1 -1
  51. package/dist/node/load.js +1 -1
  52. package/dist/web/index.js +1 -1
  53. package/package.json +19 -18
  54. package/quickjs.sh +1 -0
  55. package/dist/lib/iterable/weakmap.js +0 -53
  56. package/dist/lib/renderer/utils/color.js +0 -499
  57. /package/dist/lib/iterable/{set.js → weakset.js} +0 -0
@@ -1,24 +1,15 @@
1
- import { isPseudo, isAtKeyword, isFunction, isNumber, isDimension, parseDimension, isPercentage, isIdent, isHexColor, isHash, isIdentStart, isColor } from './utils/syntax.js';
2
- import { EnumToken } from '../ast/types.js';
1
+ import { isPseudo, isAtKeyword, isFunction, isNumber, isPercentage, isFlex, isDimension, parseDimension, isIdent, isHexColor, isHash, isIdentStart, isColor } from './utils/syntax.js';
2
+ import { EnumToken, funcLike } from '../ast/types.js';
3
3
  import { minify, combinators } from '../ast/minify.js';
4
4
  import { walkValues, walk } from '../ast/walk.js';
5
5
  import { expand } from '../ast/expand.js';
6
+ import { parseDeclaration } from './utils/declaration.js';
6
7
  import { renderToken } from '../renderer/render.js';
7
- import { COLORS_NAMES } from '../renderer/utils/color.js';
8
+ import { COLORS_NAMES } from '../renderer/color/utils/constants.js';
8
9
  import { tokenize } from './tokenize.js';
9
10
 
10
11
  const urlTokenMatcher = /^(["']?)[a-zA-Z0-9_/.-][a-zA-Z0-9_/:.#?-]+(\1)$/;
11
12
  const trimWhiteSpace = [EnumToken.CommentTokenType, EnumToken.GtTokenType, EnumToken.GteTokenType, EnumToken.LtTokenType, EnumToken.LteTokenType, EnumToken.ColumnCombinatorTokenType];
12
- const funcLike = [
13
- EnumToken.ParensTokenType,
14
- EnumToken.FunctionTokenType,
15
- EnumToken.UrlFunctionTokenType,
16
- EnumToken.StartParensTokenType,
17
- EnumToken.ImageFunctionTokenType,
18
- EnumToken.PseudoClassFuncTokenType,
19
- EnumToken.TimingFunctionTokenType,
20
- EnumToken.TimingFunctionTokenType
21
- ];
22
13
  const BadTokensTypes = [
23
14
  EnumToken.BadCommentTokenType,
24
15
  EnumToken.BadCdoTokenType,
@@ -37,6 +28,7 @@ async function doParse(iterator, options = {}) {
37
28
  src: '',
38
29
  sourcemap: false,
39
30
  minify: true,
31
+ parseColor: true,
40
32
  nestingRules: false,
41
33
  resolveImport: false,
42
34
  resolveUrls: false,
@@ -58,13 +50,19 @@ async function doParse(iterator, options = {}) {
58
50
  const errors = [];
59
51
  const src = options.src;
60
52
  const stack = [];
53
+ const stats = {
54
+ bytesIn: 0,
55
+ importedBytesIn: 0,
56
+ parse: `0ms`,
57
+ minify: `0ms`,
58
+ total: `0ms`
59
+ };
61
60
  let ast = {
62
61
  typ: EnumToken.StyleSheetNodeType,
63
62
  chi: []
64
63
  };
65
64
  let tokens = [];
66
65
  let map = new Map;
67
- let bytesIn = 0;
68
66
  let context = ast;
69
67
  if (options.sourcemap) {
70
68
  ast.loc = {
@@ -76,315 +74,21 @@ async function doParse(iterator, options = {}) {
76
74
  src: ''
77
75
  };
78
76
  }
79
- async function parseNode(results) {
80
- let tokens = results.map(mapToken);
81
- let i;
82
- let loc;
83
- for (i = 0; i < tokens.length; i++) {
84
- if (tokens[i].typ == EnumToken.CommentTokenType || tokens[i].typ == EnumToken.CDOCOMMTokenType) {
85
- const position = map.get(tokens[i]);
86
- if (tokens[i].typ == EnumToken.CDOCOMMTokenType && context.typ != EnumToken.StyleSheetNodeType) {
87
- errors.push({
88
- action: 'drop',
89
- message: `CDOCOMM not allowed here ${JSON.stringify(tokens[i], null, 1)}`,
90
- location: { src, ...position }
91
- });
92
- continue;
93
- }
94
- loc = {
95
- sta: position,
96
- src
97
- };
98
- // @ts-ignore
99
- context.chi.push(tokens[i]);
100
- if (options.sourcemap) {
101
- tokens[i].loc = loc;
102
- }
103
- }
104
- else if (tokens[i].typ != EnumToken.WhitespaceTokenType) {
105
- break;
106
- }
107
- }
108
- tokens = tokens.slice(i);
109
- if (tokens.length == 0) {
110
- return null;
111
- }
112
- let delim = tokens.at(-1);
113
- if (delim.typ == EnumToken.SemiColonTokenType || delim.typ == EnumToken.BlockStartTokenType || delim.typ == EnumToken.BlockEndTokenType) {
114
- tokens.pop();
115
- }
116
- else {
117
- delim = { typ: EnumToken.SemiColonTokenType };
118
- }
119
- // @ts-ignore
120
- while ([EnumToken.WhitespaceTokenType, EnumToken.BadStringTokenType, EnumToken.BadCommentTokenType].includes(tokens.at(-1)?.typ)) {
121
- tokens.pop();
122
- }
123
- if (tokens.length == 0) {
124
- return null;
125
- }
126
- if (tokens[0]?.typ == EnumToken.AtRuleTokenType) {
127
- const atRule = tokens.shift();
128
- const position = map.get(atRule);
129
- if (atRule.val == 'charset') {
130
- if (position.ind > 0) {
131
- errors.push({
132
- action: 'drop',
133
- message: 'doParse: invalid @charset',
134
- location: { src, ...position }
135
- });
136
- return null;
137
- }
138
- if (options.removeCharset) {
139
- return null;
140
- }
141
- }
142
- // @ts-ignore
143
- while ([EnumToken.WhitespaceTokenType].includes(tokens[0]?.typ)) {
144
- tokens.shift();
145
- }
146
- if (atRule.val == 'import') {
147
- // only @charset and @layer are accepted before @import
148
- if (context.chi.length > 0) {
149
- let i = context.chi.length;
150
- while (i--) {
151
- const type = context.chi[i].typ;
152
- if (type == EnumToken.CommentNodeType) {
153
- continue;
154
- }
155
- if (type != EnumToken.AtRuleNodeType) {
156
- errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } });
157
- return null;
158
- }
159
- const name = context.chi[i].nam;
160
- if (name != 'charset' && name != 'import' && name != 'layer') {
161
- errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } });
162
- return null;
163
- }
164
- break;
165
- }
166
- }
167
- // @ts-ignore
168
- if (tokens[0]?.typ != EnumToken.StringTokenType && tokens[0]?.typ != EnumToken.UrlFunctionTokenType) {
169
- errors.push({
170
- action: 'drop',
171
- message: 'doParse: invalid @import',
172
- location: { src, ...position }
173
- });
174
- return null;
175
- }
176
- // @ts-ignore
177
- if (tokens[0].typ == EnumToken.UrlFunctionTokenType && tokens[1]?.typ != EnumToken.UrlTokenTokenType && tokens[1]?.typ != EnumToken.StringTokenType) {
178
- errors.push({
179
- action: 'drop',
180
- message: 'doParse: invalid @import',
181
- location: { src, ...position }
182
- });
183
- return null;
184
- }
185
- }
186
- if (atRule.val == 'import') {
187
- // @ts-ignore
188
- if (tokens[0].typ == EnumToken.UrlFunctionTokenType && tokens[1].typ == EnumToken.UrlTokenTokenType) {
189
- tokens.shift();
190
- // @ts-ignore
191
- tokens[0].typ = EnumToken.StringTokenType;
192
- // @ts-ignore
193
- tokens[0].val = `"${tokens[0].val}"`;
194
- }
195
- // @ts-ignore
196
- if (tokens[0].typ == EnumToken.StringTokenType) {
197
- if (options.resolveImport) {
198
- const url = tokens[0].val.slice(1, -1);
199
- try {
200
- // @ts-ignore
201
- const root = await options.load(url, options.src).then((src) => {
202
- return doParse(src, Object.assign({}, options, {
203
- minify: false,
204
- // @ts-ignore
205
- src: options.resolve(url, options.src).absolute
206
- }));
207
- });
208
- bytesIn += root.stats.bytesIn;
209
- if (root.ast.chi.length > 0) {
210
- // @todo - filter charset, layer and scope
211
- context.chi.push(...root.ast.chi);
212
- }
213
- if (root.errors.length > 0) {
214
- errors.push(...root.errors);
215
- }
216
- return null;
217
- }
218
- catch (error) {
219
- // @ts-ignore
220
- errors.push({ action: 'ignore', message: 'doParse: ' + error.message, error });
221
- }
222
- }
223
- }
224
- }
225
- // https://www.w3.org/TR/css-nesting-1/#conditionals
226
- // allowed nesting at-rules
227
- // there must be a top level rule in the stack
228
- const raw = parseTokens(tokens, { minify: options.minify }).reduce((acc, curr) => {
229
- acc.push(renderToken(curr, { removeComments: true }));
230
- return acc;
231
- }, []);
232
- const node = {
233
- typ: EnumToken.AtRuleNodeType,
234
- nam: renderToken(atRule, { removeComments: true }),
235
- val: raw.join('')
236
- };
237
- Object.defineProperty(node, 'raw', { enumerable: false, configurable: true, writable: true, value: raw });
238
- if (delim.typ == EnumToken.BlockStartTokenType) {
239
- node.chi = [];
240
- }
241
- loc = {
242
- sta: position,
243
- src
244
- };
245
- if (options.sourcemap) {
246
- node.loc = loc;
247
- }
248
- // @ts-ignore
249
- context.chi.push(node);
250
- return delim.typ == EnumToken.BlockStartTokenType ? node : null;
251
- }
252
- else {
253
- // rule
254
- if (delim.typ == EnumToken.BlockStartTokenType) {
255
- const position = map.get(tokens[0]);
256
- const uniq = new Map;
257
- parseTokens(tokens, { minify: true }).reduce((acc, curr, index, array) => {
258
- if (curr.typ == EnumToken.WhitespaceTokenType) {
259
- if (trimWhiteSpace.includes(array[index - 1]?.typ) ||
260
- trimWhiteSpace.includes(array[index + 1]?.typ) ||
261
- combinators.includes(array[index - 1]?.val) ||
262
- combinators.includes(array[index + 1]?.val)) {
263
- return acc;
264
- }
265
- }
266
- let t = renderToken(curr, { minify: false });
267
- if (t == ',') {
268
- acc.push([]);
269
- }
270
- else {
271
- acc[acc.length - 1].push(t);
272
- }
273
- return acc;
274
- }, [[]]).reduce((acc, curr) => {
275
- acc.set(curr.join(''), curr);
276
- return acc;
277
- }, uniq);
278
- const node = {
279
- typ: EnumToken.RuleNodeType,
280
- // @ts-ignore
281
- sel: [...uniq.keys()].join(','),
282
- chi: []
283
- };
284
- let raw = [...uniq.values()];
285
- Object.defineProperty(node, 'raw', {
286
- enumerable: false,
287
- configurable: true,
288
- writable: true,
289
- value: raw
290
- });
291
- loc = {
292
- sta: position,
293
- src
294
- };
295
- if (options.sourcemap) {
296
- node.loc = loc;
297
- }
298
- // @ts-ignore
299
- context.chi.push(node);
300
- return node;
301
- }
302
- else {
303
- // declaration
304
- // @ts-ignore
305
- let name = null;
306
- // @ts-ignore
307
- let value = null;
308
- for (let i = 0; i < tokens.length; i++) {
309
- if (tokens[i].typ == EnumToken.CommentTokenType) {
310
- continue;
311
- }
312
- if (tokens[i].typ == EnumToken.ColonTokenType) {
313
- name = tokens.slice(0, i);
314
- value = parseTokens(tokens.slice(i + 1), {
315
- parseColor: true,
316
- src: options.src,
317
- resolveUrls: options.resolveUrls,
318
- resolve: options.resolve,
319
- cwd: options.cwd
320
- });
321
- }
322
- }
323
- if (name == null) {
324
- name = tokens;
325
- }
326
- const position = map.get(name[0]);
327
- if (name.length > 0) {
328
- for (let i = 1; i < name.length; i++) {
329
- if (name[i].typ != EnumToken.WhitespaceTokenType && name[i].typ != EnumToken.CommentTokenType) {
330
- errors.push({
331
- action: 'drop',
332
- message: 'doParse: invalid declaration',
333
- location: { src, ...position }
334
- });
335
- return null;
336
- }
337
- }
338
- }
339
- if (value == null || value.length == 0) {
340
- errors.push({
341
- action: 'drop',
342
- message: 'doParse: invalid declaration',
343
- location: { src, ...position }
344
- });
345
- return null;
346
- }
347
- const node = {
348
- typ: EnumToken.DeclarationNodeType,
349
- // @ts-ignore
350
- nam: renderToken(name.shift(), { removeComments: true }),
351
- // @ts-ignore
352
- val: value
353
- };
354
- while (node.val[0]?.typ == EnumToken.WhitespaceTokenType) {
355
- node.val.shift();
356
- }
357
- if (node.val.length == 0) {
358
- errors.push({
359
- action: 'drop',
360
- message: 'doParse: invalid declaration',
361
- location: { src, ...position }
362
- });
363
- return null;
364
- }
365
- // @ts-ignore
366
- context.chi.push(node);
367
- return null;
368
- }
369
- }
370
- }
371
- function mapToken(token) {
372
- const node = getTokenType(token.token, token.hint);
373
- map.set(node, token.position);
374
- return node;
375
- }
376
77
  const iter = tokenize(iterator);
377
78
  let item;
378
79
  while (item = iter.next().value) {
379
- bytesIn = item.bytesIn;
80
+ stats.bytesIn = item.bytesIn;
81
+ //
380
82
  // doParse error
381
83
  if (item.hint != null && BadTokensTypes.includes(item.hint)) {
382
84
  // bad token
383
85
  continue;
384
86
  }
385
- tokens.push(item);
87
+ if (item.hint != EnumToken.EOFTokenType) {
88
+ tokens.push(item);
89
+ }
386
90
  if (item.token == ';' || item.token == '{') {
387
- let node = await parseNode(tokens);
91
+ let node = await parseNode(tokens, context, stats, options, errors, src, map);
388
92
  if (node != null) {
389
93
  stack.push(node);
390
94
  // @ts-ignore
@@ -411,7 +115,7 @@ async function doParse(iterator, options = {}) {
411
115
  map = new Map;
412
116
  }
413
117
  else if (item.token == '}') {
414
- await parseNode(tokens);
118
+ await parseNode(tokens, context, stats, options, errors, src, map);
415
119
  const previousNode = stack.pop();
416
120
  // @ts-ignore
417
121
  context = stack[stack.length - 1] || ast;
@@ -424,12 +128,12 @@ async function doParse(iterator, options = {}) {
424
128
  }
425
129
  }
426
130
  if (tokens.length > 0) {
427
- await parseNode(tokens);
131
+ await parseNode(tokens, context, stats, options, errors, src, map);
428
132
  }
429
133
  while (stack.length > 0 && context != ast) {
430
134
  const previousNode = stack.pop();
431
135
  // @ts-ignore
432
- context = stack[stack.length - 1] || ast;
136
+ context = stack[stack.length - 1] ?? ast;
433
137
  // @ts-ignore
434
138
  if (options.removeEmpty && previousNode != null && previousNode.chi.length == 0 && context.chi[context.chi.length - 1] == previousNode) {
435
139
  context.chi.pop();
@@ -447,7 +151,7 @@ async function doParse(iterator, options = {}) {
447
151
  // @ts-ignore
448
152
  (typeof options.visitor.Declaration == 'function' || options.visitor.Declaration?.[result.node.nam] != null)) {
449
153
  const callable = typeof options.visitor.Declaration == 'function' ? options.visitor.Declaration : options.visitor.Declaration[result.node.nam];
450
- const results = callable(result.node);
154
+ const results = await callable(result.node);
451
155
  if (results == null || (Array.isArray(results) && results.length == 0)) {
452
156
  continue;
453
157
  }
@@ -455,7 +159,7 @@ async function doParse(iterator, options = {}) {
455
159
  result.parent.chi.splice(result.parent.chi.indexOf(result.node), 1, ...(Array.isArray(results) ? results : [results]));
456
160
  }
457
161
  else if (options.visitor.Rule != null && result.node.typ == EnumToken.RuleNodeType) {
458
- const results = options.visitor.Rule(result.node);
162
+ const results = await options.visitor.Rule(result.node);
459
163
  if (results == null || (Array.isArray(results) && results.length == 0)) {
460
164
  continue;
461
165
  }
@@ -467,7 +171,7 @@ async function doParse(iterator, options = {}) {
467
171
  // @ts-ignore
468
172
  (typeof options.visitor.AtRule == 'function' || options.visitor.AtRule?.[result.node.nam] != null)) {
469
173
  const callable = typeof options.visitor.AtRule == 'function' ? options.visitor.AtRule : options.visitor.AtRule[result.node.nam];
470
- const results = callable(result.node);
174
+ const results = await callable(result.node);
471
175
  if (results == null || (Array.isArray(results) && results.length == 0)) {
472
176
  continue;
473
177
  }
@@ -485,11 +189,12 @@ async function doParse(iterator, options = {}) {
485
189
  if (options.signal != null) {
486
190
  options.signal.removeEventListener('abort', reject);
487
191
  }
192
+ stats.bytesIn += stats.importedBytesIn;
488
193
  resolve({
489
194
  ast,
490
195
  errors,
491
196
  stats: {
492
- bytesIn,
197
+ ...stats,
493
198
  parse: `${(endParseTime - startTime).toFixed(2)}ms`,
494
199
  minify: `${(endTime - endParseTime).toFixed(2)}ms`,
495
200
  total: `${(endTime - startTime).toFixed(2)}ms`
@@ -497,6 +202,295 @@ async function doParse(iterator, options = {}) {
497
202
  });
498
203
  });
499
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
+ }
500
494
  function parseString(src, options = { location: false }) {
501
495
  return parseTokens([...tokenize(src)].map(t => {
502
496
  const token = getTokenType(t.token, t.hint);
@@ -620,15 +614,21 @@ function getTokenType(val, hint) {
620
614
  val
621
615
  };
622
616
  }
623
- if (isDimension(val)) {
624
- return parseDimension(val);
625
- }
626
617
  if (isPercentage(val)) {
627
618
  return {
628
619
  typ: EnumToken.PercentageTokenType,
629
620
  val: val.slice(0, -1)
630
621
  };
631
622
  }
623
+ if (isFlex(val)) {
624
+ return {
625
+ typ: EnumToken.FlexTokenType,
626
+ val: val.slice(0, -2)
627
+ };
628
+ }
629
+ if (isDimension(val)) {
630
+ return parseDimension(val);
631
+ }
632
632
  const v = val.toLowerCase();
633
633
  if (v == 'currentcolor' || val == 'transparent' || v in COLORS_NAMES) {
634
634
  return {
@@ -728,15 +728,6 @@ function parseTokens(tokens, options = {}) {
728
728
  // @ts-ignore
729
729
  parseTokens(t.chi, t.typ);
730
730
  }
731
- // @ts-ignore
732
- // t.chi.forEach(val => {
733
- // if (val.typ == EnumToken.StringTokenType) {
734
- // const slice = val.val.slice(1, -1);
735
- // if ((slice.charAt(0) != '-' || (slice.charAt(0) == '-' && isIdentStart(slice.charCodeAt(1)))) && isIdent(slice)) {
736
- // Object.assign(val, {typ: EnumToken.IdenTokenType, val: slice});
737
- // }
738
- // }
739
- // });
740
731
  let m = t.chi.length;
741
732
  let val;
742
733
  for (m = 0; m < t.chi.length; m++) {
@@ -871,6 +862,11 @@ function parseTokens(tokens, options = {}) {
871
862
  // @ts-ignore
872
863
  t.chi.pop();
873
864
  }
865
+ // @ts-ignore
866
+ if (t.chi.length > 0) {
867
+ // @ts-ignore
868
+ parseTokens(t.chi, options);
869
+ }
874
870
  if (t.typ == EnumToken.FunctionTokenType && t.val == 'calc') {
875
871
  for (const { value, parent } of walkValues(t.chi)) {
876
872
  if (value.typ == EnumToken.WhitespaceTokenType) {
@@ -893,35 +889,37 @@ function parseTokens(tokens, options = {}) {
893
889
  }
894
890
  }
895
891
  }
892
+ else if (t.typ == EnumToken.FunctionTokenType && ['minmax', 'fit-content', 'repeat'].includes(t.val)) {
893
+ // @ts-ignore
894
+ t.typ = EnumToken.GridTemplateFuncTokenType;
895
+ }
896
896
  else if (t.typ == EnumToken.StartParensTokenType) {
897
897
  // @ts-ignore
898
898
  t.typ = EnumToken.ParensTokenType;
899
899
  }
900
900
  // @ts-ignore
901
901
  if (options.parseColor && t.typ == EnumToken.FunctionTokenType && isColor(t)) {
902
- // if (isColor) {
903
902
  // @ts-ignore
904
903
  t.typ = EnumToken.ColorTokenType;
905
904
  // @ts-ignore
906
905
  t.kin = t.val;
907
- // @ts-ignore
908
- let m = t.chi.length;
909
- while (m-- > 0) {
906
+ if (t.chi[0].typ == EnumToken.IdenTokenType) {
907
+ if (t.chi[0].val == 'from') {
908
+ // @ts-ignore
909
+ t.cal = 'rel';
910
+ }
910
911
  // @ts-ignore
911
- if ([EnumToken.LiteralTokenType].concat(trimWhiteSpace).includes(t.chi[m].typ)) {
912
+ else if (t.val == 'color-mix' && t.chi[0].val == 'in') {
912
913
  // @ts-ignore
913
- if (t.chi[m + 1]?.typ == EnumToken.WhitespaceTokenType) {
914
- // @ts-ignore
915
- t.chi.splice(m + 1, 1);
916
- }
914
+ t.cal = 'mix';
915
+ }
916
+ else if (t.val == 'color') {
917
917
  // @ts-ignore
918
- if (t.chi[m - 1]?.typ == EnumToken.WhitespaceTokenType) {
919
- // @ts-ignore
920
- t.chi.splice(m - 1, 1);
921
- m--;
922
- }
918
+ t.cal = 'col';
919
+ // t.chi = t.chi.filter((t: Token) => [EnumToken.IdenTokenType, EnumToken.NumberTokenType, EnumToken.PercentageTokenType].includes(t.typ));
923
920
  }
924
921
  }
922
+ t.chi = t.chi.filter((t) => ![EnumToken.WhitespaceTokenType, EnumToken.CommaTokenType, EnumToken.CommentTokenType].includes(t.typ));
925
923
  continue;
926
924
  }
927
925
  if (t.typ == EnumToken.UrlFunctionTokenType) {
@@ -946,8 +944,6 @@ function parseTokens(tokens, options = {}) {
946
944
  }
947
945
  // @ts-ignore
948
946
  if (t.chi.length > 0) {
949
- // @ts-ignore
950
- parseTokens(t.chi, options);
951
947
  if (t.typ == EnumToken.PseudoClassFuncTokenType && t.val == ':is' && options.minify) {
952
948
  //
953
949
  const count = t.chi.filter(t => t.typ != EnumToken.CommentTokenType).length;