@tbela99/css-parser 1.3.3 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +64 -48
  3. package/dist/config.json.js +3 -0
  4. package/dist/index-umd-web.js +2266 -631
  5. package/dist/index.cjs +2271 -620
  6. package/dist/index.d.ts +522 -181
  7. package/dist/lib/ast/expand.js +5 -10
  8. package/dist/lib/ast/features/calc.js +3 -2
  9. package/dist/lib/ast/features/inlinecssvariables.js +5 -3
  10. package/dist/lib/ast/features/prefix.js +1 -1
  11. package/dist/lib/ast/features/shorthand.js +1 -0
  12. package/dist/lib/ast/features/transform.js +13 -19
  13. package/dist/lib/ast/features/type.js +1 -1
  14. package/dist/lib/ast/minify.js +6 -3
  15. package/dist/lib/ast/transform/compute.js +2 -4
  16. package/dist/lib/ast/transform/matrix.js +20 -20
  17. package/dist/lib/ast/transform/minify.js +105 -12
  18. package/dist/lib/ast/transform/rotate.js +11 -11
  19. package/dist/lib/ast/transform/scale.js +6 -6
  20. package/dist/lib/ast/transform/skew.js +4 -4
  21. package/dist/lib/ast/transform/translate.js +3 -3
  22. package/dist/lib/ast/transform/utils.js +30 -37
  23. package/dist/lib/ast/types.js +76 -5
  24. package/dist/lib/ast/walk.js +77 -58
  25. package/dist/lib/fs/resolve.js +69 -10
  26. package/dist/lib/parser/declaration/list.js +6 -1
  27. package/dist/lib/parser/parse.js +1169 -312
  28. package/dist/lib/parser/tokenize.js +33 -20
  29. package/dist/lib/parser/utils/declaration.js +54 -0
  30. package/dist/lib/parser/utils/hash.js +86 -0
  31. package/dist/lib/parser/utils/text.js +8 -0
  32. package/dist/lib/renderer/render.js +26 -7
  33. package/dist/lib/syntax/color/relativecolor.js +0 -3
  34. package/dist/lib/syntax/syntax.js +36 -18
  35. package/dist/lib/validation/at-rules/container.js +11 -0
  36. package/dist/lib/validation/at-rules/counter-style.js +11 -0
  37. package/dist/lib/validation/at-rules/font-feature-values.js +11 -0
  38. package/dist/lib/validation/at-rules/keyframes.js +11 -0
  39. package/dist/lib/validation/at-rules/layer.js +11 -0
  40. package/dist/lib/validation/at-rules/media.js +11 -0
  41. package/dist/lib/validation/at-rules/page-margin-box.js +11 -0
  42. package/dist/lib/validation/at-rules/page.js +11 -0
  43. package/dist/lib/validation/at-rules/supports.js +11 -0
  44. package/dist/lib/validation/at-rules/when.js +11 -0
  45. package/dist/lib/validation/config.js +0 -2
  46. package/dist/lib/validation/config.json.js +36 -4
  47. package/dist/lib/validation/parser/parse.js +53 -2
  48. package/dist/lib/validation/syntax.js +204 -36
  49. package/dist/lib/validation/syntaxes/compound-selector.js +1 -2
  50. package/dist/lib/validation/syntaxes/relative-selector-list.js +2 -5
  51. package/dist/node.js +60 -18
  52. package/dist/types.d.ts +17 -0
  53. package/dist/types.js +20 -0
  54. package/dist/web.js +43 -17
  55. package/package.json +20 -17
  56. package/dist/lib/validation/parser/types.js +0 -54
@@ -2,9 +2,6 @@ const epsilon = 1e-5;
2
2
  function identity() {
3
3
  return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
4
4
  }
5
- function pLength(point) {
6
- return Math.sqrt(point[0] * point[0] + point[1] * point[1] + point[2] * point[2]);
7
- }
8
5
  function normalize(point) {
9
6
  const [x, y, z] = point;
10
7
  const norm = Math.sqrt(point[0] * point[0] + point[1] * point[1] + point[2] * point[2]);
@@ -32,8 +29,14 @@ function multiply(matrixA, matrixB) {
32
29
  function inverse(matrix) {
33
30
  // Create augmented matrix [matrix | identity]
34
31
  let augmented = [
35
- 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
36
- 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1
32
+ ...matrix.slice(0, 4),
33
+ 1, 0, 0, 0,
34
+ ...matrix.slice(4, 8),
35
+ 0, 1, 0, 0,
36
+ ...matrix.slice(8, 12),
37
+ 0, 0, 1, 0,
38
+ ...matrix.slice(12, 16),
39
+ 0, 0, 0, 1
37
40
  ];
38
41
  // Gaussian elimination with partial pivoting
39
42
  for (let col = 0; col < 4; col++) {
@@ -73,24 +76,9 @@ function inverse(matrix) {
73
76
  // Extract the inverse from the right side of the augmented matrix
74
77
  return augmented.slice(0, 16);
75
78
  }
76
- // function transpose(matrix: Matrix): Matrix {
77
- // // Crée une nouvelle matrice vide 4x4
78
- // // @ts-ignore
79
- // let transposed: Matrix = [[], [], [], []] as Matrix;
80
- //
81
- // // Parcourt chaque ligne et colonne pour transposer
82
- // for (let i = 0; i < 4; i++) {
83
- //
84
- // for (let j = 0; j < 4; j++) {
85
- //
86
- // transposed[j][i] = matrix[i][j];
87
- // }
88
- // }
89
- //
90
- // return transposed;
91
- // }
92
79
  function round(number) {
93
- return Math.abs(number) < epsilon ? 0 : +number.toPrecision(6);
80
+ const rounded = Math.round(number);
81
+ return Math.abs(rounded - number) <= epsilon ? rounded : +number.toPrecision(6);
94
82
  }
95
83
  // translate3d(25.9808px, 0, 15px ) rotateY(60deg) skewX(49.9999deg) scale(1, 1.2)
96
84
  // translate → rotate → skew → scale
@@ -113,7 +101,7 @@ function decompose(original) {
113
101
  perspectiveMatrix[15] = 1;
114
102
  // @ts-ignore
115
103
  const inverted = inverse(original.slice());
116
- if (!inverted) {
104
+ if (inverted === null) {
117
105
  return null;
118
106
  }
119
107
  const transposedInverse = transposeMatrix4(inverted);
@@ -134,8 +122,13 @@ function decompose(original) {
134
122
  const row0 = [matrix[0], matrix[1], matrix[2]];
135
123
  const row1 = [matrix[4], matrix[5], matrix[6]];
136
124
  const row2 = [matrix[8], matrix[9], matrix[10]];
125
+ const cross = [
126
+ row1[1] * row2[2] - row1[2] * row2[1],
127
+ row1[2] * row2[0] - row1[0] * row2[2],
128
+ row1[0] * row2[1] - row1[1] * row2[0],
129
+ ];
137
130
  // Compute scale
138
- const scaleX = pLength(row0);
131
+ const scaleX = Math.hypot(...row0);
139
132
  const row0Norm = normalize(row0);
140
133
  const skewXY = dot(row0Norm, row1);
141
134
  const row1Proj = [
@@ -143,7 +136,7 @@ function decompose(original) {
143
136
  row1[1] - skewXY * row0Norm[1],
144
137
  row1[2] - skewXY * row0Norm[2]
145
138
  ];
146
- const scaleY = pLength(row1Proj);
139
+ const scaleY = Math.hypot(...row1Proj);
147
140
  const row1Norm = normalize(row1Proj);
148
141
  const skewXZ = dot(row0Norm, row2);
149
142
  const skewYZ = dot(row1Norm, row2);
@@ -152,8 +145,9 @@ function decompose(original) {
152
145
  row2[1] - skewXZ * row0Norm[1] - skewYZ * row1Norm[1],
153
146
  row2[2] - skewXZ * row0Norm[2] - skewYZ * row1Norm[2]
154
147
  ];
155
- const scaleZ = pLength(row2Proj);
156
148
  const row2Norm = normalize(row2Proj);
149
+ const determinant = row0[0] * cross[0] + row0[1] * cross[1] + row0[2] * cross[2];
150
+ const scaleZ = Math.hypot(...row2Proj) * (determinant < 0 ? -1 : 1);
157
151
  // Build rotation matrix from orthonormalized vectors
158
152
  const r00 = row0Norm[0], r01 = row1Norm[0], r02 = row2Norm[0];
159
153
  const r10 = row0Norm[1], r11 = row1Norm[1], r12 = row2Norm[1];
@@ -190,7 +184,6 @@ function decompose(original) {
190
184
  qz = 0.25 * s;
191
185
  }
192
186
  [qx, qy, qz] = toZero([qx, qy, qz]);
193
- // const q = gcd(qx, gcd(qy, qz));
194
187
  let q = [Math.abs(qx), Math.abs(qy), Math.abs(qz)].reduce((acc, curr) => {
195
188
  if (acc == 0 || (curr > 0 && curr < acc)) {
196
189
  acc = curr;
@@ -235,16 +228,16 @@ function toZero(v) {
235
228
  // https://drafts.csswg.org/css-transforms-1/#2d-matrix
236
229
  function is2DMatrix(matrix) {
237
230
  // m13,m14, m23, m24, m31, m32, m34, m43 are all 0
238
- return matrix[0 * 4 + 2] === 0 &&
239
- matrix[0 * 4 + 3] === 0 &&
240
- matrix[1 * 4 + 2] === 0 &&
241
- matrix[1 * 4 + 3] === 0 &&
242
- matrix[2 * 4 + 0] === 0 &&
243
- matrix[2 * 4 + 1] === 0 &&
244
- matrix[2 * 4 + 3] === 0 &&
245
- matrix[3 * 4 + 2] === 0 &&
246
- matrix[2 * 4 + 2] === 1 &&
247
- matrix[3 * 4 + 3] === 1;
231
+ return matrix[2] === 0 &&
232
+ matrix[3] === 0 &&
233
+ matrix[6] === 0 &&
234
+ matrix[7] === 0 &&
235
+ matrix[8] === 0 &&
236
+ matrix[9] === 0 &&
237
+ matrix[11] === 0 &&
238
+ matrix[14] === 0 &&
239
+ matrix[10] === 1 &&
240
+ matrix[15] === 1;
248
241
  }
249
242
 
250
243
  export { decompose, epsilon, identity, is2DMatrix, multiply, round, toZero };
@@ -19,14 +19,26 @@ var ValidationLevel;
19
19
  * disable validation
20
20
  */
21
21
  ValidationLevel[ValidationLevel["None"] = 0] = "None";
22
+ /**
23
+ * validate selectors
24
+ */
25
+ ValidationLevel[ValidationLevel["Selector"] = 1] = "Selector";
26
+ /**
27
+ * validate at-rules
28
+ */
29
+ ValidationLevel[ValidationLevel["AtRule"] = 2] = "AtRule";
30
+ /**
31
+ * validate declarations
32
+ */
33
+ ValidationLevel[ValidationLevel["Declaration"] = 4] = "Declaration";
22
34
  /**
23
35
  * validate selectors and at-rules
24
36
  */
25
- ValidationLevel[ValidationLevel["Default"] = 1] = "Default";
37
+ ValidationLevel[ValidationLevel["Default"] = 3] = "Default";
26
38
  /**
27
39
  * validate selectors, at-rules and declarations
28
40
  */
29
- ValidationLevel[ValidationLevel["All"] = 2] = "All"; // selectors + at-rules + declarations
41
+ ValidationLevel[ValidationLevel["All"] = 7] = "All"; // selectors + at-rules + declarations
30
42
  })(ValidationLevel || (ValidationLevel = {}));
31
43
  /**
32
44
  * enum of all token types
@@ -415,6 +427,23 @@ var EnumToken;
415
427
  * invalid declaration node type
416
428
  */
417
429
  EnumToken[EnumToken["InvalidDeclarationNodeType"] = 94] = "InvalidDeclarationNodeType";
430
+ /* css module nodes */
431
+ /**
432
+ * composes token node type
433
+ */
434
+ EnumToken[EnumToken["ComposesSelectorNodeType"] = 95] = "ComposesSelectorNodeType";
435
+ /**
436
+ * css variable token type
437
+ */
438
+ EnumToken[EnumToken["CssVariableTokenType"] = 96] = "CssVariableTokenType";
439
+ /**
440
+ * css variable import token type
441
+ */
442
+ EnumToken[EnumToken["CssVariableImportTokenType"] = 97] = "CssVariableImportTokenType";
443
+ /**
444
+ * css variable declaration map token type
445
+ */
446
+ EnumToken[EnumToken["CssVariableDeclarationMapTokenType"] = 98] = "CssVariableDeclarationMapTokenType";
418
447
  /* aliases */
419
448
  /**
420
449
  * alias for time token type
@@ -531,7 +560,7 @@ var EnumToken;
531
560
  var ColorType;
532
561
  (function (ColorType) {
533
562
  /**
534
- * system colors
563
+ * deprecated system colors
535
564
  */
536
565
  ColorType[ColorType["SYS"] = 0] = "SYS";
537
566
  /**
@@ -539,7 +568,7 @@ var ColorType;
539
568
  */
540
569
  ColorType[ColorType["DPSYS"] = 1] = "DPSYS";
541
570
  /**
542
- * colors as literals
571
+ * named colors
543
572
  */
544
573
  ColorType[ColorType["LIT"] = 2] = "LIT";
545
574
  /**
@@ -639,5 +668,47 @@ var ColorType;
639
668
  */
640
669
  ColorType[ColorType["DEVICE_CMYK"] = 7] = "DEVICE_CMYK";
641
670
  })(ColorType || (ColorType = {}));
671
+ var ModuleCaseTransformEnum;
672
+ (function (ModuleCaseTransformEnum) {
673
+ /**
674
+ * export class names as-is
675
+ */
676
+ ModuleCaseTransformEnum[ModuleCaseTransformEnum["IgnoreCase"] = 1] = "IgnoreCase";
677
+ /**
678
+ * transform mapping key name to camel case
679
+ */
680
+ ModuleCaseTransformEnum[ModuleCaseTransformEnum["CamelCase"] = 2] = "CamelCase";
681
+ /**
682
+ * transform class names and mapping key name to camel case
683
+ */
684
+ ModuleCaseTransformEnum[ModuleCaseTransformEnum["CamelCaseOnly"] = 4] = "CamelCaseOnly";
685
+ /**
686
+ * transform mapping key name to dash case
687
+ */
688
+ ModuleCaseTransformEnum[ModuleCaseTransformEnum["DashCase"] = 8] = "DashCase";
689
+ /**
690
+ * transform class names and mapping key name to dash case
691
+ */
692
+ ModuleCaseTransformEnum[ModuleCaseTransformEnum["DashCaseOnly"] = 16] = "DashCaseOnly";
693
+ })(ModuleCaseTransformEnum || (ModuleCaseTransformEnum = {}));
694
+ var ModuleScopeEnumOptions;
695
+ (function (ModuleScopeEnumOptions) {
696
+ /**
697
+ * use the global scope
698
+ */
699
+ ModuleScopeEnumOptions[ModuleScopeEnumOptions["Global"] = 32] = "Global";
700
+ /**
701
+ * use the local scope
702
+ */
703
+ ModuleScopeEnumOptions[ModuleScopeEnumOptions["Local"] = 64] = "Local";
704
+ /**
705
+ * do not allow selector without an id or class
706
+ */
707
+ ModuleScopeEnumOptions[ModuleScopeEnumOptions["Pure"] = 128] = "Pure";
708
+ /**
709
+ * export using ICSS module format
710
+ */
711
+ ModuleScopeEnumOptions[ModuleScopeEnumOptions["ICSS"] = 256] = "ICSS";
712
+ })(ModuleScopeEnumOptions || (ModuleScopeEnumOptions = {}));
642
713
 
643
- export { ColorType, EnumToken, SyntaxValidationResult, ValidationLevel };
714
+ export { ColorType, EnumToken, ModuleCaseTransformEnum, ModuleScopeEnumOptions, SyntaxValidationResult, ValidationLevel };
@@ -12,28 +12,28 @@ var WalkerOptionEnum;
12
12
  */
13
13
  WalkerOptionEnum[WalkerOptionEnum["Stop"] = 2] = "Stop";
14
14
  /**
15
- * ignore node and process children
15
+ * ignore the current node and process its children
16
16
  */
17
17
  WalkerOptionEnum[WalkerOptionEnum["Children"] = 4] = "Children";
18
18
  /**
19
- * ignore children
19
+ * ignore the current node children
20
20
  */
21
21
  WalkerOptionEnum[WalkerOptionEnum["IgnoreChildren"] = 8] = "IgnoreChildren";
22
22
  })(WalkerOptionEnum || (WalkerOptionEnum = {}));
23
23
  /**
24
24
  * event types for the walkValues function
25
25
  */
26
- var WalkerValueEvent;
27
- (function (WalkerValueEvent) {
26
+ var WalkerEvent;
27
+ (function (WalkerEvent) {
28
28
  /**
29
29
  * enter node
30
30
  */
31
- WalkerValueEvent[WalkerValueEvent["Enter"] = 1] = "Enter";
31
+ WalkerEvent[WalkerEvent["Enter"] = 1] = "Enter";
32
32
  /**
33
33
  * leave node
34
34
  */
35
- WalkerValueEvent[WalkerValueEvent["Leave"] = 2] = "Leave";
36
- })(WalkerValueEvent || (WalkerValueEvent = {}));
35
+ WalkerEvent[WalkerEvent["Leave"] = 2] = "Leave";
36
+ })(WalkerEvent || (WalkerEvent = {}));
37
37
  /**
38
38
  * walk ast nodes
39
39
  * @param node initial node
@@ -64,11 +64,10 @@ var WalkerValueEvent;
64
64
  * }
65
65
  * ```
66
66
  *
67
- * Using a filter to control the walk process:
67
+ * Using a {@link filter} function to control the ast traversal. the filter function returns a value of type {@link WalkerOption}.
68
68
  *
69
69
  * ```ts
70
- *
71
- * import {walk} from '@tbela99/css-parser';
70
+ * import {EnumToken, transform, walk, WalkerOptionEnum} from '@tbela99/css-parser';
72
71
  *
73
72
  * const css = `
74
73
  * body { color: color(from var(--base-color) display-p3 r calc(g + 0.24) calc(b + 0.15)); }
@@ -84,17 +83,28 @@ var WalkerValueEvent;
84
83
  * }
85
84
  * `;
86
85
  *
87
- * for (const {node, parent, root} of walk(ast, (node) => {
86
+ * function filter(node) {
88
87
  *
89
88
  * if (node.typ == EnumToken.AstRule && node.sel.includes('html')) {
90
89
  *
91
90
  * // skip the children of the current node
92
91
  * return WalkerOptionEnum.IgnoreChildren;
93
92
  * }
94
- * })) {
93
+ * }
95
94
  *
96
- * // do something with node
95
+ * const result = await transform(css);
96
+ * for (const {node} of walk(result.ast, filter)) {
97
+ *
98
+ * console.error([EnumToken[node.typ]]);
97
99
  * }
100
+ *
101
+ * // [ "StyleSheetNodeType" ]
102
+ * // [ "RuleNodeType" ]
103
+ * // [ "DeclarationNodeType" ]
104
+ * // [ "RuleNodeType" ]
105
+ * // [ "DeclarationNodeType" ]
106
+ * // [ "RuleNodeType" ]
107
+ * // [ "DeclarationNodeType" ]
98
108
  * ```
99
109
  */
100
110
  function* walk(node, filter, reverse) {
@@ -102,7 +112,8 @@ function* walk(node, filter, reverse) {
102
112
  const root = node;
103
113
  const map = new Map;
104
114
  let isNumeric = false;
105
- while ((node = parents.shift())) {
115
+ let i = 0;
116
+ while ((node = parents[i++])) {
106
117
  let option = null;
107
118
  if (filter != null) {
108
119
  option = filter(node);
@@ -121,8 +132,8 @@ function* walk(node, filter, reverse) {
121
132
  yield { node, parent: map.get(node), root };
122
133
  }
123
134
  if ('chi' in node && (!isNumeric || ((option & WalkerOptionEnum.IgnoreChildren) === 0))) {
124
- parents.unshift(...node.chi[reverse ? 'reverse' : 'slice']());
125
- for (const child of node.chi.slice()) {
135
+ parents.splice(i, 0, ...node.chi[reverse ? 'reverse' : 'slice']());
136
+ for (const child of node.chi) {
126
137
  map.set(child, node);
127
138
  }
128
139
  }
@@ -139,55 +150,68 @@ function* walk(node, filter, reverse) {
139
150
  *
140
151
  * ```ts
141
152
  *
142
- * import {EnumToken, walk} from '@tbela99/css-parser';
153
+ * import {AstDeclaration, EnumToken, transform, walkValues} from '@tbela99/css-parser';
143
154
  *
144
155
  * const css = `
145
156
  * 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
  * `;
157
158
  *
158
- * for (const {value} of walkValues(result.ast.chi[0].chi[0].val, null, null,true)) {
159
+ * const result = await transform(css);
160
+ * const declaration = result.ast.chi[0].chi[0] as AstDeclaration;
161
+ *
162
+ * // walk the node attribute's tokens in reverse order
163
+ * for (const {value} of walkValues(declaration.val, null, null,true)) {
159
164
  *
160
165
  * console.error([EnumToken[value.typ], value.val]);
161
166
  * }
162
167
  *
168
+ * // [ "Color", "color" ]
169
+ * // [ "FunctionTokenType", "calc" ]
170
+ * // [ "Number", 0.15 ]
171
+ * // [ "Add", undefined ]
172
+ * // [ "Iden", "b" ]
173
+ * // [ "Whitespace", undefined ]
174
+ * // [ "FunctionTokenType", "calc" ]
175
+ * // [ "Number", 0.24 ]
176
+ * // [ "Add", undefined ]
177
+ * // [ "Iden", "g" ]
178
+ * // [ "Whitespace", undefined ]
179
+ * // [ "Iden", "r" ]
180
+ * // [ "Whitespace", undefined ]
181
+ * // [ "Iden", "display-p3" ]
182
+ * // [ "Whitespace", undefined ]
183
+ * // [ "FunctionTokenType", "var" ]
184
+ * // [ "DashedIden", "--base-color" ]
185
+ * // [ "Whitespace", undefined ]
186
+ * // [ "Iden", "from" ]
187
+ * ```
163
188
  */
164
189
  function* walkValues(values, root = null, filter, reverse) {
165
- // const set = new Set<Token>();
166
190
  const stack = values.slice();
167
191
  const map = new Map;
168
192
  let previous = null;
169
193
  if (filter != null && typeof filter == 'function') {
170
194
  filter = {
171
- event: WalkerValueEvent.Enter,
195
+ event: WalkerEvent.Enter,
172
196
  fn: filter
173
197
  };
174
198
  }
175
199
  else if (filter == null) {
176
200
  filter = {
177
- event: WalkerValueEvent.Enter
201
+ event: WalkerEvent.Enter
178
202
  };
179
203
  }
180
204
  let isNumeric = false;
181
- const eventType = filter.event ?? WalkerValueEvent.Enter;
205
+ const eventType = filter.event ?? WalkerEvent.Enter;
182
206
  while (stack.length > 0) {
183
207
  let value = reverse ? stack.pop() : stack.shift();
184
208
  let option = null;
185
- if (filter.fn != null && (eventType & WalkerValueEvent.Enter)) {
209
+ if (filter.fn != null && (eventType & WalkerEvent.Enter)) {
186
210
  const isValid = filter.type == null || value.typ == filter.type ||
187
211
  (Array.isArray(filter.type) && filter.type.includes(value.typ)) ||
188
212
  (typeof filter.type == 'function' && filter.type(value));
189
213
  if (isValid) {
190
- option = filter.fn(value, map.get(value) ?? root, WalkerValueEvent.Enter);
214
+ option = filter.fn(value, map.get(value) ?? root, WalkerEvent.Enter);
191
215
  isNumeric = typeof option == 'number';
192
216
  if (isNumeric && (option & WalkerOptionEnum.Stop)) {
193
217
  return;
@@ -196,12 +220,15 @@ function* walkValues(values, root = null, filter, reverse) {
196
220
  continue;
197
221
  }
198
222
  // @ts-ignore
199
- if (option != null && typeof option == 'object' && 'typ' in option) {
200
- map.set(option, map.get(value) ?? root);
223
+ if (option != null && typeof option == 'object' && ('typ' in option || Array.isArray(option))) {
224
+ const op = Array.isArray(option) ? option : [option];
225
+ for (const o of op) {
226
+ map.set(o, map.get(value) ?? root);
227
+ }
228
+ stack[reverse ? 'push' : 'unshift'](...op);
201
229
  }
202
230
  }
203
231
  }
204
- // if ((eventType & WalkerValueEvent.Enter) && (!isNumeric || ((option as number) & WalkerOptionEnum.Children) === 0)) {
205
232
  yield {
206
233
  value,
207
234
  parent: map.get(value) ?? root,
@@ -210,7 +237,6 @@ function* walkValues(values, root = null, filter, reverse) {
210
237
  // @ts-ignore
211
238
  root: root ?? null
212
239
  };
213
- // }
214
240
  if ('chi' in value && (!isNumeric || (option & WalkerOptionEnum.IgnoreChildren) === 0)) {
215
241
  const sliced = value.chi.slice();
216
242
  for (const child of sliced) {
@@ -222,12 +248,12 @@ function* walkValues(values, root = null, filter, reverse) {
222
248
  const values = [];
223
249
  if ('l' in value && value.l != null) {
224
250
  // @ts-ignore
225
- values[reverse ? 'push' : 'unshift'](value.l);
251
+ values.push(value.l);
226
252
  // @ts-ignore
227
253
  map.set(value.l, value);
228
254
  }
229
255
  if ('op' in value && typeof value.op == 'object') {
230
- values[reverse ? 'push' : 'unshift'](value.op);
256
+ values.push(value.op);
231
257
  // @ts-ignore
232
258
  map.set(value.op, value);
233
259
  }
@@ -235,14 +261,14 @@ function* walkValues(values, root = null, filter, reverse) {
235
261
  if (Array.isArray(value.r)) {
236
262
  for (const r of value.r) {
237
263
  // @ts-ignore
238
- values[reverse ? 'push' : 'unshift'](r);
264
+ values.push(r);
239
265
  // @ts-ignore
240
266
  map.set(r, value);
241
267
  }
242
268
  }
243
269
  else {
244
270
  // @ts-ignore
245
- values[reverse ? 'push' : 'unshift'](value.r);
271
+ values.push(value.r);
246
272
  // @ts-ignore
247
273
  map.set(value.r, value);
248
274
  }
@@ -251,31 +277,24 @@ function* walkValues(values, root = null, filter, reverse) {
251
277
  stack[reverse ? 'push' : 'unshift'](...values);
252
278
  }
253
279
  }
254
- if ((eventType & WalkerValueEvent.Leave) && filter.fn != null) {
280
+ if ((eventType & WalkerEvent.Leave) && filter.fn != null) {
255
281
  const isValid = filter.type == null || value.typ == filter.type ||
256
282
  (Array.isArray(filter.type) && filter.type.includes(value.typ)) ||
257
283
  (typeof filter.type == 'function' && filter.type(value));
258
284
  if (isValid) {
259
- option = filter.fn(value, map.get(value), WalkerValueEvent.Leave);
285
+ option = filter.fn(value, map.get(value), WalkerEvent.Leave);
260
286
  // @ts-ignore
261
- if (option != null && 'typ' in option) {
262
- map.set(option, map.get(value) ?? root);
287
+ if (option != null && ('typ' in option || Array.isArray(option))) {
288
+ const op = Array.isArray(option) ? option : [option];
289
+ for (const o of op) {
290
+ map.set(o, map.get(value) ?? root);
291
+ }
292
+ stack[reverse ? 'push' : 'unshift'](...op);
263
293
  }
264
294
  }
265
295
  }
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
- // }
277
296
  previous = value;
278
297
  }
279
298
  }
280
299
 
281
- export { WalkerOptionEnum, WalkerValueEvent, walk, walkValues };
300
+ export { WalkerEvent, WalkerOptionEnum, walk, walkValues };
@@ -10,6 +10,9 @@ function dirname(path) {
10
10
  //
11
11
  // return path;
12
12
  // }
13
+ if (path === '') {
14
+ return '';
15
+ }
13
16
  let i = 0;
14
17
  let parts = [''];
15
18
  for (; i < path.length; i++) {
@@ -17,9 +20,10 @@ function dirname(path) {
17
20
  if (chr == '/') {
18
21
  parts.push('');
19
22
  }
20
- else if (chr == '?' || chr == '#') {
21
- break;
22
- }
23
+ // else if (chr == '?' || chr == '#') {
24
+ //
25
+ // break;
26
+ // }
23
27
  else {
24
28
  parts[parts.length - 1] += chr;
25
29
  }
@@ -33,6 +37,12 @@ function dirname(path) {
33
37
  * @private
34
38
  */
35
39
  function splitPath(result) {
40
+ if (result.length == 0) {
41
+ return { parts: [], i: 0 };
42
+ }
43
+ if (result === '/') {
44
+ return { parts: ['/'], i: 0 };
45
+ }
36
46
  const parts = [''];
37
47
  let i = 0;
38
48
  for (; i < result.length; i++) {
@@ -74,6 +84,23 @@ function resolve(url, currentDirectory, cwd) {
74
84
  relative: url
75
85
  };
76
86
  }
87
+ cwd ??= '';
88
+ currentDirectory ??= '';
89
+ if (currentDirectory !== '' && url.startsWith(currentDirectory + '/')) {
90
+ return {
91
+ absolute: url,
92
+ relative: url.slice(currentDirectory.length + 1)
93
+ };
94
+ }
95
+ if (currentDirectory === '' && cwd !== '' && url.startsWith(cwd == '/' ? cwd : cwd + '/')) {
96
+ cwd = normalize(cwd);
97
+ const absolute = normalize(url);
98
+ const prefix = cwd == '/' ? cwd : cwd + '/';
99
+ return {
100
+ absolute,
101
+ relative: absolute.startsWith(prefix) ? absolute.slice(prefix.length) : diff(absolute, cwd)
102
+ };
103
+ }
77
104
  if (matchUrl.test(currentDirectory)) {
78
105
  const path = new URL(url, currentDirectory).href;
79
106
  return {
@@ -88,9 +115,15 @@ function resolve(url, currentDirectory, cwd) {
88
115
  else if (currentDirectory.charAt(0) == '/') {
89
116
  result = dirname(currentDirectory) + '/' + url;
90
117
  }
91
- let { parts, i } = splitPath(result);
92
- const absolute = parts.join('/');
93
- const { parts: dirs } = splitPath(cwd ?? currentDirectory);
118
+ const absolute = normalize(result);
119
+ return {
120
+ absolute,
121
+ relative: absolute === '' ? '' : diff(absolute, cwd ?? currentDirectory),
122
+ };
123
+ }
124
+ function diff(path1, path2) {
125
+ let { parts } = splitPath(path1);
126
+ const { parts: dirs } = splitPath(path2);
94
127
  for (const p of dirs) {
95
128
  if (parts[0] == p) {
96
129
  parts.shift();
@@ -99,10 +132,36 @@ function resolve(url, currentDirectory, cwd) {
99
132
  parts.unshift('..');
100
133
  }
101
134
  }
102
- return {
103
- absolute,
104
- relative: parts.join('/') + (i < result.length ? result.slice(i) : '')
105
- };
135
+ return parts.join('/');
136
+ }
137
+ function normalize(path) {
138
+ let parts = [];
139
+ let i = 0;
140
+ for (; i < path.length; i++) {
141
+ const chr = path.charAt(i);
142
+ if (chr == '/') {
143
+ if (parts.length == 0 || parts[parts.length - 1] !== '') {
144
+ parts.push('');
145
+ }
146
+ }
147
+ else if (chr == '?' || chr == '#') {
148
+ break;
149
+ }
150
+ else {
151
+ parts[parts.length - 1] += chr;
152
+ }
153
+ }
154
+ let k = -1;
155
+ while (++k < parts.length) {
156
+ if (parts[k] == '.') {
157
+ parts.splice(k--, 1);
158
+ }
159
+ else if (parts[k] == '..') {
160
+ parts.splice(k - 1, 2);
161
+ k -= 2;
162
+ }
163
+ }
164
+ return (path.charAt(0) == '/' ? '/' : '') + parts.join('/');
106
165
  }
107
166
 
108
167
  export { dirname, matchUrl, resolve };
@@ -25,8 +25,13 @@ class PropertyList {
25
25
  });
26
26
  }
27
27
  add(...declarations) {
28
+ let name;
28
29
  for (const declaration of declarations) {
29
- if (declaration.typ != EnumToken.DeclarationNodeType || (Array.isArray(this.options.removeDuplicateDeclarations) ? this.options.removeDuplicateDeclarations.includes(declaration.nam) : !this.options.removeDuplicateDeclarations)) {
30
+ name = declaration.typ != EnumToken.DeclarationNodeType ? null : declaration.nam.toLowerCase();
31
+ if (declaration.typ != EnumToken.DeclarationNodeType ||
32
+ 'composes' === name ||
33
+ (typeof this.options.removeDuplicateDeclarations === 'string' && this.options.removeDuplicateDeclarations === name) ||
34
+ (Array.isArray(this.options.removeDuplicateDeclarations) ? this.options.removeDuplicateDeclarations.includes(declaration.nam) : !this.options.removeDuplicateDeclarations)) {
30
35
  this.declarations.set(Number(Math.random().toString().slice(2)).toString(36), declaration);
31
36
  continue;
32
37
  }