@tbela99/css-parser 1.3.1 → 1.3.3

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,60 +1,127 @@
1
+ /**
2
+ * options for the walk function
3
+ */
1
4
  var WalkerOptionEnum;
2
5
  (function (WalkerOptionEnum) {
3
6
  /**
4
7
  * ignore the current node and its children
5
8
  */
6
- WalkerOptionEnum[WalkerOptionEnum["Ignore"] = 0] = "Ignore";
9
+ WalkerOptionEnum[WalkerOptionEnum["Ignore"] = 1] = "Ignore";
7
10
  /**
8
11
  * stop walking the tree
9
12
  */
10
- WalkerOptionEnum[WalkerOptionEnum["Stop"] = 1] = "Stop";
13
+ WalkerOptionEnum[WalkerOptionEnum["Stop"] = 2] = "Stop";
11
14
  /**
12
15
  * ignore node and process children
13
16
  */
14
- WalkerOptionEnum[WalkerOptionEnum["Children"] = 2] = "Children";
17
+ WalkerOptionEnum[WalkerOptionEnum["Children"] = 4] = "Children";
15
18
  /**
16
19
  * ignore children
17
20
  */
18
- WalkerOptionEnum[WalkerOptionEnum["IgnoreChildren"] = 3] = "IgnoreChildren";
21
+ WalkerOptionEnum[WalkerOptionEnum["IgnoreChildren"] = 8] = "IgnoreChildren";
19
22
  })(WalkerOptionEnum || (WalkerOptionEnum = {}));
23
+ /**
24
+ * event types for the walkValues function
25
+ */
20
26
  var WalkerValueEvent;
21
27
  (function (WalkerValueEvent) {
22
28
  /**
23
29
  * enter node
24
30
  */
25
- WalkerValueEvent[WalkerValueEvent["Enter"] = 0] = "Enter";
31
+ WalkerValueEvent[WalkerValueEvent["Enter"] = 1] = "Enter";
26
32
  /**
27
33
  * leave node
28
34
  */
29
- WalkerValueEvent[WalkerValueEvent["Leave"] = 1] = "Leave";
35
+ WalkerValueEvent[WalkerValueEvent["Leave"] = 2] = "Leave";
30
36
  })(WalkerValueEvent || (WalkerValueEvent = {}));
31
37
  /**
32
38
  * walk ast nodes
33
- * @param node
34
- * @param filter
39
+ * @param node initial node
40
+ * @param filter control the walk process
41
+ * @param reverse walk in reverse order
42
+ *
43
+ * ```ts
44
+ *
45
+ * import {walk} from '@tbela99/css-parser';
46
+ *
47
+ * const css = `
48
+ * body { color: color(from var(--base-color) display-p3 r calc(g + 0.24) calc(b + 0.15)); }
49
+ *
50
+ * html,
51
+ * body {
52
+ * line-height: 1.474;
53
+ * }
54
+ *
55
+ * .ruler {
56
+ *
57
+ * height: 10px;
58
+ * }
59
+ * `;
60
+ *
61
+ * for (const {node, parent, root} of walk(ast)) {
62
+ *
63
+ * // do something with node
64
+ * }
65
+ * ```
66
+ *
67
+ * Using a filter to control the walk process:
68
+ *
69
+ * ```ts
70
+ *
71
+ * import {walk} from '@tbela99/css-parser';
72
+ *
73
+ * const css = `
74
+ * body { color: color(from var(--base-color) display-p3 r calc(g + 0.24) calc(b + 0.15)); }
75
+ *
76
+ * html,
77
+ * body {
78
+ * line-height: 1.474;
79
+ * }
80
+ *
81
+ * .ruler {
82
+ *
83
+ * height: 10px;
84
+ * }
85
+ * `;
86
+ *
87
+ * for (const {node, parent, root} of walk(ast, (node) => {
88
+ *
89
+ * if (node.typ == EnumToken.AstRule && node.sel.includes('html')) {
90
+ *
91
+ * // skip the children of the current node
92
+ * return WalkerOptionEnum.IgnoreChildren;
93
+ * }
94
+ * })) {
95
+ *
96
+ * // do something with node
97
+ * }
98
+ * ```
35
99
  */
36
- function* walk(node, filter) {
100
+ function* walk(node, filter, reverse) {
37
101
  const parents = [node];
38
102
  const root = node;
39
103
  const map = new Map;
104
+ let isNumeric = false;
40
105
  while ((node = parents.shift())) {
41
106
  let option = null;
42
107
  if (filter != null) {
43
108
  option = filter(node);
44
- if (option === WalkerOptionEnum.Ignore) {
45
- continue;
46
- }
47
- if (option === WalkerOptionEnum.Stop) {
48
- break;
109
+ isNumeric = typeof option == 'number';
110
+ if (isNumeric) {
111
+ if ((option & WalkerOptionEnum.Ignore)) {
112
+ continue;
113
+ }
114
+ if ((option & WalkerOptionEnum.Stop)) {
115
+ break;
116
+ }
49
117
  }
50
118
  }
51
- // @ts-ignore
52
- if (option !== 'children') {
119
+ if (!isNumeric || (option & WalkerOptionEnum.Children) === 0) {
53
120
  // @ts-ignore
54
121
  yield { node, parent: map.get(node), root };
55
122
  }
56
- if (option !== WalkerOptionEnum.IgnoreChildren && 'chi' in node) {
57
- parents.unshift(...node.chi);
123
+ if ('chi' in node && (!isNumeric || ((option & WalkerOptionEnum.IgnoreChildren) === 0))) {
124
+ parents.unshift(...node.chi[reverse ? 'reverse' : 'slice']());
58
125
  for (const child of node.chi.slice()) {
59
126
  map.set(child, node);
60
127
  }
@@ -67,13 +134,38 @@ function* walk(node, filter) {
67
134
  * @param root
68
135
  * @param filter
69
136
  * @param reverse
137
+ *
138
+ * Example:
139
+ *
140
+ * ```ts
141
+ *
142
+ * import {EnumToken, walk} from '@tbela99/css-parser';
143
+ *
144
+ * const css = `
145
+ * body { color: color(from var(--base-color) display-p3 r calc(g + 0.24) calc(b + 0.15)); }
146
+ *
147
+ * html,
148
+ * body {
149
+ * line-height: 1.474;
150
+ * }
151
+ *
152
+ * .ruler {
153
+ *
154
+ * height: 10px;
155
+ * }
156
+ * `;
157
+ *
158
+ * for (const {value} of walkValues(result.ast.chi[0].chi[0].val, null, null,true)) {
159
+ *
160
+ * console.error([EnumToken[value.typ], value.val]);
161
+ * }
162
+ *
70
163
  */
71
164
  function* walkValues(values, root = null, filter, reverse) {
72
165
  // const set = new Set<Token>();
73
166
  const stack = values.slice();
74
167
  const map = new Map;
75
168
  let previous = null;
76
- // let parent: FunctionToken | ParensToken | BinaryExpressionToken | null = null;
77
169
  if (filter != null && typeof filter == 'function') {
78
170
  filter = {
79
171
  event: WalkerValueEvent.Enter,
@@ -85,21 +177,23 @@ function* walkValues(values, root = null, filter, reverse) {
85
177
  event: WalkerValueEvent.Enter
86
178
  };
87
179
  }
180
+ let isNumeric = false;
88
181
  const eventType = filter.event ?? WalkerValueEvent.Enter;
89
182
  while (stack.length > 0) {
90
183
  let value = reverse ? stack.pop() : stack.shift();
91
184
  let option = null;
92
- if (filter.fn != null && eventType == WalkerValueEvent.Enter) {
185
+ if (filter.fn != null && (eventType & WalkerValueEvent.Enter)) {
93
186
  const isValid = filter.type == null || value.typ == filter.type ||
94
187
  (Array.isArray(filter.type) && filter.type.includes(value.typ)) ||
95
188
  (typeof filter.type == 'function' && filter.type(value));
96
189
  if (isValid) {
97
- option = filter.fn(value, map.get(value) ?? root);
98
- if (option === WalkerOptionEnum.Ignore) {
99
- continue;
190
+ option = filter.fn(value, map.get(value) ?? root, WalkerValueEvent.Enter);
191
+ isNumeric = typeof option == 'number';
192
+ if (isNumeric && (option & WalkerOptionEnum.Stop)) {
193
+ return;
100
194
  }
101
- if (option === WalkerOptionEnum.Stop) {
102
- break;
195
+ if (isNumeric && (option & WalkerOptionEnum.Ignore)) {
196
+ continue;
103
197
  }
104
198
  // @ts-ignore
105
199
  if (option != null && typeof option == 'object' && 'typ' in option) {
@@ -107,38 +201,33 @@ function* walkValues(values, root = null, filter, reverse) {
107
201
  }
108
202
  }
109
203
  }
110
- if (eventType == WalkerValueEvent.Enter && option !== WalkerOptionEnum.Children) {
111
- yield {
112
- value,
113
- parent: map.get(value) ?? root,
114
- previousValue: previous,
115
- nextValue: stack[0] ?? null,
116
- // @ts-ignore
117
- root: root ?? null
118
- };
119
- }
120
- if (option !== WalkerOptionEnum.IgnoreChildren && 'chi' in value) {
204
+ // if ((eventType & WalkerValueEvent.Enter) && (!isNumeric || ((option as number) & WalkerOptionEnum.Children) === 0)) {
205
+ yield {
206
+ value,
207
+ parent: map.get(value) ?? root,
208
+ previousValue: previous,
209
+ nextValue: stack[0] ?? null,
210
+ // @ts-ignore
211
+ root: root ?? null
212
+ };
213
+ // }
214
+ if ('chi' in value && (!isNumeric || (option & WalkerOptionEnum.IgnoreChildren) === 0)) {
121
215
  const sliced = value.chi.slice();
122
216
  for (const child of sliced) {
123
217
  map.set(child, value);
124
218
  }
125
- if (reverse) {
126
- stack.push(...sliced);
127
- }
128
- else {
129
- stack.unshift(...sliced);
130
- }
219
+ stack[reverse ? 'push' : 'unshift'](...sliced);
131
220
  }
132
221
  else {
133
222
  const values = [];
134
223
  if ('l' in value && value.l != null) {
135
224
  // @ts-ignore
136
- values.push(value.l);
225
+ values[reverse ? 'push' : 'unshift'](value.l);
137
226
  // @ts-ignore
138
227
  map.set(value.l, value);
139
228
  }
140
229
  if ('op' in value && typeof value.op == 'object') {
141
- values.push(value.op);
230
+ values[reverse ? 'push' : 'unshift'](value.op);
142
231
  // @ts-ignore
143
232
  map.set(value.op, value);
144
233
  }
@@ -146,44 +235,45 @@ function* walkValues(values, root = null, filter, reverse) {
146
235
  if (Array.isArray(value.r)) {
147
236
  for (const r of value.r) {
148
237
  // @ts-ignore
149
- values.push(r);
238
+ values[reverse ? 'push' : 'unshift'](r);
150
239
  // @ts-ignore
151
240
  map.set(r, value);
152
241
  }
153
242
  }
154
243
  else {
155
244
  // @ts-ignore
156
- values.push(value.r);
245
+ values[reverse ? 'push' : 'unshift'](value.r);
157
246
  // @ts-ignore
158
247
  map.set(value.r, value);
159
248
  }
160
249
  }
161
250
  if (values.length > 0) {
162
- stack.unshift(...values);
251
+ stack[reverse ? 'push' : 'unshift'](...values);
163
252
  }
164
253
  }
165
- if (eventType == WalkerValueEvent.Leave && filter.fn != null) {
254
+ if ((eventType & WalkerValueEvent.Leave) && filter.fn != null) {
166
255
  const isValid = filter.type == null || value.typ == filter.type ||
167
256
  (Array.isArray(filter.type) && filter.type.includes(value.typ)) ||
168
257
  (typeof filter.type == 'function' && filter.type(value));
169
258
  if (isValid) {
170
- option = filter.fn(value, map.get(value));
259
+ option = filter.fn(value, map.get(value), WalkerValueEvent.Leave);
171
260
  // @ts-ignore
172
261
  if (option != null && 'typ' in option) {
173
262
  map.set(option, map.get(value) ?? root);
174
263
  }
175
264
  }
176
265
  }
177
- if (eventType == WalkerValueEvent.Leave && option !== WalkerOptionEnum.Children) {
178
- yield {
179
- value,
180
- parent: map.get(value) ?? root,
181
- previousValue: previous,
182
- nextValue: stack[0] ?? null,
183
- // @ts-ignore
184
- root: root ?? null
185
- };
186
- }
266
+ // if ((eventType & WalkerValueEvent.Leave) && (!isNumeric && ((option as number) & WalkerOptionEnum.Children) === 0)) {
267
+ //
268
+ // yield {
269
+ // value,
270
+ // parent: <FunctionToken | ParensToken>map.get(value) ?? root,
271
+ // previousValue: previous,
272
+ // nextValue: <Token>stack[0] ?? null,
273
+ // // @ts-ignore
274
+ // root: root ?? null
275
+ // };
276
+ // }
187
277
  previous = value;
188
278
  }
189
279
  }
@@ -2,12 +2,14 @@ const matchUrl = /^(https?:)?\/\//;
2
2
  /**
3
3
  * return the directory name of a path
4
4
  * @param path
5
- * @internal
5
+ *
6
+ * @private
6
7
  */
7
8
  function dirname(path) {
8
- if (path == '/' || path === '') {
9
- return path;
10
- }
9
+ // if (path == '/' || path === '') {
10
+ //
11
+ // return path;
12
+ // }
11
13
  let i = 0;
12
14
  let parts = [''];
13
15
  for (; i < path.length; i++) {
@@ -26,7 +26,7 @@ class PropertyList {
26
26
  }
27
27
  add(...declarations) {
28
28
  for (const declaration of declarations) {
29
- if (declaration.typ != EnumToken.DeclarationNodeType || !this.options.removeDuplicateDeclarations) {
29
+ if (declaration.typ != EnumToken.DeclarationNodeType || (Array.isArray(this.options.removeDuplicateDeclarations) ? this.options.removeDuplicateDeclarations.includes(declaration.nam) : !this.options.removeDuplicateDeclarations)) {
30
30
  this.declarations.set(Number(Math.random().toString().slice(2)).toString(36), declaration);
31
31
  continue;
32
32
  }