@tbela99/css-parser 0.2.0 → 0.3.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.
@@ -1,3 +1,5 @@
1
+ import { EnumToken } from './types.js';
2
+
1
3
  function* walk(node, filter) {
2
4
  const parents = [node];
3
5
  const root = node;
@@ -27,20 +29,38 @@ function* walk(node, filter) {
27
29
  }
28
30
  }
29
31
  }
30
- function* walkValues(values) {
32
+ function* walkValues(values, root = null, filter) {
31
33
  const stack = values.slice();
32
34
  const weakMap = new WeakMap;
33
35
  let value;
34
36
  while (stack.length > 0) {
35
37
  value = stack.shift();
38
+ let option = null;
39
+ if (filter != null) {
40
+ option = filter(value);
41
+ if (option === 'ignore') {
42
+ continue;
43
+ }
44
+ if (option === 'stop') {
45
+ break;
46
+ }
47
+ }
36
48
  // @ts-ignore
37
- yield { value, parent: weakMap.get(value) };
38
- if ('chi' in value) {
39
- for (const child of value.chi) {
49
+ if (option !== 'children') {
50
+ // @ts-ignore
51
+ yield { value, parent: weakMap.get(value), root };
52
+ }
53
+ if (option !== 'ignore-children' && 'chi' in value) {
54
+ for (const child of value.chi.slice()) {
40
55
  weakMap.set(child, value);
41
56
  }
42
57
  stack.unshift(...value.chi);
43
58
  }
59
+ else if (value.typ == EnumToken.BinaryExpressionTokenType) {
60
+ weakMap.set(value.l, value);
61
+ weakMap.set(value.r, value);
62
+ stack.unshift(value.l, value.r);
63
+ }
44
64
  }
45
65
  }
46
66
 
@@ -35,13 +35,14 @@ function splitPath(result) {
35
35
  parts[parts.length - 1] += chr;
36
36
  }
37
37
  }
38
- let k = parts.length;
39
- while (k--) {
38
+ let k = -1;
39
+ while (++k < parts.length) {
40
40
  if (parts[k] == '.') {
41
- parts.splice(k, 1);
41
+ parts.splice(k--, 1);
42
42
  }
43
43
  else if (parts[k] == '..') {
44
44
  parts.splice(k - 1, 2);
45
+ k -= 2;
45
46
  }
46
47
  }
47
48
  return { parts, i };
@@ -0,0 +1,48 @@
1
+ class IterableWeakSet {
2
+ #weakset = new WeakSet;
3
+ #set = new Set;
4
+ constructor(iterable) {
5
+ if (iterable) {
6
+ for (const value of iterable) {
7
+ const ref = new WeakRef(value);
8
+ this.#weakset.add(value);
9
+ this.#set.add(ref);
10
+ }
11
+ }
12
+ }
13
+ has(value) {
14
+ return this.#weakset.has(value);
15
+ }
16
+ delete(value) {
17
+ if (this.#weakset.has(value)) {
18
+ for (const ref of this.#set) {
19
+ if (ref.deref() === value) {
20
+ this.#set.delete(ref);
21
+ break;
22
+ }
23
+ }
24
+ return this.#weakset.delete(value);
25
+ }
26
+ return false;
27
+ }
28
+ add(value) {
29
+ if (!this.#weakset.has(value)) {
30
+ this.#weakset.add(value);
31
+ this.#set.add(new WeakRef(value));
32
+ }
33
+ return this;
34
+ }
35
+ *[Symbol.iterator]() {
36
+ for (const ref of new Set(this.#set)) {
37
+ const key = ref.deref();
38
+ if (key != null) {
39
+ yield key;
40
+ }
41
+ else {
42
+ this.#set.delete(ref);
43
+ }
44
+ }
45
+ }
46
+ }
47
+
48
+ export { IterableWeakSet };
@@ -21,7 +21,11 @@ class PropertyList {
21
21
  this.declarations = new Map;
22
22
  }
23
23
  set(nam, value) {
24
- return this.add({ typ: EnumToken.DeclarationNodeType, nam, val: Array.isArray(value) ? value : parseString(String(value)) });
24
+ return this.add({
25
+ typ: EnumToken.DeclarationNodeType,
26
+ nam,
27
+ val: Array.isArray(value) ? value : parseString(String(value))
28
+ });
25
29
  }
26
30
  add(declaration) {
27
31
  if (declaration.typ != EnumToken.DeclarationNodeType || !this.options.removeDuplicateDeclarations) {
@@ -7,9 +7,7 @@ import { parseString } from '../parse.js';
7
7
  import { getConfig } from '../utils/config.js';
8
8
  import { matchType } from '../utils/type.js';
9
9
  import { PropertySet } from './set.js';
10
- import { IterableWeakMap } from '../../iterable/weakmap.js';
11
10
 
12
- const cache = new IterableWeakMap();
13
11
  const propertiesConfig = getConfig();
14
12
  class PropertyMap {
15
13
  config;
@@ -195,15 +193,29 @@ class PropertyMap {
195
193
  }
196
194
  if (!isShorthand || requiredCount < this.requiredCount) {
197
195
  if (isShorthand && this.declarations.has(this.config.shorthand)) {
198
- // console.debug(...this.declarations.values());
196
+ const cache = new Map();
199
197
  const removeDefaults = (declaration) => {
200
- // const dec: AstDeclaration = {...declaration};
201
- const config = this.config.shorthand == declaration.nam ? this.config : this.config.properties[declaration.nam];
202
- declaration.val = declaration.val.filter((val) => {
203
- if (!cache.has(val)) {
204
- cache.set(val, renderToken(val, { minify: true }));
198
+ let config = this.config.shorthand == declaration.nam ? this.config : this.config.properties[declaration.nam];
199
+ if (config == null && declaration.nam in propertiesConfig.properties) {
200
+ // @ts-ignore
201
+ const shorthand = propertiesConfig.properties[declaration.nam].shorthand;
202
+ // @ts-ignore
203
+ config = propertiesConfig.properties[shorthand];
204
+ }
205
+ declaration.val = declaration.val.map((t) => {
206
+ if (!cache.has(t)) {
207
+ cache.set(t, renderToken(t, { minify: true }));
205
208
  }
206
- return !config.default.includes(cache.get(val));
209
+ const value = cache.get(t);
210
+ // @ts-ignore
211
+ if (config?.mapping?.[value] != null) {
212
+ // @ts-ignore
213
+ t = parseString(config.mapping[value])[0];
214
+ cache.set(t, renderToken(t, { minify: true }));
215
+ }
216
+ return t;
217
+ }).filter((val) => {
218
+ return !config?.default?.includes(cache.get(val));
207
219
  })
208
220
  .filter((val, index, array) => !(index > 0 &&
209
221
  val.typ == EnumToken.WhitespaceTokenType &&
@@ -222,13 +234,24 @@ class PropertyMap {
222
234
  }
223
235
  return acc;
224
236
  }, []);
225
- const filtered = values.map(removeDefaults).filter((x) => x.val.length > 0);
237
+ let isImportant = false;
238
+ const filtered = values.map(removeDefaults).filter((x) => x.val.filter((t) => {
239
+ if (t.typ == EnumToken.ImportantTokenType) {
240
+ isImportant = true;
241
+ }
242
+ return ![EnumToken.WhitespaceTokenType, EnumToken.ImportantTokenType].includes(t.typ);
243
+ }).length > 0);
226
244
  if (filtered.length == 0 && this.config.default.length > 0) {
227
245
  filtered.push({
228
246
  typ: EnumToken.DeclarationNodeType,
229
247
  nam: this.config.shorthand,
230
248
  val: parseString(this.config.default[0])
231
249
  });
250
+ if (isImportant) {
251
+ filtered[0].val.push({
252
+ typ: EnumToken.ImportantTokenType
253
+ });
254
+ }
232
255
  }
233
256
  return (filtered.length > 0 ? filtered : values)[Symbol.iterator]();
234
257
  }
@@ -324,7 +347,9 @@ class PropertyMap {
324
347
  }, []);
325
348
  // @todo remove renderToken call
326
349
  if (props.default.includes(curr[1][i].reduce((acc, curr) => acc + renderToken(curr) + ' ', '').trimEnd())) {
327
- continue;
350
+ if (!this.config.properties[curr[0]].required) {
351
+ continue;
352
+ }
328
353
  }
329
354
  // remove default values
330
355
  let doFilterDefault = true;
@@ -338,12 +363,15 @@ class PropertyMap {
338
363
  }
339
364
  }
340
365
  // remove default values
341
- values = values.filter((val) => {
366
+ const filtered = values.filter((val) => {
342
367
  if (val.typ == EnumToken.WhitespaceTokenType || val.typ == EnumToken.CommentTokenType) {
343
368
  return false;
344
369
  }
345
370
  return !doFilterDefault || !(val.typ == EnumToken.IdenTokenType && props.default.includes(val.val));
346
371
  });
372
+ if (filtered.length > 0 || !(this.requiredCount == requiredCount && this.config.properties[curr[0]].required)) {
373
+ values = filtered;
374
+ }
347
375
  if (values.length > 0) {
348
376
  if ('mapping' in props) {
349
377
  // @ts-ignore
@@ -399,7 +427,10 @@ class PropertyMap {
399
427
  return acc;
400
428
  }, []);
401
429
  if (this.config.mapping != null) {
402
- const val = values.reduce((acc, curr) => acc + renderToken(curr, { removeComments: true, minify: true }), '');
430
+ const val = values.reduce((acc, curr) => acc + renderToken(curr, {
431
+ removeComments: true,
432
+ minify: true
433
+ }), '');
403
434
  if (val in this.config.mapping) {
404
435
  values.length = 0;
405
436
  values.push({
@@ -6,6 +6,29 @@ import '../parse.js';
6
6
  import '../../renderer/utils/color.js';
7
7
  import '../../renderer/sourcemap/lib/encode.js';
8
8
 
9
+ function dedup(values) {
10
+ for (const value of values) {
11
+ let i = value.length;
12
+ while (i-- > 1) {
13
+ const t = value[i];
14
+ const k = value[i == 1 ? 0 : i % 2];
15
+ if (t.val == k.val && t.val == '0') {
16
+ if ((t.typ == EnumToken.NumberTokenType && isLength(k)) ||
17
+ (k.typ == EnumToken.NumberTokenType && isLength(t)) ||
18
+ (isLength(k) || isLength(t))) {
19
+ value.splice(i, 1);
20
+ continue;
21
+ }
22
+ }
23
+ if (eq(t, k)) {
24
+ value.splice(i, 1);
25
+ continue;
26
+ }
27
+ break;
28
+ }
29
+ }
30
+ return values;
31
+ }
9
32
  class PropertySet {
10
33
  config;
11
34
  declarations;
@@ -100,7 +123,23 @@ class PropertySet {
100
123
  let iterator;
101
124
  const declarations = this.declarations;
102
125
  if (declarations.size < this.config.properties.length) {
103
- iterator = declarations.values();
126
+ const values = [...declarations.values()];
127
+ if (this.isShortHand()) {
128
+ const val = values[0].val.reduce((acc, curr) => {
129
+ if (![EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType].includes(curr.typ)) {
130
+ acc.push(curr);
131
+ }
132
+ return acc;
133
+ }, []);
134
+ values[0].val = val.reduce((acc, curr) => {
135
+ if (acc.length > 0) {
136
+ acc.push({ typ: EnumToken.WhitespaceTokenType });
137
+ }
138
+ acc.push(curr);
139
+ return acc;
140
+ }, []);
141
+ }
142
+ return values[Symbol.iterator]();
104
143
  }
105
144
  else {
106
145
  const values = [];
@@ -118,26 +157,7 @@ class PropertySet {
118
157
  index++;
119
158
  }
120
159
  });
121
- for (const value of values) {
122
- let i = value.length;
123
- while (i-- > 1) {
124
- const t = value[i];
125
- const k = value[i == 1 ? 0 : i % 2];
126
- if (t.val == k.val && t.val == '0') {
127
- if ((t.typ == EnumToken.NumberTokenType && isLength(k)) ||
128
- (k.typ == EnumToken.NumberTokenType && isLength(t)) ||
129
- (isLength(k) || isLength(t))) {
130
- value.splice(i, 1);
131
- continue;
132
- }
133
- }
134
- if (eq(t, k)) {
135
- value.splice(i, 1);
136
- continue;
137
- }
138
- break;
139
- }
140
- }
160
+ dedup(values);
141
161
  iterator = [{
142
162
  typ: EnumToken.DeclarationNodeType,
143
163
  nam: this.config.shorthand,
@@ -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
8
  import { COLORS_NAMES } from '../renderer/utils/color.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,
@@ -312,7 +304,7 @@ async function doParse(iterator, options = {}) {
312
304
  if (tokens[i].typ == EnumToken.ColonTokenType) {
313
305
  name = tokens.slice(0, i);
314
306
  value = parseTokens(tokens.slice(i + 1), {
315
- parseColor: true,
307
+ parseColor: options.parseColor,
316
308
  src: options.src,
317
309
  resolveUrls: options.resolveUrls,
318
310
  resolve: options.resolve,
@@ -351,19 +343,11 @@ async function doParse(iterator, options = {}) {
351
343
  // @ts-ignore
352
344
  val: value
353
345
  };
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;
346
+ const result = parseDeclaration(node, errors, src, position);
347
+ if (result != null) {
348
+ // @ts-ignore
349
+ context.chi.push(node);
364
350
  }
365
- // @ts-ignore
366
- context.chi.push(node);
367
351
  return null;
368
352
  }
369
353
  }
@@ -620,15 +604,21 @@ function getTokenType(val, hint) {
620
604
  val
621
605
  };
622
606
  }
623
- if (isDimension(val)) {
624
- return parseDimension(val);
625
- }
626
607
  if (isPercentage(val)) {
627
608
  return {
628
609
  typ: EnumToken.PercentageTokenType,
629
610
  val: val.slice(0, -1)
630
611
  };
631
612
  }
613
+ if (isFlex(val)) {
614
+ return {
615
+ typ: EnumToken.FlexTokenType,
616
+ val: val.slice(0, -2)
617
+ };
618
+ }
619
+ if (isDimension(val)) {
620
+ return parseDimension(val);
621
+ }
632
622
  const v = val.toLowerCase();
633
623
  if (v == 'currentcolor' || val == 'transparent' || v in COLORS_NAMES) {
634
624
  return {
@@ -728,15 +718,6 @@ function parseTokens(tokens, options = {}) {
728
718
  // @ts-ignore
729
719
  parseTokens(t.chi, t.typ);
730
720
  }
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
721
  let m = t.chi.length;
741
722
  let val;
742
723
  for (m = 0; m < t.chi.length; m++) {
@@ -871,6 +852,11 @@ function parseTokens(tokens, options = {}) {
871
852
  // @ts-ignore
872
853
  t.chi.pop();
873
854
  }
855
+ // @ts-ignore
856
+ if (t.chi.length > 0) {
857
+ // @ts-ignore
858
+ parseTokens(t.chi, options);
859
+ }
874
860
  if (t.typ == EnumToken.FunctionTokenType && t.val == 'calc') {
875
861
  for (const { value, parent } of walkValues(t.chi)) {
876
862
  if (value.typ == EnumToken.WhitespaceTokenType) {
@@ -893,35 +879,25 @@ function parseTokens(tokens, options = {}) {
893
879
  }
894
880
  }
895
881
  }
882
+ else if (t.typ == EnumToken.FunctionTokenType && ['minmax', 'fit-content', 'repeat'].includes(t.val)) {
883
+ // @ts-ignore
884
+ t.typ = EnumToken.GridTemplateFuncTokenType;
885
+ }
896
886
  else if (t.typ == EnumToken.StartParensTokenType) {
897
887
  // @ts-ignore
898
888
  t.typ = EnumToken.ParensTokenType;
899
889
  }
900
890
  // @ts-ignore
901
891
  if (options.parseColor && t.typ == EnumToken.FunctionTokenType && isColor(t)) {
902
- // if (isColor) {
903
892
  // @ts-ignore
904
893
  t.typ = EnumToken.ColorTokenType;
905
894
  // @ts-ignore
906
895
  t.kin = t.val;
907
- // @ts-ignore
908
- let m = t.chi.length;
909
- while (m-- > 0) {
896
+ if (t.chi[0].typ == EnumToken.IdenTokenType && t.chi[0].val == 'from') {
910
897
  // @ts-ignore
911
- if ([EnumToken.LiteralTokenType].concat(trimWhiteSpace).includes(t.chi[m].typ)) {
912
- // @ts-ignore
913
- if (t.chi[m + 1]?.typ == EnumToken.WhitespaceTokenType) {
914
- // @ts-ignore
915
- t.chi.splice(m + 1, 1);
916
- }
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
- }
923
- }
898
+ t.cal = 'rel';
924
899
  }
900
+ t.chi = t.chi.filter((t) => ![EnumToken.WhitespaceTokenType, EnumToken.CommaTokenType, EnumToken.CommentTokenType].includes(t.typ));
925
901
  continue;
926
902
  }
927
903
  if (t.typ == EnumToken.UrlFunctionTokenType) {
@@ -946,8 +922,6 @@ function parseTokens(tokens, options = {}) {
946
922
  }
947
923
  // @ts-ignore
948
924
  if (t.chi.length > 0) {
949
- // @ts-ignore
950
- parseTokens(t.chi, options);
951
925
  if (t.typ == EnumToken.PseudoClassFuncTokenType && t.val == ':is' && options.minify) {
952
926
  //
953
927
  const count = t.chi.filter(t => t.typ != EnumToken.CommentTokenType).length;
@@ -0,0 +1,67 @@
1
+ import { EnumToken } from '../../ast/types.js';
2
+ import '../../ast/minify.js';
3
+ import { walkValues } from '../../ast/walk.js';
4
+ import '../parse.js';
5
+ import { isWhiteSpace } from './syntax.js';
6
+ import '../../renderer/utils/color.js';
7
+ import '../../renderer/sourcemap/lib/encode.js';
8
+
9
+ function parseDeclaration(node, errors, src, position) {
10
+ while (node.val[0]?.typ == EnumToken.WhitespaceTokenType) {
11
+ node.val.shift();
12
+ }
13
+ if (node.val.filter((t) => ![EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType].includes(t.typ)).length == 0) {
14
+ errors.push({
15
+ action: 'drop',
16
+ message: 'doParse: invalid declaration',
17
+ location: { src, ...position }
18
+ });
19
+ return null;
20
+ }
21
+ for (const { value: val, parent } of walkValues(node.val, node)) {
22
+ if (val.typ == EnumToken.AttrTokenType && val.chi.every((t) => [EnumToken.IdenTokenType, EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType].includes(t.typ))) {
23
+ // @ts-ignore
24
+ val.typ = EnumToken.IdenListTokenType;
25
+ }
26
+ else if (val.typ == EnumToken.StringTokenType && (node.nam == 'grid' || node.nam == 'grid-template-areas' || node.nam == 'grid-template-rows' || node.nam == 'grid-template-columns')) {
27
+ val.val = val.val.at(0) + parseGridTemplate(val.val.slice(1, -1)) + val.val.at(-1);
28
+ // @ts-ignore
29
+ const array = parent?.chi ?? node.val;
30
+ const index = array.indexOf(val);
31
+ if (index > 0 && array[index - 1].typ == EnumToken.WhitespaceTokenType) {
32
+ array.splice(index - 1, 1);
33
+ }
34
+ }
35
+ }
36
+ return node;
37
+ }
38
+ function parseGridTemplate(template) {
39
+ let result = '';
40
+ let buffer = '';
41
+ for (let i = 0; i < template.length; i++) {
42
+ const char = template[i];
43
+ if (isWhiteSpace(char.codePointAt(0))) {
44
+ while (i + 1 < template.length && isWhiteSpace(template[i + 1].codePointAt(0))) {
45
+ i++;
46
+ }
47
+ result += buffer + ' ';
48
+ buffer = '';
49
+ }
50
+ else if (char == '.') {
51
+ while (i + 1 < template.length && template[i + 1] == '.') {
52
+ i++;
53
+ }
54
+ if (isWhiteSpace((result.at(-1)?.codePointAt(0)))) {
55
+ result = result.slice(0, -1);
56
+ }
57
+ result += buffer + char;
58
+ buffer = '';
59
+ }
60
+ else {
61
+ buffer += char;
62
+ }
63
+ }
64
+ return buffer.length > 0 ? result + buffer : result;
65
+ }
66
+
67
+ export { parseDeclaration };
@@ -37,10 +37,37 @@ function isColor(token) {
37
37
  // named color
38
38
  return token.val.toLowerCase() in COLORS_NAMES;
39
39
  }
40
+ let isLegacySyntax = false;
40
41
  if (token.typ == EnumToken.FunctionTokenType && token.chi.length > 0 && colorsFunc.includes(token.val)) {
42
+ const keywords = ['from', 'none'];
43
+ if (['rgb', 'hsl', 'hwb'].includes(token.val)) {
44
+ keywords.push('a', ...token.val.split(''));
45
+ }
46
+ // console.debug(JSON.stringify({token}, null, 1));
41
47
  // @ts-ignore
42
48
  for (const v of token.chi) {
43
- if (![EnumToken.NumberTokenType, EnumToken.AngleTokenType, EnumToken.PercentageTokenType, EnumToken.CommaTokenType, EnumToken.WhitespaceTokenType, EnumToken.LiteralTokenType].includes(v.typ)) {
49
+ // console.debug(JSON.stringify({v}, null, 1));
50
+ if (v.typ == EnumToken.CommaTokenType) {
51
+ isLegacySyntax = true;
52
+ }
53
+ if (v.typ == EnumToken.IdenTokenType) {
54
+ if (!(keywords.includes(v.val) || v.val.toLowerCase() in COLORS_NAMES)) {
55
+ return false;
56
+ }
57
+ if (keywords.includes(v.val)) {
58
+ if (isLegacySyntax) {
59
+ return false;
60
+ }
61
+ if (v.val == 'from' && ['rgba', 'hsla'].includes(token.val)) {
62
+ return false;
63
+ }
64
+ }
65
+ continue;
66
+ }
67
+ if (v.typ == EnumToken.FunctionTokenType && (v.val == 'calc' || colorsFunc.includes(v.val))) {
68
+ continue;
69
+ }
70
+ if (![EnumToken.ColorTokenType, EnumToken.IdenTokenType, EnumToken.NumberTokenType, EnumToken.AngleTokenType, EnumToken.PercentageTokenType, EnumToken.CommaTokenType, EnumToken.WhitespaceTokenType, EnumToken.LiteralTokenType].includes(v.typ)) {
44
71
  return false;
45
72
  }
46
73
  }
@@ -200,6 +227,9 @@ function isDimension(name) {
200
227
  function isPercentage(name) {
201
228
  return name.endsWith('%') && isNumber(name.slice(0, -1));
202
229
  }
230
+ function isFlex(name) {
231
+ return name.endsWith('fr') && isNumber(name.slice(0, -2));
232
+ }
203
233
  function parseDimension(name) {
204
234
  let index = name.length;
205
235
  while (index--) {
@@ -267,4 +297,4 @@ function isWhiteSpace(codepoint) {
267
297
  codepoint == 0xa || codepoint == 0xc || codepoint == 0xd;
268
298
  }
269
299
 
270
- export { isAngle, isAtKeyword, isColor, isDigit, isDimension, isFrequency, isFunction, isHash, isHexColor, isIdent, isIdentCodepoint, isIdentStart, isLength, isNewLine, isNonPrintable, isNumber, isPercentage, isPseudo, isResolution, isTime, isWhiteSpace, parseDimension };
300
+ export { isAngle, isAtKeyword, isColor, isDigit, isDimension, isFlex, isFrequency, isFunction, isHash, isHexColor, isIdent, isIdentCodepoint, isIdentStart, isLength, isNewLine, isNonPrintable, isNumber, isPercentage, isPseudo, isResolution, isTime, isWhiteSpace, parseDimension };