@tbela99/css-parser 0.1.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.
Files changed (40) hide show
  1. package/README.md +267 -2
  2. package/dist/config.json.js +611 -4
  3. package/dist/index-umd-web.js +2898 -1223
  4. package/dist/index.cjs +2898 -1223
  5. package/dist/lib/ast/expand.js +11 -11
  6. package/dist/lib/ast/features/calc.js +33 -224
  7. package/dist/lib/ast/features/index.js +3 -3
  8. package/dist/lib/ast/features/inlinecssvariables.js +46 -31
  9. package/dist/lib/ast/features/shorthand.js +7 -7
  10. package/dist/lib/ast/features/utils/math.js +95 -0
  11. package/dist/lib/ast/math/expression.js +185 -0
  12. package/dist/lib/ast/math/math.js +95 -0
  13. package/dist/lib/ast/minify.js +34 -29
  14. package/dist/lib/ast/types.js +108 -78
  15. package/dist/lib/ast/walk.js +42 -9
  16. package/dist/lib/fs/resolve.js +4 -3
  17. package/dist/lib/iterable/set.js +48 -0
  18. package/dist/lib/iterable/weakmap.js +53 -0
  19. package/dist/lib/iterable/weakset.js +48 -0
  20. package/dist/lib/parser/declaration/list.js +7 -3
  21. package/dist/lib/parser/declaration/map.js +86 -7
  22. package/dist/lib/parser/declaration/set.js +43 -23
  23. package/dist/lib/parser/parse.js +561 -387
  24. package/dist/lib/parser/tokenize.js +42 -13
  25. package/dist/lib/parser/utils/declaration.js +67 -0
  26. package/dist/lib/parser/utils/syntax.js +32 -2
  27. package/dist/lib/parser/utils/type.js +7 -2
  28. package/dist/lib/renderer/render.js +163 -47
  29. package/dist/lib/renderer/utils/calccolor.js +238 -0
  30. package/dist/lib/renderer/utils/color.js +36 -164
  31. package/dist/lib/renderer/utils/hex.js +124 -0
  32. package/dist/lib/renderer/utils/hsl.js +49 -0
  33. package/dist/lib/renderer/utils/hsv.js +15 -0
  34. package/dist/lib/renderer/utils/hwb.js +50 -0
  35. package/dist/lib/renderer/utils/rgb.js +66 -0
  36. package/dist/node/index.js +8 -12
  37. package/dist/web/index.js +8 -12
  38. package/package.json +9 -7
  39. package/dist/index.d.ts +0 -1056
  40. /package/dist/lib/ast/{utiles → utils}/minifyfeature.js +0 -0
@@ -1,258 +1,235 @@
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
- import { walkValues } from '../ast/walk.js';
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
- const trimWhiteSpace = [EnumToken.GtTokenType, EnumToken.GteTokenType, EnumToken.LtTokenType, EnumToken.LteTokenType];
12
- const funcLike = [EnumToken.ParensTokenType, EnumToken.StartParensTokenType, EnumToken.FunctionTokenType, EnumToken.UrlFunctionTokenType, EnumToken.PseudoClassFuncTokenType];
13
- const BadTokensTypes = [EnumToken.BadCommentTokenType,
12
+ const trimWhiteSpace = [EnumToken.CommentTokenType, EnumToken.GtTokenType, EnumToken.GteTokenType, EnumToken.LtTokenType, EnumToken.LteTokenType, EnumToken.ColumnCombinatorTokenType];
13
+ const BadTokensTypes = [
14
+ EnumToken.BadCommentTokenType,
14
15
  EnumToken.BadCdoTokenType,
15
16
  EnumToken.BadUrlTokenType,
16
- EnumToken.BadStringTokenType];
17
+ EnumToken.BadStringTokenType
18
+ ];
19
+ const webkitPseudoAliasMap = {
20
+ '-webkit-autofill': 'autofill'
21
+ };
17
22
  async function doParse(iterator, options = {}) {
18
- options = {
19
- src: '',
20
- sourcemap: false,
21
- minify: true,
22
- nestingRules: false,
23
- resolveImport: false,
24
- resolveUrls: false,
25
- removeCharset: false,
26
- removeEmpty: true,
27
- removeDuplicateDeclarations: true,
28
- computeShorthand: true,
29
- computeCalcExpression: true,
30
- inlineCssVariables: false,
31
- ...options
32
- };
33
- if (options.expandNestingRules) {
34
- options.nestingRules = false;
35
- }
36
- if (options.resolveImport) {
37
- options.resolveUrls = true;
38
- }
39
- const startTime = performance.now();
40
- const errors = [];
41
- const src = options.src;
42
- const stack = [];
43
- let ast = {
44
- typ: 2 /* NodeType.StyleSheetNodeType */,
45
- chi: []
46
- };
47
- let tokens = [];
48
- let map = new Map;
49
- let bytesIn = 0;
50
- let context = ast;
51
- if (options.sourcemap) {
52
- ast.loc = {
53
- sta: {
54
- ind: 0,
55
- lin: 1,
56
- col: 1
57
- },
58
- src: ''
59
- };
60
- }
61
- async function parseNode(results) {
62
- let tokens = results.map(mapToken);
63
- let i;
64
- let loc;
65
- for (i = 0; i < tokens.length; i++) {
66
- if (tokens[i].typ == EnumToken.CommentTokenType || tokens[i].typ == EnumToken.CDOCOMMTokenType) {
67
- const position = map.get(tokens[i]);
68
- if (tokens[i].typ == EnumToken.CDOCOMMTokenType && context.typ != 2 /* NodeType.StyleSheetNodeType */) {
69
- errors.push({
70
- action: 'drop',
71
- message: `CDOCOMM not allowed here ${JSON.stringify(tokens[i], null, 1)}`,
72
- location: { src, ...position }
73
- });
74
- continue;
75
- }
76
- loc = {
77
- sta: position,
78
- src
79
- };
80
- // @ts-ignore
81
- context.chi.push(tokens[i]);
82
- if (options.sourcemap) {
83
- tokens[i].loc = loc;
84
- }
85
- }
86
- else if (tokens[i].typ != EnumToken.WhitespaceTokenType) {
87
- break;
88
- }
89
- }
90
- tokens = tokens.slice(i);
91
- if (tokens.length == 0) {
92
- return null;
23
+ return new Promise(async (resolve, reject) => {
24
+ if (options.signal != null) {
25
+ options.signal.addEventListener('abort', reject);
93
26
  }
94
- let delim = tokens.at(-1);
95
- if (delim.typ == EnumToken.SemiColonTokenType || delim.typ == EnumToken.BlockStartTokenType || delim.typ == EnumToken.BlockEndTokenType) {
96
- tokens.pop();
97
- }
98
- else {
99
- delim = { typ: EnumToken.SemiColonTokenType };
27
+ options = {
28
+ src: '',
29
+ sourcemap: false,
30
+ minify: true,
31
+ parseColor: true,
32
+ nestingRules: false,
33
+ resolveImport: false,
34
+ resolveUrls: false,
35
+ removeCharset: false,
36
+ removeEmpty: true,
37
+ removeDuplicateDeclarations: true,
38
+ computeShorthand: true,
39
+ computeCalcExpression: true,
40
+ inlineCssVariables: false,
41
+ ...options
42
+ };
43
+ if (options.expandNestingRules) {
44
+ options.nestingRules = false;
100
45
  }
101
- // @ts-ignore
102
- while ([EnumToken.WhitespaceTokenType, EnumToken.BadStringTokenType, EnumToken.BadCommentTokenType].includes(tokens.at(-1)?.typ)) {
103
- tokens.pop();
46
+ if (options.resolveImport) {
47
+ options.resolveUrls = true;
104
48
  }
105
- if (tokens.length == 0) {
106
- return null;
49
+ const startTime = performance.now();
50
+ const errors = [];
51
+ const src = options.src;
52
+ const stack = [];
53
+ let ast = {
54
+ typ: EnumToken.StyleSheetNodeType,
55
+ chi: []
56
+ };
57
+ let tokens = [];
58
+ let map = new Map;
59
+ let bytesIn = 0;
60
+ let context = ast;
61
+ if (options.sourcemap) {
62
+ ast.loc = {
63
+ sta: {
64
+ ind: 0,
65
+ lin: 1,
66
+ col: 1
67
+ },
68
+ src: ''
69
+ };
107
70
  }
108
- if (tokens[0]?.typ == EnumToken.AtRuleTokenType) {
109
- const atRule = tokens.shift();
110
- const position = map.get(atRule);
111
- if (atRule.val == 'charset') {
112
- if (position.ind > 0) {
113
- errors.push({ action: 'drop', message: 'doParse: invalid @charset', location: { src, ...position } });
114
- return null;
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
+ }
115
95
  }
116
- if (options.removeCharset) {
117
- return null;
96
+ else if (tokens[i].typ != EnumToken.WhitespaceTokenType) {
97
+ break;
118
98
  }
119
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
+ }
120
111
  // @ts-ignore
121
- while ([EnumToken.WhitespaceTokenType].includes(tokens[0]?.typ)) {
122
- tokens.shift();
123
- }
124
- if (atRule.val == 'import') {
125
- // only @charset and @layer are accepted before @import
126
- if (context.chi.length > 0) {
127
- let i = context.chi.length;
128
- while (i--) {
129
- const type = context.chi[i].typ;
130
- if (type == 0 /* NodeType.CommentNodeType */) {
131
- continue;
132
- }
133
- if (type != 3 /* NodeType.AtRuleNodeType */) {
134
- errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } });
135
- return null;
136
- }
137
- const name = context.chi[i].nam;
138
- if (name != 'charset' && name != 'import' && name != 'layer') {
139
- errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } });
140
- return null;
141
- }
142
- break;
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;
143
132
  }
144
133
  }
145
134
  // @ts-ignore
146
- if (tokens[0]?.typ != EnumToken.StringTokenType && tokens[0]?.typ != EnumToken.UrlFunctionTokenType) {
147
- errors.push({ action: 'drop', message: 'doParse: invalid @import', location: { src, ...position } });
148
- return null;
149
- }
150
- // @ts-ignore
151
- if (tokens[0].typ == EnumToken.UrlFunctionTokenType && tokens[1]?.typ != EnumToken.UrlTokenTokenType && tokens[1]?.typ != EnumToken.StringTokenType) {
152
- errors.push({ action: 'drop', message: 'doParse: invalid @import', location: { src, ...position } });
153
- return null;
154
- }
155
- }
156
- if (atRule.val == 'import') {
157
- // @ts-ignore
158
- if (tokens[0].typ == EnumToken.UrlFunctionTokenType && tokens[1].typ == EnumToken.UrlTokenTokenType) {
135
+ while ([EnumToken.WhitespaceTokenType].includes(tokens[0]?.typ)) {
159
136
  tokens.shift();
160
- // @ts-ignore
161
- tokens[0].typ = EnumToken.StringTokenType;
162
- // @ts-ignore
163
- tokens[0].val = `"${tokens[0].val}"`;
164
137
  }
165
- // @ts-ignore
166
- if (tokens[0].typ == EnumToken.StringTokenType) {
167
- if (options.resolveImport) {
168
- const url = tokens[0].val.slice(1, -1);
169
- try {
170
- // @ts-ignore
171
- const root = await options.load(url, options.src).then((src) => {
172
- return doParse(src, Object.assign({}, options, {
173
- minify: false,
174
- // @ts-ignore
175
- src: options.resolve(url, options.src).absolute
176
- }));
177
- });
178
- bytesIn += root.stats.bytesIn;
179
- if (root.ast.chi.length > 0) {
180
- // @todo - filter charset, layer and scope
181
- context.chi.push(...root.ast.chi);
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;
182
146
  }
183
- if (root.errors.length > 0) {
184
- errors.push(...root.errors);
147
+ if (type != EnumToken.AtRuleNodeType) {
148
+ errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } });
149
+ return null;
185
150
  }
186
- return null;
187
- }
188
- catch (error) {
189
- // @ts-ignore
190
- errors.push({ action: 'ignore', message: 'doParse: ' + error.message, error });
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;
191
157
  }
192
158
  }
193
- }
194
- }
195
- // https://www.w3.org/TR/css-nesting-1/#conditionals
196
- // allowed nesting at-rules
197
- // there must be a top level rule in the stack
198
- const raw = parseTokens(tokens, { minify: options.minify }).reduce((acc, curr) => {
199
- acc.push(renderToken(curr, { removeComments: true }));
200
- return acc;
201
- }, []);
202
- const node = {
203
- typ: 3 /* NodeType.AtRuleNodeType */,
204
- nam: renderToken(atRule, { removeComments: true }),
205
- val: raw.join('')
206
- };
207
- Object.defineProperty(node, 'raw', { enumerable: false, configurable: true, writable: true, value: raw });
208
- if (delim.typ == EnumToken.BlockStartTokenType) {
209
- node.chi = [];
210
- }
211
- loc = {
212
- sta: position,
213
- src
214
- };
215
- if (options.sourcemap) {
216
- node.loc = loc;
217
- }
218
- // @ts-ignore
219
- context.chi.push(node);
220
- return delim.typ == EnumToken.BlockStartTokenType ? node : null;
221
- }
222
- else {
223
- // rule
224
- if (delim.typ == EnumToken.BlockStartTokenType) {
225
- const position = map.get(tokens[0]);
226
- const uniq = new Map;
227
- parseTokens(tokens, { minify: true }).reduce((acc, curr, index, array) => {
228
- if (curr.typ == EnumToken.WhitespaceTokenType) {
229
- if (trimWhiteSpace.includes(array[index - 1]?.typ) ||
230
- trimWhiteSpace.includes(array[index + 1]?.typ) ||
231
- combinators.includes(array[index - 1]?.val) ||
232
- combinators.includes(array[index + 1]?.val)) {
233
- return acc;
234
- }
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;
235
167
  }
236
- let t = renderToken(curr, { minify: false });
237
- if (t == ',') {
238
- acc.push([]);
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;
239
176
  }
240
- else {
241
- acc[acc.length - 1].push(t);
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}"`;
242
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 }));
243
222
  return acc;
244
- }, [[]]).reduce((acc, curr) => {
245
- acc.set(curr.join(''), curr);
246
- return acc;
247
- }, uniq);
223
+ }, []);
248
224
  const node = {
249
- typ: 4 /* NodeType.RuleNodeType */,
250
- // @ts-ignore
251
- sel: [...uniq.keys()].join(','),
252
- chi: []
225
+ typ: EnumToken.AtRuleNodeType,
226
+ nam: renderToken(atRule, { removeComments: true }),
227
+ val: raw.join('')
253
228
  };
254
- let raw = [...uniq.values()];
255
229
  Object.defineProperty(node, 'raw', { enumerable: false, configurable: true, writable: true, value: raw });
230
+ if (delim.typ == EnumToken.BlockStartTokenType) {
231
+ node.chi = [];
232
+ }
256
233
  loc = {
257
234
  sta: position,
258
235
  src
@@ -262,166 +239,247 @@ async function doParse(iterator, options = {}) {
262
239
  }
263
240
  // @ts-ignore
264
241
  context.chi.push(node);
265
- return node;
242
+ return delim.typ == EnumToken.BlockStartTokenType ? node : null;
266
243
  }
267
244
  else {
268
- // declaration
269
- // @ts-ignore
270
- let name = null;
271
- // @ts-ignore
272
- let value = null;
273
- for (let i = 0; i < tokens.length; i++) {
274
- if (tokens[i].typ == EnumToken.CommentTokenType) {
275
- continue;
276
- }
277
- if (tokens[i].typ == EnumToken.ColonTokenType) {
278
- name = tokens.slice(0, i);
279
- value = parseTokens(tokens.slice(i + 1), {
280
- parseColor: true,
281
- src: options.src,
282
- resolveUrls: options.resolveUrls,
283
- resolve: options.resolve,
284
- cwd: options.cwd
285
- });
286
- }
287
- }
288
- if (name == null) {
289
- name = tokens;
290
- }
291
- const position = map.get(name[0]);
292
- if (name.length > 0) {
293
- for (let i = 1; i < name.length; i++) {
294
- if (name[i].typ != EnumToken.WhitespaceTokenType && name[i].typ != EnumToken.CommentTokenType) {
295
- errors.push({
296
- action: 'drop',
297
- message: 'doParse: invalid declaration',
298
- location: { src, ...position }
299
- });
300
- return null;
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
+ }
301
257
  }
302
- }
303
- }
304
- if (value == null || value.length == 0) {
305
- errors.push({
306
- action: 'drop',
307
- message: 'doParse: invalid declaration',
308
- location: { src, ...position }
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
309
282
  });
310
- return null;
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;
311
293
  }
312
- const node = {
313
- typ: 5 /* NodeType.DeclarationNodeType */,
294
+ else {
295
+ // declaration
314
296
  // @ts-ignore
315
- nam: renderToken(name.shift(), { removeComments: true }),
297
+ let name = null;
316
298
  // @ts-ignore
317
- val: value
318
- };
319
- while (node.val[0]?.typ == EnumToken.WhitespaceTokenType) {
320
- node.val.shift();
321
- }
322
- if (node.val.length == 0) {
323
- errors.push({
324
- action: 'drop',
325
- message: 'doParse: invalid declaration',
326
- location: { src, ...position }
327
- });
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
+ }
328
351
  return null;
329
352
  }
330
- // @ts-ignore
331
- context.chi.push(node);
332
- return null;
333
353
  }
334
354
  }
335
- }
336
- function mapToken(token) {
337
- const node = getTokenType(token.token, token.hint);
338
- map.set(node, token.position);
339
- return node;
340
- }
341
- const iter = tokenize(iterator);
342
- let item;
343
- while (item = iter.next().value) {
344
- bytesIn = item.bytesIn;
345
- // doParse error
346
- if (item.hint != null && BadTokensTypes.includes(item.hint)) {
347
- // bad token
348
- continue;
355
+ function mapToken(token) {
356
+ const node = getTokenType(token.token, token.hint);
357
+ map.set(node, token.position);
358
+ return node;
349
359
  }
350
- tokens.push(item);
351
- if (item.token == ';' || item.token == '{') {
352
- let node = await parseNode(tokens);
353
- if (node != null) {
354
- stack.push(node);
360
+ const iter = tokenize(iterator);
361
+ let item;
362
+ while (item = iter.next().value) {
363
+ bytesIn = item.bytesIn;
364
+ // doParse error
365
+ if (item.hint != null && BadTokensTypes.includes(item.hint)) {
366
+ // bad token
367
+ continue;
368
+ }
369
+ tokens.push(item);
370
+ if (item.token == ';' || item.token == '{') {
371
+ let node = await parseNode(tokens);
372
+ if (node != null) {
373
+ stack.push(node);
374
+ // @ts-ignore
375
+ context = node;
376
+ }
377
+ else if (item.token == '{') {
378
+ // node == null
379
+ // consume and throw away until the closing '}' or EOF
380
+ let inBlock = 1;
381
+ do {
382
+ item = iter.next().value;
383
+ if (item == null) {
384
+ break;
385
+ }
386
+ if (item.token == '{') {
387
+ inBlock++;
388
+ }
389
+ else if (item.token == '}') {
390
+ inBlock--;
391
+ }
392
+ } while (inBlock != 0);
393
+ }
394
+ tokens = [];
395
+ map = new Map;
396
+ }
397
+ else if (item.token == '}') {
398
+ await parseNode(tokens);
399
+ const previousNode = stack.pop();
355
400
  // @ts-ignore
356
- context = node;
357
- }
358
- else if (item.token == '{') {
359
- // node == null
360
- // consume and throw away until the closing '}' or EOF
361
- let inBlock = 1;
362
- do {
363
- item = iter.next().value;
364
- if (item == null) {
365
- break;
366
- }
367
- if (item.token == '{') {
368
- inBlock++;
369
- }
370
- else if (item.token == '}') {
371
- inBlock--;
372
- }
373
- } while (inBlock != 0);
401
+ context = stack[stack.length - 1] || ast;
402
+ // @ts-ignore
403
+ if (options.removeEmpty && previousNode != null && previousNode.chi.length == 0 && context.chi[context.chi.length - 1] == previousNode) {
404
+ context.chi.pop();
405
+ }
406
+ tokens = [];
407
+ map = new Map;
374
408
  }
375
- tokens = [];
376
- map = new Map;
377
409
  }
378
- else if (item.token == '}') {
410
+ if (tokens.length > 0) {
379
411
  await parseNode(tokens);
412
+ }
413
+ while (stack.length > 0 && context != ast) {
380
414
  const previousNode = stack.pop();
381
415
  // @ts-ignore
382
416
  context = stack[stack.length - 1] || ast;
383
417
  // @ts-ignore
384
418
  if (options.removeEmpty && previousNode != null && previousNode.chi.length == 0 && context.chi[context.chi.length - 1] == previousNode) {
385
419
  context.chi.pop();
420
+ continue;
386
421
  }
387
- tokens = [];
388
- map = new Map;
422
+ break;
389
423
  }
390
- }
391
- if (tokens.length > 0) {
392
- await parseNode(tokens);
393
- }
394
- while (stack.length > 0 && context != ast) {
395
- const previousNode = stack.pop();
396
- // @ts-ignore
397
- context = stack[stack.length - 1] || ast;
398
- // @ts-ignore
399
- if (options.removeEmpty && previousNode != null && previousNode.chi.length == 0 && context.chi[context.chi.length - 1] == previousNode) {
400
- context.chi.pop();
401
- continue;
424
+ const endParseTime = performance.now();
425
+ if (options.expandNestingRules) {
426
+ ast = expand(ast);
402
427
  }
403
- break;
404
- }
405
- const endParseTime = performance.now();
406
- if (options.expandNestingRules) {
407
- ast = expand(ast);
408
- }
409
- if (options.minify) {
410
- if (ast.chi.length > 0) {
411
- minify(ast, options, true, errors, false);
428
+ if (options.visitor != null) {
429
+ for (const result of walk(ast)) {
430
+ if (result.node.typ == EnumToken.DeclarationNodeType &&
431
+ // @ts-ignore
432
+ (typeof options.visitor.Declaration == 'function' || options.visitor.Declaration?.[result.node.nam] != null)) {
433
+ const callable = typeof options.visitor.Declaration == 'function' ? options.visitor.Declaration : options.visitor.Declaration[result.node.nam];
434
+ const results = callable(result.node);
435
+ if (results == null || (Array.isArray(results) && results.length == 0)) {
436
+ continue;
437
+ }
438
+ // @ts-ignore
439
+ result.parent.chi.splice(result.parent.chi.indexOf(result.node), 1, ...(Array.isArray(results) ? results : [results]));
440
+ }
441
+ else if (options.visitor.Rule != null && result.node.typ == EnumToken.RuleNodeType) {
442
+ const results = options.visitor.Rule(result.node);
443
+ if (results == null || (Array.isArray(results) && results.length == 0)) {
444
+ continue;
445
+ }
446
+ // @ts-ignore
447
+ result.parent.chi.splice(result.parent.chi.indexOf(result.node), 1, ...(Array.isArray(results) ? results : [results]));
448
+ }
449
+ else if (options.visitor.AtRule != null &&
450
+ result.node.typ == EnumToken.AtRuleNodeType &&
451
+ // @ts-ignore
452
+ (typeof options.visitor.AtRule == 'function' || options.visitor.AtRule?.[result.node.nam] != null)) {
453
+ const callable = typeof options.visitor.AtRule == 'function' ? options.visitor.AtRule : options.visitor.AtRule[result.node.nam];
454
+ const results = callable(result.node);
455
+ if (results == null || (Array.isArray(results) && results.length == 0)) {
456
+ continue;
457
+ }
458
+ // @ts-ignore
459
+ result.parent.chi.splice(result.parent.chi.indexOf(result.node), 1, ...(Array.isArray(results) ? results : [results]));
460
+ }
461
+ }
412
462
  }
413
- }
414
- const endTime = performance.now();
415
- return {
416
- ast,
417
- errors,
418
- stats: {
419
- bytesIn,
420
- parse: `${(endParseTime - startTime).toFixed(2)}ms`,
421
- minify: `${(endTime - endParseTime).toFixed(2)}ms`,
422
- total: `${(endTime - startTime).toFixed(2)}ms`
463
+ if (options.minify) {
464
+ if (ast.chi.length > 0) {
465
+ minify(ast, options, true, errors, false);
466
+ }
423
467
  }
424
- };
468
+ const endTime = performance.now();
469
+ if (options.signal != null) {
470
+ options.signal.removeEventListener('abort', reject);
471
+ }
472
+ resolve({
473
+ ast,
474
+ errors,
475
+ stats: {
476
+ bytesIn,
477
+ parse: `${(endParseTime - startTime).toFixed(2)}ms`,
478
+ minify: `${(endTime - endParseTime).toFixed(2)}ms`,
479
+ total: `${(endTime - startTime).toFixed(2)}ms`
480
+ }
481
+ });
482
+ });
425
483
  }
426
484
  function parseString(src, options = { location: false }) {
427
485
  return parseTokens([...tokenize(src)].map(t => {
@@ -440,7 +498,9 @@ function getTokenType(val, hint) {
440
498
  return ([
441
499
  EnumToken.WhitespaceTokenType, EnumToken.SemiColonTokenType, EnumToken.ColonTokenType, EnumToken.BlockStartTokenType,
442
500
  EnumToken.BlockStartTokenType, EnumToken.AttrStartTokenType, EnumToken.AttrEndTokenType, EnumToken.StartParensTokenType, EnumToken.EndParensTokenType,
443
- EnumToken.CommaTokenType, EnumToken.GtTokenType, EnumToken.LtTokenType, EnumToken.GteTokenType, EnumToken.LteTokenType, EnumToken.EOFTokenType
501
+ EnumToken.CommaTokenType, EnumToken.GtTokenType, EnumToken.LtTokenType, EnumToken.GteTokenType, EnumToken.LteTokenType, EnumToken.CommaTokenType,
502
+ EnumToken.StartMatchTokenType, EnumToken.EndMatchTokenType, EnumToken.IncludeMatchTokenType, EnumToken.DashMatchTokenType, EnumToken.ContainMatchTokenType,
503
+ EnumToken.EOFTokenType
444
504
  ].includes(hint) ? { typ: hint } : { typ: hint, val });
445
505
  }
446
506
  if (val == ' ') {
@@ -504,8 +564,36 @@ function getTokenType(val, hint) {
504
564
  }
505
565
  if (isFunction(val)) {
506
566
  val = val.slice(0, -1);
567
+ if (val == 'url') {
568
+ return {
569
+ typ: EnumToken.UrlFunctionTokenType,
570
+ val,
571
+ chi: []
572
+ };
573
+ }
574
+ if (['linear-gradient', 'radial-gradient', 'repeating-linear-gradient', 'repeating-radial-gradient', 'conic-gradient', 'image', 'image-set', 'element', 'cross-fade'].includes(val)) {
575
+ return {
576
+ typ: EnumToken.ImageFunctionTokenType,
577
+ val,
578
+ chi: []
579
+ };
580
+ }
581
+ if (['ease', 'ease-in', 'ease-out', 'ease-in-out', 'linear', 'step-start', 'step-end', 'steps', 'cubic-bezier'].includes(val)) {
582
+ return {
583
+ typ: EnumToken.TimingFunctionTokenType,
584
+ val,
585
+ chi: []
586
+ };
587
+ }
588
+ if (['view', 'scroll'].includes(val)) {
589
+ return {
590
+ typ: EnumToken.TimelineFunctionTokenType,
591
+ val,
592
+ chi: []
593
+ };
594
+ }
507
595
  return {
508
- typ: val == 'url' ? EnumToken.UrlFunctionTokenType : EnumToken.FunctionTokenType,
596
+ typ: EnumToken.FunctionTokenType,
509
597
  val,
510
598
  chi: []
511
599
  };
@@ -516,15 +604,21 @@ function getTokenType(val, hint) {
516
604
  val
517
605
  };
518
606
  }
519
- if (isDimension(val)) {
520
- return parseDimension(val);
521
- }
522
607
  if (isPercentage(val)) {
523
608
  return {
524
609
  typ: EnumToken.PercentageTokenType,
525
610
  val: val.slice(0, -1)
526
611
  };
527
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
+ }
528
622
  const v = val.toLowerCase();
529
623
  if (v == 'currentcolor' || val == 'transparent' || v in COLORS_NAMES) {
530
624
  return {
@@ -535,7 +629,7 @@ function getTokenType(val, hint) {
535
629
  }
536
630
  if (isIdent(val)) {
537
631
  return {
538
- typ: EnumToken.IdenTokenType,
632
+ typ: val.startsWith('--') ? EnumToken.DashedIdenTokenType : EnumToken.IdenTokenType,
539
633
  val
540
634
  };
541
635
  }
@@ -568,7 +662,7 @@ function parseTokens(tokens, options = {}) {
568
662
  const t = tokens[i];
569
663
  if (t.typ == EnumToken.WhitespaceTokenType && ((i == 0 ||
570
664
  i + 1 == tokens.length ||
571
- [EnumToken.CommaTokenType, EnumToken.GteTokenType, EnumToken.LteTokenType].includes(tokens[i + 1].typ)) ||
665
+ [EnumToken.CommaTokenType, EnumToken.GteTokenType, EnumToken.LteTokenType, EnumToken.ColumnCombinatorTokenType].includes(tokens[i + 1].typ)) ||
572
666
  (i > 0 &&
573
667
  // tokens[i + 1]?.typ != Literal ||
574
668
  // funcLike.includes(tokens[i - 1].typ) &&
@@ -585,15 +679,18 @@ function parseTokens(tokens, options = {}) {
585
679
  tokens[i + 1].typ = EnumToken.PseudoClassFuncTokenType;
586
680
  }
587
681
  else if (typ == EnumToken.IdenTokenType) {
682
+ if (tokens[i + 1].val in webkitPseudoAliasMap) {
683
+ tokens[i + 1].val = webkitPseudoAliasMap[tokens[i + 1].val];
684
+ }
588
685
  tokens[i + 1].val = ':' + tokens[i + 1].val;
589
686
  tokens[i + 1].typ = EnumToken.PseudoClassTokenType;
590
687
  }
591
688
  if (typ == EnumToken.FunctionTokenType || typ == EnumToken.IdenTokenType) {
592
689
  tokens.splice(i, 1);
593
690
  i--;
594
- continue;
595
691
  }
596
692
  }
693
+ continue;
597
694
  }
598
695
  if (t.typ == EnumToken.AttrStartTokenType) {
599
696
  let k = i;
@@ -614,21 +711,105 @@ function parseTokens(tokens, options = {}) {
614
711
  if (t.chi.at(-1).typ == EnumToken.AttrEndTokenType) {
615
712
  // @ts-ignore
616
713
  t.chi.pop();
714
+ }
715
+ // @ts-ignore
716
+ if (t.chi.length > 1) {
717
+ /*(<AttrToken>t).chi =*/
617
718
  // @ts-ignore
618
- if (t.chi.length > 1) {
619
- /*(<AttrToken>t).chi =*/
719
+ parseTokens(t.chi, t.typ);
720
+ }
721
+ let m = t.chi.length;
722
+ let val;
723
+ for (m = 0; m < t.chi.length; m++) {
724
+ val = t.chi[m];
725
+ if (val.typ == EnumToken.StringTokenType) {
726
+ const slice = val.val.slice(1, -1);
727
+ if ((slice.charAt(0) != '-' || (slice.charAt(0) == '-' && isIdentStart(slice.charCodeAt(1)))) && isIdent(slice)) {
728
+ Object.assign(val, { typ: EnumToken.IdenTokenType, val: slice });
729
+ }
730
+ }
731
+ else if (val.typ == EnumToken.LiteralTokenType && val.val == '|') {
732
+ let upper = m;
733
+ let lower = m;
734
+ while (++upper < t.chi.length) {
735
+ if (t.chi[upper].typ == EnumToken.CommentTokenType) {
736
+ continue;
737
+ }
738
+ break;
739
+ }
740
+ while (lower-- > 0) {
741
+ if (t.chi[lower].typ == EnumToken.CommentTokenType) {
742
+ continue;
743
+ }
744
+ break;
745
+ }
620
746
  // @ts-ignore
621
- parseTokens(t.chi, t.typ);
747
+ t.chi[m] = {
748
+ typ: EnumToken.NameSpaceAttributeTokenType,
749
+ l: t.chi[lower],
750
+ r: t.chi[upper]
751
+ };
752
+ t.chi.splice(upper, 1);
753
+ if (lower >= 0) {
754
+ t.chi.splice(lower, 1);
755
+ m--;
756
+ }
622
757
  }
623
- // @ts-ignore
624
- t.chi.forEach(val => {
758
+ else if ([
759
+ EnumToken.DashMatchTokenType, EnumToken.StartMatchTokenType, EnumToken.ContainMatchTokenType, EnumToken.EndMatchTokenType, EnumToken.IncludeMatchTokenType
760
+ ].includes(t.chi[m].typ)) {
761
+ let upper = m;
762
+ let lower = m;
763
+ while (++upper < t.chi.length) {
764
+ if (t.chi[upper].typ == EnumToken.CommentTokenType) {
765
+ continue;
766
+ }
767
+ break;
768
+ }
769
+ while (lower-- > 0) {
770
+ if (t.chi[lower].typ == EnumToken.CommentTokenType) {
771
+ continue;
772
+ }
773
+ break;
774
+ }
775
+ val = t.chi[lower];
776
+ if (val.typ == EnumToken.StringTokenType) {
777
+ const slice = val.val.slice(1, -1);
778
+ if ((slice.charAt(0) != '-' || (slice.charAt(0) == '-' && isIdentStart(slice.charCodeAt(1)))) && isIdent(slice)) {
779
+ Object.assign(val, { typ: EnumToken.IdenTokenType, val: slice });
780
+ }
781
+ }
782
+ val = t.chi[upper];
625
783
  if (val.typ == EnumToken.StringTokenType) {
626
784
  const slice = val.val.slice(1, -1);
627
785
  if ((slice.charAt(0) != '-' || (slice.charAt(0) == '-' && isIdentStart(slice.charCodeAt(1)))) && isIdent(slice)) {
628
786
  Object.assign(val, { typ: EnumToken.IdenTokenType, val: slice });
629
787
  }
630
788
  }
631
- });
789
+ t.chi[m] = {
790
+ typ: EnumToken.MatchExpressionTokenType,
791
+ op: t.chi[m].typ,
792
+ l: t.chi[lower],
793
+ r: t.chi[upper]
794
+ };
795
+ t.chi.splice(upper, 1);
796
+ t.chi.splice(lower, 1);
797
+ upper = m;
798
+ m--;
799
+ while (upper < t.chi.length && t.chi[upper].typ == EnumToken.WhitespaceTokenType) {
800
+ upper++;
801
+ }
802
+ if (upper < t.chi.length &&
803
+ t.chi[upper].typ == EnumToken.Iden &&
804
+ ['i', 's'].includes(t.chi[upper].val.toLowerCase())) {
805
+ t.chi[m].attr = t.chi[upper].val;
806
+ t.chi.splice(upper, 1);
807
+ }
808
+ }
809
+ }
810
+ m = t.chi.length;
811
+ while (t.chi.at(-1)?.typ == EnumToken.WhitespaceTokenType) {
812
+ t.chi.pop();
632
813
  }
633
814
  continue;
634
815
  }
@@ -671,6 +852,11 @@ function parseTokens(tokens, options = {}) {
671
852
  // @ts-ignore
672
853
  t.chi.pop();
673
854
  }
855
+ // @ts-ignore
856
+ if (t.chi.length > 0) {
857
+ // @ts-ignore
858
+ parseTokens(t.chi, options);
859
+ }
674
860
  if (t.typ == EnumToken.FunctionTokenType && t.val == 'calc') {
675
861
  for (const { value, parent } of walkValues(t.chi)) {
676
862
  if (value.typ == EnumToken.WhitespaceTokenType) {
@@ -693,35 +879,25 @@ function parseTokens(tokens, options = {}) {
693
879
  }
694
880
  }
695
881
  }
882
+ else if (t.typ == EnumToken.FunctionTokenType && ['minmax', 'fit-content', 'repeat'].includes(t.val)) {
883
+ // @ts-ignore
884
+ t.typ = EnumToken.GridTemplateFuncTokenType;
885
+ }
696
886
  else if (t.typ == EnumToken.StartParensTokenType) {
697
887
  // @ts-ignore
698
888
  t.typ = EnumToken.ParensTokenType;
699
889
  }
700
890
  // @ts-ignore
701
891
  if (options.parseColor && t.typ == EnumToken.FunctionTokenType && isColor(t)) {
702
- // if (isColor) {
703
892
  // @ts-ignore
704
893
  t.typ = EnumToken.ColorTokenType;
705
894
  // @ts-ignore
706
895
  t.kin = t.val;
707
- // @ts-ignore
708
- let m = t.chi.length;
709
- while (m-- > 0) {
896
+ if (t.chi[0].typ == EnumToken.IdenTokenType && t.chi[0].val == 'from') {
710
897
  // @ts-ignore
711
- if ([EnumToken.LiteralTokenType].concat(trimWhiteSpace).includes(t.chi[m].typ)) {
712
- // @ts-ignore
713
- if (t.chi[m + 1]?.typ == EnumToken.WhitespaceTokenType) {
714
- // @ts-ignore
715
- t.chi.splice(m + 1, 1);
716
- }
717
- // @ts-ignore
718
- if (t.chi[m - 1]?.typ == EnumToken.WhitespaceTokenType) {
719
- // @ts-ignore
720
- t.chi.splice(m - 1, 1);
721
- m--;
722
- }
723
- }
898
+ t.cal = 'rel';
724
899
  }
900
+ t.chi = t.chi.filter((t) => ![EnumToken.WhitespaceTokenType, EnumToken.CommaTokenType, EnumToken.CommentTokenType].includes(t.typ));
725
901
  continue;
726
902
  }
727
903
  if (t.typ == EnumToken.UrlFunctionTokenType) {
@@ -746,8 +922,6 @@ function parseTokens(tokens, options = {}) {
746
922
  }
747
923
  // @ts-ignore
748
924
  if (t.chi.length > 0) {
749
- // @ts-ignore
750
- parseTokens(t.chi, options);
751
925
  if (t.typ == EnumToken.PseudoClassFuncTokenType && t.val == ':is' && options.minify) {
752
926
  //
753
927
  const count = t.chi.filter(t => t.typ != EnumToken.CommentTokenType).length;