@tbela99/css-parser 0.8.0 → 0.9.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 (64) hide show
  1. package/.editorconfig +484 -0
  2. package/README.md +13 -8
  3. package/dist/index-umd-web.js +2451 -2554
  4. package/dist/index.cjs +2605 -2708
  5. package/dist/index.d.ts +73 -23
  6. package/dist/lib/ast/expand.js +29 -4
  7. package/dist/lib/ast/math/expression.js +1 -1
  8. package/dist/lib/ast/minify.js +31 -17
  9. package/dist/lib/ast/types.js +2 -0
  10. package/dist/lib/ast/walk.js +12 -0
  11. package/dist/lib/parser/declaration/map.js +59 -52
  12. package/dist/lib/parser/declaration/set.js +0 -12
  13. package/dist/lib/parser/parse.js +204 -139
  14. package/dist/lib/parser/tokenize.js +15 -3
  15. package/dist/lib/renderer/color/color.js +2 -2
  16. package/dist/lib/renderer/color/hex.js +1 -1
  17. package/dist/lib/renderer/color/hsl.js +1 -1
  18. package/dist/lib/renderer/color/hwb.js +2 -2
  19. package/dist/lib/renderer/color/lab.js +3 -2
  20. package/dist/lib/renderer/color/lch.js +1 -1
  21. package/dist/lib/renderer/color/oklab.js +2 -2
  22. package/dist/lib/renderer/color/oklch.js +1 -1
  23. package/dist/lib/renderer/color/p3.js +1 -1
  24. package/dist/lib/renderer/color/prophotoRgb.js +2 -2
  25. package/dist/lib/renderer/color/prophotorgb.js +2 -2
  26. package/dist/lib/renderer/color/rgb.js +1 -1
  27. package/dist/lib/renderer/color/srgb.js +2 -2
  28. package/dist/lib/renderer/color/utils/constants.js +1 -1
  29. package/dist/lib/renderer/color/xyz.js +2 -18
  30. package/dist/lib/renderer/color/xyzd50.js +20 -2
  31. package/dist/lib/renderer/render.js +37 -8
  32. package/dist/lib/renderer/sourcemap/sourcemap.js +1 -1
  33. package/dist/lib/syntax/syntax.js +337 -1
  34. package/dist/lib/validation/at-rules/container.js +353 -0
  35. package/dist/lib/validation/at-rules/counter-style.js +2 -2
  36. package/dist/lib/validation/at-rules/custom-media.js +52 -0
  37. package/dist/lib/validation/at-rules/document.js +40 -60
  38. package/dist/lib/validation/at-rules/else.js +5 -0
  39. package/dist/lib/validation/at-rules/font-feature-values.js +3 -0
  40. package/dist/lib/validation/at-rules/import.js +64 -59
  41. package/dist/lib/validation/at-rules/layer.js +3 -0
  42. package/dist/lib/validation/at-rules/media.js +118 -29
  43. package/dist/lib/validation/at-rules/supports.js +51 -20
  44. package/dist/lib/validation/at-rules/when.js +178 -0
  45. package/dist/lib/validation/atrule.js +25 -10
  46. package/dist/lib/validation/config.js +20 -15
  47. package/dist/lib/validation/config.json.js +242 -74
  48. package/dist/lib/validation/declaration.js +32 -10
  49. package/dist/lib/validation/parser/parse.js +87 -103
  50. package/dist/lib/validation/parser/types.js +2 -2
  51. package/dist/lib/validation/selector.js +6 -3
  52. package/dist/lib/validation/syntax.js +86 -6
  53. package/dist/lib/validation/syntaxes/complex-selector-list.js +16 -12
  54. package/dist/lib/validation/syntaxes/complex-selector.js +17 -247
  55. package/dist/lib/validation/syntaxes/compound-selector.js +226 -0
  56. package/dist/lib/validation/syntaxes/image.js +29 -0
  57. package/dist/lib/validation/syntaxes/keyframe-block-list.js +1 -1
  58. package/dist/lib/validation/syntaxes/keyframe-selector.js +1 -1
  59. package/dist/lib/validation/syntaxes/layer-name.js +5 -16
  60. package/dist/lib/validation/syntaxes/relative-selector-list.js +43 -13
  61. package/dist/lib/validation/utils/list.js +2 -2
  62. package/dist/node/index.js +1 -1
  63. package/dist/web/index.js +1 -1
  64. package/package.json +10 -9
@@ -1,15 +1,14 @@
1
1
  import { ValidationLevel, EnumToken } from '../../ast/types.js';
2
2
  import '../../ast/minify.js';
3
3
  import '../../ast/walk.js';
4
- import '../../parser/parse.js';
4
+ import { parseSelector } from '../../parser/parse.js';
5
5
  import { colorFontTech, fontFeaturesTech, fontFormat } from '../../syntax/syntax.js';
6
6
  import '../../parser/utils/config.js';
7
7
  import '../../renderer/color/utils/constants.js';
8
8
  import '../../renderer/sourcemap/lib/encode.js';
9
9
  import { consumeWhitespace } from '../utils/whitespace.js';
10
10
  import { splitTokenList } from '../utils/list.js';
11
- import { validateSyntax } from '../syntax.js';
12
- import { getParsedSyntax } from '../config.js';
11
+ import { validateComplexSelector } from '../syntaxes/complex-selector.js';
13
12
 
14
13
  function validateAtRuleSupports(atRule, options, root) {
15
14
  // media-query-list
@@ -19,7 +18,7 @@ function validateAtRuleSupports(atRule, options, root) {
19
18
  valid: ValidationLevel.Drop,
20
19
  matches: [],
21
20
  node: atRule,
22
- syntax: '@supports',
21
+ syntax: '@' + atRule.nam,
23
22
  error: 'expected supports query list',
24
23
  tokens: []
25
24
  };
@@ -37,7 +36,7 @@ function validateAtRuleSupports(atRule, options, root) {
37
36
  valid: ValidationLevel.Drop,
38
37
  matches: [],
39
38
  node: atRule,
40
- syntax: '@supports',
39
+ syntax: '@' + atRule.nam,
41
40
  error: 'expected at-rule body',
42
41
  tokens: []
43
42
  };
@@ -47,12 +46,13 @@ function validateAtRuleSupports(atRule, options, root) {
47
46
  valid: ValidationLevel.Valid,
48
47
  matches: [],
49
48
  node: atRule,
50
- syntax: '@supports',
49
+ syntax: '@' + atRule.nam,
51
50
  error: '',
52
51
  tokens: []
53
52
  };
54
53
  }
55
54
  function validateAtRuleSupportsConditions(atRule, tokenList) {
55
+ let result = null;
56
56
  for (const tokens of splitTokenList(tokenList)) {
57
57
  if (tokens.length == 0) {
58
58
  // @ts-ignore
@@ -60,28 +60,52 @@ function validateAtRuleSupportsConditions(atRule, tokenList) {
60
60
  valid: ValidationLevel.Drop,
61
61
  matches: [],
62
62
  node: tokens[0] ?? atRule,
63
- syntax: '@supports',
63
+ syntax: '@' + atRule.nam,
64
64
  error: 'unexpected token',
65
65
  tokens: []
66
66
  };
67
67
  }
68
68
  let previousToken = null;
69
- let result = null;
70
69
  while (tokens.length > 0) {
71
70
  result = validateSupportCondition(atRule, tokens[0]);
72
71
  // supports-condition
73
- if (result == null || result.valid == ValidationLevel.Valid) {
72
+ if (result.valid == ValidationLevel.Valid) {
74
73
  previousToken = tokens[0];
75
74
  tokens.shift();
76
75
  }
77
76
  else {
78
77
  result = validateSupportFeature(tokens[0]);
79
- if (result == null || result.valid == ValidationLevel.Valid) {
78
+ if ( /*result == null || */result.valid == ValidationLevel.Valid) {
80
79
  previousToken = tokens[0];
81
80
  tokens.shift();
82
81
  }
83
82
  else {
84
- return result;
83
+ if (tokens[0].typ == EnumToken.ParensTokenType) {
84
+ result = validateAtRuleSupportsConditions(atRule, tokens[0].chi);
85
+ if ( /* result == null || */result.valid == ValidationLevel.Valid) {
86
+ previousToken = tokens[0];
87
+ tokens.shift();
88
+ // continue;
89
+ }
90
+ else {
91
+ return result;
92
+ }
93
+ }
94
+ else {
95
+ return result;
96
+ }
97
+ // if (result!= null && result.valid == ValidationLevel.Drop) {
98
+ //
99
+ // return {
100
+ // valid: ValidationLevel.Drop,
101
+ // matches: [],
102
+ // node: tokens[0] ?? atRule,
103
+ // syntax: '@' + atRule.nam,
104
+ // // @ts-ignore
105
+ // error: result.error as string ?? 'unexpected token',
106
+ // tokens: []
107
+ // };
108
+ // }
85
109
  }
86
110
  }
87
111
  if (tokens.length == 0) {
@@ -94,7 +118,7 @@ function validateAtRuleSupportsConditions(atRule, tokenList) {
94
118
  valid: ValidationLevel.Drop,
95
119
  matches: [],
96
120
  node: tokens[0] ?? previousToken ?? atRule,
97
- syntax: '@supports',
121
+ syntax: '@' + atRule.nam,
98
122
  error: 'expected whitespace',
99
123
  tokens: []
100
124
  };
@@ -106,7 +130,7 @@ function validateAtRuleSupportsConditions(atRule, tokenList) {
106
130
  valid: ValidationLevel.Drop,
107
131
  matches: [],
108
132
  node: tokens[0] ?? atRule,
109
- syntax: '@supports',
133
+ syntax: '@' + atRule.nam,
110
134
  error: 'expected and/or',
111
135
  tokens: []
112
136
  };
@@ -117,7 +141,7 @@ function validateAtRuleSupportsConditions(atRule, tokenList) {
117
141
  valid: ValidationLevel.Drop,
118
142
  matches: [],
119
143
  node: tokens[0] ?? atRule,
120
- syntax: '@supports',
144
+ syntax: '@' + atRule.nam,
121
145
  error: 'expected supports-condition',
122
146
  tokens: []
123
147
  };
@@ -129,26 +153,33 @@ function validateAtRuleSupportsConditions(atRule, tokenList) {
129
153
  valid: ValidationLevel.Drop,
130
154
  matches: [],
131
155
  node: tokens[0] ?? atRule,
132
- syntax: '@supports',
156
+ syntax: '@' + atRule.nam,
133
157
  error: 'expected whitespace',
134
158
  tokens: []
135
159
  };
136
160
  }
137
161
  }
138
162
  }
139
- return null;
163
+ return {
164
+ valid: ValidationLevel.Valid,
165
+ matches: [],
166
+ node: atRule,
167
+ syntax: '@' + atRule.nam,
168
+ error: '',
169
+ tokens: []
170
+ };
140
171
  }
141
172
  function validateSupportCondition(atRule, token) {
142
173
  if (token.typ == EnumToken.MediaFeatureNotTokenType) {
143
174
  return validateSupportCondition(atRule, token.val);
144
175
  }
145
- if (token.typ != EnumToken.ParensTokenType) {
176
+ if (token.typ != EnumToken.ParensTokenType && !(['when', 'else'].includes(atRule.nam) && token.typ == EnumToken.FunctionTokenType && ['supports', 'font-format', 'font-tech'].includes(token.val))) {
146
177
  // @ts-ignore
147
178
  return {
148
179
  valid: ValidationLevel.Drop,
149
180
  matches: [],
150
181
  node: token,
151
- syntax: '@supports',
182
+ syntax: '@' + atRule.nam,
152
183
  error: 'expected supports condition-in-parens',
153
184
  tokens: []
154
185
  };
@@ -163,7 +194,7 @@ function validateSupportCondition(atRule, token) {
163
194
  valid: ValidationLevel.Valid,
164
195
  matches: [],
165
196
  node: null,
166
- syntax: '@supports',
197
+ syntax: '@' + atRule.nam,
167
198
  error: '',
168
199
  tokens: []
169
200
  };
@@ -203,7 +234,7 @@ function validateSupportCondition(atRule, token) {
203
234
  function validateSupportFeature(token) {
204
235
  if (token.typ == EnumToken.FunctionTokenType) {
205
236
  if (token.val.localeCompare('selector', undefined, { sensitivity: 'base' }) == 0) {
206
- return validateSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, 'complex-selector'), token.chi);
237
+ return validateComplexSelector(parseSelector(token.chi));
207
238
  }
208
239
  if (token.val.localeCompare('font-tech', undefined, { sensitivity: 'base' }) == 0) {
209
240
  const chi = token.chi.filter((t) => ![EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType].includes(t.typ));
@@ -0,0 +1,178 @@
1
+ import { ValidationLevel, EnumToken } from '../../ast/types.js';
2
+ import '../../ast/minify.js';
3
+ import '../../ast/walk.js';
4
+ import '../../parser/parse.js';
5
+ import '../../renderer/color/utils/constants.js';
6
+ import '../../renderer/sourcemap/lib/encode.js';
7
+ import '../../parser/utils/config.js';
8
+ import { consumeWhitespace } from '../utils/whitespace.js';
9
+ import { splitTokenList } from '../utils/list.js';
10
+ import { validateMediaFeature, validateMediaCondition } from './media.js';
11
+ import { validateSupportCondition } from './supports.js';
12
+
13
+ function validateAtRuleWhen(atRule, options, root) {
14
+ const slice = Array.isArray(atRule.tokens) ? atRule.tokens.slice() : [];
15
+ consumeWhitespace(slice);
16
+ if (slice.length == 0) {
17
+ // @ts-ignore
18
+ return {
19
+ valid: ValidationLevel.Valid,
20
+ matches: [],
21
+ node: atRule,
22
+ syntax: '@when',
23
+ error: '',
24
+ tokens: []
25
+ };
26
+ }
27
+ const result = validateAtRuleWhenQueryList(atRule.tokens, atRule);
28
+ if (result.valid == ValidationLevel.Drop) {
29
+ return result;
30
+ }
31
+ if (!('chi' in atRule)) {
32
+ // @ts-ignore
33
+ return {
34
+ valid: ValidationLevel.Drop,
35
+ matches: [],
36
+ node: atRule,
37
+ syntax: '@when',
38
+ error: 'expected at-rule body',
39
+ tokens: []
40
+ };
41
+ }
42
+ return {
43
+ valid: ValidationLevel.Valid,
44
+ matches: [],
45
+ node: atRule,
46
+ syntax: '@when',
47
+ error: '',
48
+ tokens: result.tokens
49
+ };
50
+ }
51
+ // media() = media( [ <mf-plain> | <mf-boolean> | <mf-range> ] )
52
+ // supports() = supports( <declaration> )
53
+ function validateAtRuleWhenQueryList(tokenList, atRule) {
54
+ const matched = [];
55
+ let result = null;
56
+ for (const split of splitTokenList(tokenList)) {
57
+ const match = [];
58
+ result = null;
59
+ consumeWhitespace(split);
60
+ if (split.length == 0) {
61
+ continue;
62
+ }
63
+ while (split.length > 0) {
64
+ if (split[0].typ != EnumToken.FunctionTokenType || !['media', 'supports', 'font-tech', 'font-format'].includes(split[0].val)) {
65
+ result = {
66
+ valid: ValidationLevel.Drop,
67
+ matches: [],
68
+ node: split[0] ?? atRule,
69
+ syntax: '@when',
70
+ error: 'unexpected token',
71
+ tokens: []
72
+ };
73
+ break;
74
+ }
75
+ const chi = split[0].chi.slice();
76
+ consumeWhitespace(chi);
77
+ if (split[0].val == 'media') {
78
+ // result = valida
79
+ if (chi.length != 1 || !(validateMediaFeature(chi[0]) || validateMediaCondition(split[0], atRule))) {
80
+ result = {
81
+ valid: ValidationLevel.Drop,
82
+ matches: [],
83
+ node: split[0] ?? atRule,
84
+ syntax: 'media( [ <mf-plain> | <mf-boolean> | <mf-range> ] )',
85
+ error: 'unexpected token',
86
+ tokens: []
87
+ };
88
+ break;
89
+ }
90
+ }
91
+ else if (['supports', 'font-tech', 'font-format'].includes(split[0].val)) {
92
+ // result = valida
93
+ if (!validateSupportCondition(atRule, split[0])) {
94
+ result = {
95
+ valid: ValidationLevel.Drop,
96
+ matches: [],
97
+ node: split[0] ?? atRule,
98
+ syntax: 'media( [ <mf-plain> | <mf-boolean> | <mf-range> ] )',
99
+ error: 'unexpected token',
100
+ tokens: []
101
+ };
102
+ break;
103
+ }
104
+ }
105
+ if (match.length > 0) {
106
+ match.push({ typ: EnumToken.WhitespaceTokenType });
107
+ }
108
+ match.push(split.shift());
109
+ consumeWhitespace(split);
110
+ if (split.length == 0) {
111
+ break;
112
+ }
113
+ if (![EnumToken.MediaFeatureAndTokenType, EnumToken.MediaFeatureOrTokenType].includes(split[0].typ)) {
114
+ result = {
115
+ valid: ValidationLevel.Drop,
116
+ matches: [],
117
+ node: split[0] ?? atRule,
118
+ syntax: '@when',
119
+ error: 'expecting and/or media-condition',
120
+ tokens: []
121
+ };
122
+ break;
123
+ }
124
+ if (match.length > 0) {
125
+ match.push({ typ: EnumToken.WhitespaceTokenType });
126
+ }
127
+ match.push(split.shift());
128
+ consumeWhitespace(split);
129
+ if (split.length == 0) {
130
+ result = {
131
+ valid: ValidationLevel.Drop,
132
+ matches: [],
133
+ node: split[0] ?? atRule,
134
+ syntax: '@when',
135
+ error: 'expecting media-condition',
136
+ tokens: []
137
+ };
138
+ break;
139
+ }
140
+ }
141
+ if (result == null && match.length > 0) {
142
+ matched.push(match);
143
+ }
144
+ }
145
+ if (result != null) {
146
+ return result;
147
+ }
148
+ if (matched.length == 0) {
149
+ return {
150
+ valid: ValidationLevel.Drop,
151
+ matches: [],
152
+ // @ts-ignore
153
+ node: result?.node ?? atRule,
154
+ syntax: '@when',
155
+ error: 'invalid at-rule body',
156
+ tokens: []
157
+ };
158
+ }
159
+ tokenList.length = 0;
160
+ for (const match of matched) {
161
+ if (tokenList.length > 0) {
162
+ tokenList.push({
163
+ typ: EnumToken.CommaTokenType
164
+ });
165
+ }
166
+ tokenList.push(...match);
167
+ }
168
+ return {
169
+ valid: ValidationLevel.Valid,
170
+ matches: [],
171
+ node: atRule,
172
+ syntax: '@when',
173
+ error: '',
174
+ tokens: tokenList
175
+ };
176
+ }
177
+
178
+ export { validateAtRuleWhen, validateAtRuleWhenQueryList };
@@ -5,7 +5,7 @@ import '../parser/parse.js';
5
5
  import '../renderer/color/utils/constants.js';
6
6
  import '../renderer/sourcemap/lib/encode.js';
7
7
  import '../parser/utils/config.js';
8
- import { getParsedSyntax, getSyntaxConfig } from './config.js';
8
+ import { getSyntaxConfig, getParsedSyntax } from './config.js';
9
9
  import { validateAtRuleMedia } from './at-rules/media.js';
10
10
  import { validateAtRuleCounterStyle } from './at-rules/counter-style.js';
11
11
  import { validateAtRulePage } from './at-rules/page.js';
@@ -17,6 +17,10 @@ import { validateAtRuleFontFeatureValues } from './at-rules/font-feature-values.
17
17
  import { validateAtRuleNamespace } from './at-rules/namespace.js';
18
18
  import { validateAtRuleDocument } from './at-rules/document.js';
19
19
  import { validateAtRuleKeyframes } from './at-rules/keyframes.js';
20
+ import { validateAtRuleWhen } from './at-rules/when.js';
21
+ import { validateAtRuleElse } from './at-rules/else.js';
22
+ import { validateAtRuleContainer } from './at-rules/container.js';
23
+ import { validateAtRuleCustomMedia } from './at-rules/custom-media.js';
20
24
 
21
25
  function validateAtRule(atRule, options, root) {
22
26
  if (atRule.nam == 'charset') {
@@ -60,9 +64,21 @@ function validateAtRule(atRule, options, root) {
60
64
  if (atRule.nam == 'namespace') {
61
65
  return validateAtRuleNamespace(atRule);
62
66
  }
67
+ if (atRule.nam == 'when') {
68
+ return validateAtRuleWhen(atRule);
69
+ }
70
+ if (atRule.nam == 'else') {
71
+ return validateAtRuleElse(atRule);
72
+ }
73
+ if (atRule.nam == 'container') {
74
+ return validateAtRuleContainer(atRule);
75
+ }
63
76
  if (atRule.nam == 'document') {
64
77
  return validateAtRuleDocument(atRule);
65
78
  }
79
+ if (atRule.nam == 'custom-media') {
80
+ return validateAtRuleCustomMedia(atRule);
81
+ }
66
82
  if (['position-try', 'property', 'font-palette-values'].includes(atRule.nam)) {
67
83
  if (!('tokens' in atRule)) {
68
84
  return {
@@ -132,15 +148,14 @@ function validateAtRule(atRule, options, root) {
132
148
  }
133
149
  }
134
150
  if (!(name in config.atRules)) {
135
- // if (root?.typ == EnumToken.AtRuleNodeType) {
136
- //
137
- // const syntaxes: ValidationToken = (getParsedSyntax(ValidationSyntaxGroupEnum.AtRules, '@' + (root as AstAtRule).nam) as ValidationToken[])?.[0];
138
- //
139
- // if ('chi' in syntaxes) {
140
- //
141
- // return validateSyntax(syntaxes.chi as ValidationToken[], [atRule], root, options);
142
- // }
143
- // }
151
+ if (options.lenient) {
152
+ return {
153
+ valid: ValidationLevel.Lenient,
154
+ node: atRule,
155
+ syntax: null,
156
+ error: ''
157
+ };
158
+ }
144
159
  return {
145
160
  valid: ValidationLevel.Drop,
146
161
  node: atRule,
@@ -1,6 +1,6 @@
1
1
  import config from './config.json.js';
2
2
  import './parser/types.js';
3
- import { parseSyntax, walkValidationToken, renderSyntax } from './parser/parse.js';
3
+ import { parseSyntax } from './parser/parse.js';
4
4
 
5
5
  const parsedSyntaxes = new Map();
6
6
  Object.freeze(config);
@@ -9,25 +9,30 @@ function getSyntaxConfig() {
9
9
  return config;
10
10
  }
11
11
  function getParsedSyntax(group, key) {
12
- if (!(key in config[group])) {
13
- const matches = key.match(/(@?)(-[a-zA-Z]+)-(.*?)$/);
14
- if (matches != null) {
15
- key = matches[1] + matches[3];
16
- }
17
- if (!(key in config[group])) {
18
- return null;
12
+ // @ts-ignore
13
+ let obj = config[group];
14
+ const keys = Array.isArray(key) ? key : [key];
15
+ for (let i = 0; i < keys.length; i++) {
16
+ key = keys[i];
17
+ if (!(key in obj)) {
18
+ if ((i == 0 && key.charAt(0) == '@') || key.charAt(0) == '-') {
19
+ const matches = key.match(/^(@?)(-[a-zA-Z]+)-(.*?)$/);
20
+ if (matches != null) {
21
+ key = matches[1] + matches[3];
22
+ }
23
+ }
24
+ if (!(key in obj)) {
25
+ return null;
26
+ }
19
27
  }
28
+ // @ts-ignore
29
+ obj = obj[key];
20
30
  }
21
- const index = group + '.' + key;
31
+ const index = group + '.' + keys.join('.');
22
32
  // @ts-ignore
23
33
  if (!parsedSyntaxes.has(index)) {
24
34
  // @ts-ignore
25
- const syntax = parseSyntax(config[group][key].syntax);
26
- for (const node of syntax.chi) {
27
- for (const { token, parent } of walkValidationToken(node)) {
28
- token.text = renderSyntax(token);
29
- }
30
- }
35
+ const syntax = parseSyntax(obj.syntax);
31
36
  // @ts-ignore
32
37
  parsedSyntaxes.set(index, syntax.chi);
33
38
  }