@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
@@ -7,12 +7,12 @@ import { walkValues } from './walk.js';
7
7
 
8
8
  function expand(ast) {
9
9
  //
10
- if (![4 /* NodeType.RuleNodeType */, 2 /* NodeType.StyleSheetNodeType */, 3 /* NodeType.AtRuleNodeType */].includes(ast.typ)) {
10
+ if (![EnumToken.RuleNodeType, EnumToken.StyleSheetNodeType, EnumToken.AtRuleNodeType].includes(ast.typ)) {
11
11
  return ast;
12
12
  }
13
- if (4 /* NodeType.RuleNodeType */ == ast.typ) {
13
+ if (EnumToken.RuleNodeType == ast.typ) {
14
14
  return {
15
- typ: 2 /* NodeType.StyleSheetNodeType */,
15
+ typ: EnumToken.StyleSheetNodeType,
16
16
  chi: expandRule(ast)
17
17
  };
18
18
  }
@@ -24,16 +24,16 @@ function expand(ast) {
24
24
  for (let i = 0; i < ast.chi.length; i++) {
25
25
  // @ts-ignore
26
26
  const node = ast.chi[i];
27
- if (node.typ == 4 /* NodeType.RuleNodeType */) {
27
+ if (node.typ == EnumToken.RuleNodeType) {
28
28
  // @ts-ignore
29
29
  result.chi.push(...expandRule(node));
30
30
  // i += expanded.length - 1;
31
31
  }
32
- else if (node.typ == 3 /* NodeType.AtRuleNodeType */ && 'chi' in node) {
32
+ else if (node.typ == EnumToken.AtRuleNodeType && 'chi' in node) {
33
33
  let hasRule = false;
34
34
  let j = node.chi.length;
35
35
  while (j--) {
36
- if (node.chi[j].typ == 4 /* NodeType.RuleNodeType */ || node.chi[j].typ == 3 /* NodeType.AtRuleNodeType */) {
36
+ if (node.chi[j].typ == EnumToken.RuleNodeType || node.chi[j].typ == EnumToken.AtRuleNodeType) {
37
37
  hasRule = true;
38
38
  break;
39
39
  }
@@ -51,10 +51,10 @@ function expand(ast) {
51
51
  function expandRule(node) {
52
52
  const ast = { ...node, chi: node.chi.slice() };
53
53
  const result = [];
54
- if (ast.typ == 4 /* NodeType.RuleNodeType */) {
54
+ if (ast.typ == EnumToken.RuleNodeType) {
55
55
  let i = 0;
56
56
  for (; i < ast.chi.length; i++) {
57
- if (ast.chi[i].typ == 4 /* NodeType.RuleNodeType */) {
57
+ if (ast.chi[i].typ == EnumToken.RuleNodeType) {
58
58
  const rule = ast.chi[i];
59
59
  if (!rule.sel.includes('&')) {
60
60
  const selRule = splitRule(rule.sel);
@@ -70,7 +70,7 @@ function expandRule(node) {
70
70
  ast.chi.splice(i--, 1);
71
71
  result.push(...expandRule(rule));
72
72
  }
73
- else if (ast.chi[i].typ == 3 /* NodeType.AtRuleNodeType */) {
73
+ else if (ast.chi[i].typ == EnumToken.AtRuleNodeType) {
74
74
  let astAtRule = ast.chi[i];
75
75
  const values = [];
76
76
  if (astAtRule.nam == 'scope') {
@@ -85,7 +85,7 @@ function expandRule(node) {
85
85
  // @ts-ignore
86
86
  astAtRule.chi.length = 0;
87
87
  for (const r of expandRule(clone)) {
88
- if (r.typ == 3 /* NodeType.AtRuleNodeType */ && 'chi' in r) {
88
+ if (r.typ == EnumToken.AtRuleNodeType && 'chi' in r) {
89
89
  if (astAtRule.val !== '' && r.val !== '') {
90
90
  if (astAtRule.nam == 'media' && r.nam == 'media') {
91
91
  r.val = astAtRule.val + ' and ' + r.val;
@@ -97,7 +97,7 @@ function expandRule(node) {
97
97
  // @ts-ignore
98
98
  values.push(r);
99
99
  }
100
- else if (r.typ == 4 /* NodeType.RuleNodeType */) {
100
+ else if (r.typ == EnumToken.RuleNodeType) {
101
101
  // @ts-ignore
102
102
  astAtRule.chi.push(...expandRule(r));
103
103
  }
@@ -1,21 +1,22 @@
1
1
  import { EnumToken } from '../types.js';
2
- import { reduceNumber, renderToken } from '../../renderer/render.js';
3
2
  import { walkValues } from '../walk.js';
4
- import { MinifyFeature } from '../utiles/minifyfeature.js';
3
+ import { MinifyFeature } from '../utils/minifyfeature.js';
4
+ import { IterableWeakSet } from '../../iterable/weakset.js';
5
+ import { evaluate } from '../math/expression.js';
5
6
 
6
- class ComputeCalcExpression extends MinifyFeature {
7
+ class ComputeCalcExpressionFeature extends MinifyFeature {
7
8
  static get ordering() {
8
9
  return 1;
9
10
  }
10
11
  static register(options) {
11
12
  if (options.computeCalcExpression) {
12
13
  for (const feature of options.features) {
13
- if (feature instanceof ComputeCalcExpression) {
14
+ if (feature instanceof ComputeCalcExpressionFeature) {
14
15
  return;
15
16
  }
16
17
  }
17
18
  // @ts-ignore
18
- options.features.push(new ComputeCalcExpression());
19
+ options.features.push(new ComputeCalcExpressionFeature());
19
20
  }
20
21
  }
21
22
  run(ast) {
@@ -24,15 +25,35 @@ class ComputeCalcExpression extends MinifyFeature {
24
25
  }
25
26
  // @ts-ignore
26
27
  for (const node of ast.chi) {
27
- if (node.typ != 5 /* NodeType.DeclarationNodeType */) {
28
+ if (node.typ != EnumToken.DeclarationNodeType) {
28
29
  continue;
29
30
  }
30
- const set = new Set;
31
- for (const { parent } of walkValues(node.val)) {
32
- if (parent != null && parent.typ == EnumToken.FunctionTokenType && parent.val == 'calc') {
31
+ const set = new IterableWeakSet;
32
+ for (const { value, parent } of walkValues(node.val)) {
33
+ if (value != null && value.typ == EnumToken.FunctionTokenType && value.val == 'calc') {
33
34
  if (!set.has(parent)) {
34
- set.add(parent);
35
- parent.chi = evaluate(parent.chi);
35
+ set.add(value);
36
+ value.chi = evaluate(value.chi);
37
+ if (value.chi.length == 1 && value.chi[0].typ != EnumToken.BinaryExpressionTokenType) {
38
+ if (parent != null) {
39
+ if (parent.typ == EnumToken.BinaryExpressionTokenType) {
40
+ if (parent.l == value) {
41
+ parent.l = value.chi[0];
42
+ }
43
+ else {
44
+ parent.r = value.chi[0];
45
+ }
46
+ }
47
+ else {
48
+ for (let i = 0; i < parent.chi.length; i++) {
49
+ if (parent.chi[i] == value) {
50
+ parent.chi.splice(i, 1, value.chi[0]);
51
+ break;
52
+ }
53
+ }
54
+ }
55
+ }
56
+ }
36
57
  }
37
58
  }
38
59
  }
@@ -40,217 +61,5 @@ class ComputeCalcExpression extends MinifyFeature {
40
61
  return ast;
41
62
  }
42
63
  }
43
- /**
44
- * evaluate arithmetic operation
45
- * @param l
46
- * @param r
47
- * @param op
48
- */
49
- function doEvaluate(l, r, op) {
50
- const defaultReturn = {
51
- typ: EnumToken.BinaryExpressionTokenType,
52
- op,
53
- l,
54
- r
55
- };
56
- if (!isScalarToken(l) || !isScalarToken(r)) {
57
- return defaultReturn;
58
- }
59
- if ((op == EnumToken.Add || op == EnumToken.Sub)) {
60
- // @ts-ignore
61
- if (l.typ != r.typ || Number.isNaN(+l.val) || Number.isNaN(r.val)) {
62
- return defaultReturn;
63
- }
64
- // @ts-ignore
65
- return { ...l, val: reduceNumber(+l.val + (op == EnumToken.Add ? +r.val : -1 * r.val)) };
66
- }
67
- else {
68
- // @ts-ignore
69
- let val;
70
- if (op == EnumToken.Div) {
71
- if (r.typ != EnumToken.NumberTokenType || r.val == '0') {
72
- return defaultReturn;
73
- }
74
- // @ts-ignore
75
- val = reduceNumber(l.val / r.val);
76
- }
77
- else {
78
- // @ts-ignore
79
- val = reduceNumber(r.val * l.val);
80
- }
81
- let result;
82
- if (r.typ == EnumToken.NumberTokenType || op == EnumToken.Div) {
83
- result = { ...l, val };
84
- }
85
- else {
86
- // @ts-ignore
87
- result = { ...r, val };
88
- }
89
- if (renderToken(result).length <= renderToken(defaultReturn).length) {
90
- return result;
91
- }
92
- }
93
- return defaultReturn;
94
- }
95
- /**
96
- * evaluate an array of tokens
97
- * @param tokens
98
- */
99
- function evaluate(tokens) {
100
- const nodes = inlineExpression(evaluateExpression(buildExpression(tokens)));
101
- if (nodes.length <= 1) {
102
- return nodes;
103
- }
104
- const map = new Map;
105
- let token;
106
- let i;
107
- for (i = 0; i < nodes.length; i++) {
108
- token = nodes[i];
109
- if (token.typ == EnumToken.Add) {
110
- continue;
111
- }
112
- if (token.typ == EnumToken.Sub) {
113
- if (!isScalarToken(nodes[i + 1])) {
114
- token = { typ: EnumToken.ListToken, chi: [nodes[i], nodes[i + 1]] };
115
- }
116
- else {
117
- token = doEvaluate(nodes[i + 1], { typ: EnumToken.NumberTokenType, val: '-1' }, EnumToken.Mul);
118
- }
119
- i++;
120
- }
121
- if (!map.has(token.typ)) {
122
- map.set(token.typ, [token]);
123
- }
124
- else {
125
- map.get(token.typ).push(token);
126
- }
127
- }
128
- return [...map].reduce((acc, curr) => {
129
- const token = curr[1].reduce((acc, curr) => doEvaluate(acc, curr, EnumToken.Add));
130
- if (token.typ != EnumToken.BinaryExpressionTokenType) {
131
- if ('val' in token && +token.val < 0) {
132
- acc.push({ typ: EnumToken.Sub }, { ...token, val: String(-token.val) });
133
- return acc;
134
- }
135
- }
136
- if (acc.length > 0 && curr[0] != EnumToken.ListToken) {
137
- acc.push({ typ: EnumToken.Add });
138
- }
139
- acc.push(token);
140
- return acc;
141
- }, []);
142
- }
143
- /**
144
- * convert BinaryExpression into an array
145
- * @param token
146
- */
147
- function inlineExpression(token) {
148
- const result = [];
149
- if (token.typ == EnumToken.BinaryExpressionTokenType) {
150
- if ([EnumToken.Mul, EnumToken.Div].includes(token.op)) {
151
- result.push(token);
152
- }
153
- else {
154
- result.push(...inlineExpression(token.l), { typ: token.op }, ...inlineExpression(token.r));
155
- }
156
- }
157
- else {
158
- result.push(token);
159
- }
160
- return result;
161
- }
162
- /**
163
- * evaluate expression
164
- * @param token
165
- */
166
- function evaluateExpression(token) {
167
- if (token.typ != EnumToken.BinaryExpressionTokenType) {
168
- return token;
169
- }
170
- if (token.r.typ == EnumToken.BinaryExpressionTokenType) {
171
- token.r = evaluateExpression(token.r);
172
- }
173
- if (token.l.typ == EnumToken.BinaryExpressionTokenType) {
174
- token.l = evaluateExpression(token.l);
175
- }
176
- const result = doEvaluate(token.l, token.r, token.op);
177
- if (result.typ == EnumToken.BinaryExpressionTokenType &&
178
- [EnumToken.Mul, EnumToken.Div].includes(result.op)) {
179
- // wrap expression
180
- if (result.l.typ == EnumToken.BinaryExpressionTokenType && [EnumToken.Sub, EnumToken.Add].includes(result.l.op)) {
181
- result.l = { typ: EnumToken.ParensTokenType, chi: [result.l] };
182
- }
183
- else if (result.r.typ == EnumToken.BinaryExpressionTokenType && [EnumToken.Sub, EnumToken.Add].includes(result.r.op)) {
184
- result.r = { typ: EnumToken.ParensTokenType, chi: [result.r] };
185
- }
186
- }
187
- return result;
188
- }
189
- function isScalarToken(token) {
190
- return token.typ != EnumToken.BinaryExpressionTokenType && token.typ != EnumToken.ParensTokenType && token.typ != EnumToken.FunctionTokenType;
191
- }
192
- /**
193
- *
194
- * generate binary expression tree
195
- * @param tokens
196
- */
197
- function buildExpression(tokens) {
198
- return factor(factor(tokens.filter(t => t.typ != EnumToken.WhitespaceTokenType), ['/', '*']), ['+', '-'])[0];
199
- }
200
- function getArithmeticOperation(op) {
201
- if (op == '+') {
202
- return EnumToken.Add;
203
- }
204
- if (op == '-') {
205
- return EnumToken.Sub;
206
- }
207
- if (op == '/') {
208
- return EnumToken.Div;
209
- }
210
- return EnumToken.Mul;
211
- }
212
- /**
213
- *
214
- * generate binary expression tree
215
- * @param token
216
- */
217
- function factorToken(token) {
218
- if (token.typ == EnumToken.ParensTokenType || (token.typ == EnumToken.FunctionTokenType && token.val == 'calc')) {
219
- if (token.typ == EnumToken.FunctionTokenType && token.val == 'calc') {
220
- token = { ...token, typ: EnumToken.ParensTokenType };
221
- // @ts-ignore
222
- delete token.val;
223
- }
224
- return buildExpression(token.chi);
225
- }
226
- return token;
227
- }
228
- /**
229
- * generate binary expression tree
230
- * @param tokens
231
- * @param ops
232
- */
233
- function factor(tokens, ops) {
234
- let isOp;
235
- const opList = [EnumToken.Add, EnumToken.Sub, EnumToken.Div, EnumToken.Mul];
236
- if (tokens.length == 1) {
237
- return [factorToken(tokens[0])];
238
- }
239
- for (let i = 0; i < tokens.length; i++) {
240
- isOp = opList.includes(tokens[i].typ);
241
- if (isOp ||
242
- // @ts-ignore
243
- (tokens[i].typ == EnumToken.LiteralTokenType && ops.includes(tokens[i].val))) {
244
- tokens.splice(i - 1, 3, {
245
- typ: EnumToken.BinaryExpressionTokenType,
246
- op: isOp ? tokens[i].typ : getArithmeticOperation(tokens[i].val),
247
- l: factorToken(tokens[i - 1]),
248
- r: factorToken(tokens[i + 1])
249
- });
250
- i--;
251
- }
252
- }
253
- return tokens;
254
- }
255
64
 
256
- export { ComputeCalcExpression };
65
+ export { ComputeCalcExpressionFeature };
@@ -1,3 +1,3 @@
1
- export { InlineCssVariables } from './inlinecssvariables.js';
2
- export { ComputeShorthand } from './shorthand.js';
3
- export { ComputeCalcExpression } from './calc.js';
1
+ export { InlineCssVariablesFeature } from './inlinecssvariables.js';
2
+ export { ComputeShorthandFeature } from './shorthand.js';
3
+ export { ComputeCalcExpressionFeature } from './calc.js';
@@ -1,34 +1,58 @@
1
1
  import { EnumToken } from '../types.js';
2
2
  import { walkValues } from '../walk.js';
3
- import { MinifyFeature } from '../utiles/minifyfeature.js';
3
+ import { MinifyFeature } from '../utils/minifyfeature.js';
4
+ import { IterableWeakSet } from '../../iterable/weakset.js';
4
5
 
5
- class InlineCssVariables extends MinifyFeature {
6
+ function replace(node, variableScope) {
7
+ for (const { value, parent: parentValue } of walkValues(node.val)) {
8
+ if (value?.typ == EnumToken.FunctionTokenType && value.val == 'var') {
9
+ if (value.chi.length == 1 && value.chi[0].typ == EnumToken.DashedIdenTokenType) {
10
+ const info = variableScope.get(value.chi[0].val);
11
+ if (info?.replaceable) {
12
+ if (parentValue != null) {
13
+ let i = 0;
14
+ for (; i < parentValue.chi.length; i++) {
15
+ if (parentValue.chi[i] == value) {
16
+ parentValue.chi.splice(i, 1, ...info.node.val);
17
+ break;
18
+ }
19
+ }
20
+ }
21
+ else {
22
+ node.val = info.node.val.slice();
23
+ }
24
+ }
25
+ }
26
+ }
27
+ }
28
+ }
29
+ class InlineCssVariablesFeature extends MinifyFeature {
6
30
  static get ordering() {
7
31
  return 0;
8
32
  }
9
33
  static register(options) {
10
34
  if (options.inlineCssVariables) {
11
35
  for (const feature of options.features) {
12
- if (feature instanceof InlineCssVariables) {
36
+ if (feature instanceof InlineCssVariablesFeature) {
13
37
  return;
14
38
  }
15
39
  }
16
40
  // @ts-ignore
17
- options.features.push(new InlineCssVariables());
41
+ options.features.push(new InlineCssVariablesFeature());
18
42
  }
19
43
  }
20
44
  run(ast, options = {}, parent, context) {
21
45
  if (!('variableScope' in context)) {
22
46
  context.variableScope = new Map;
23
47
  }
24
- const isRoot = parent.typ == 2 /* NodeType.StyleSheetNodeType */ && ast.typ == 4 /* NodeType.RuleNodeType */ && ast.sel == ':root';
48
+ const isRoot = parent.typ == EnumToken.StyleSheetNodeType && ast.typ == EnumToken.RuleNodeType && ast.sel == ':root';
25
49
  const variableScope = context.variableScope;
26
50
  // @ts-ignore
27
51
  for (const node of ast.chi) {
28
- if (node.typ == 1 /* NodeType.CDOCOMMNodeType */ || node.typ == 0 /* NodeType.CommentNodeType */) {
52
+ if (node.typ == EnumToken.CDOCOMMNodeType || node.typ == EnumToken.CommentNodeType) {
29
53
  continue;
30
54
  }
31
- if (node.typ != 5 /* NodeType.DeclarationNodeType */) {
55
+ if (node.typ != EnumToken.DeclarationNodeType) {
32
56
  break;
33
57
  }
34
58
  // css variable
@@ -37,13 +61,23 @@ class InlineCssVariables extends MinifyFeature {
37
61
  const info = {
38
62
  globalScope: isRoot,
39
63
  // @ts-ignore
40
- parent: new Set(),
64
+ parent: new IterableWeakSet(),
41
65
  declarationCount: 1,
42
66
  replaceable: isRoot,
43
67
  node: node
44
68
  };
45
69
  info.parent.add(ast);
46
70
  variableScope.set(node.nam, info);
71
+ let recursive = false;
72
+ for (const { value, parent: parentValue } of walkValues(node.val)) {
73
+ if (value?.typ == EnumToken.FunctionTokenType && value.val == 'var') {
74
+ recursive = true;
75
+ break;
76
+ }
77
+ }
78
+ if (recursive) {
79
+ replace(node, variableScope);
80
+ }
47
81
  }
48
82
  else {
49
83
  const info = variableScope.get(node.nam);
@@ -59,27 +93,7 @@ class InlineCssVariables extends MinifyFeature {
59
93
  }
60
94
  }
61
95
  else {
62
- for (const { value, parent: parentValue } of walkValues(node.val)) {
63
- if (value?.typ == EnumToken.FunctionTokenType && value.val == 'var') {
64
- if (value.chi.length == 1 && value.chi[0].typ == EnumToken.IdenTokenType) {
65
- const info = variableScope.get(value.chi[0].val);
66
- if (info?.replaceable) {
67
- if (parentValue != null) {
68
- let i = 0;
69
- for (; i < parentValue.chi.length; i++) {
70
- if (parentValue.chi[i] == value) {
71
- parentValue.chi.splice(i, 1, ...info.node.val);
72
- break;
73
- }
74
- }
75
- }
76
- else {
77
- node.val = info.node.val.slice();
78
- }
79
- }
80
- }
81
- }
82
- }
96
+ replace(node, variableScope);
83
97
  }
84
98
  }
85
99
  }
@@ -88,10 +102,11 @@ class InlineCssVariables extends MinifyFeature {
88
102
  for (const info of variableScope.values()) {
89
103
  if (info.replaceable) {
90
104
  let i;
105
+ // drop declarations from :root{}
91
106
  for (const parent of info.parent) {
92
107
  i = parent.chi?.length ?? 0;
93
108
  while (i--) {
94
- if (parent.chi[i].typ == 5 /* NodeType.DeclarationNodeType */ && parent.chi[i].nam == info.node.nam) {
109
+ if (parent.chi[i].typ == EnumToken.DeclarationNodeType && parent.chi[i].nam == info.node.nam) {
95
110
  parent.chi.splice(i, 1);
96
111
  }
97
112
  }
@@ -112,4 +127,4 @@ class InlineCssVariables extends MinifyFeature {
112
127
  }
113
128
  }
114
129
 
115
- export { InlineCssVariables };
130
+ export { InlineCssVariablesFeature };
@@ -1,24 +1,24 @@
1
1
  import { PropertyList } from '../../parser/declaration/list.js';
2
2
  import '../../renderer/utils/color.js';
3
- import '../types.js';
3
+ import { EnumToken } from '../types.js';
4
4
  import '../minify.js';
5
5
  import '../../parser/parse.js';
6
6
  import '../../renderer/sourcemap/lib/encode.js';
7
- import { MinifyFeature } from '../utiles/minifyfeature.js';
7
+ import { MinifyFeature } from '../utils/minifyfeature.js';
8
8
 
9
- class ComputeShorthand extends MinifyFeature {
9
+ class ComputeShorthandFeature extends MinifyFeature {
10
10
  static get ordering() {
11
11
  return 2;
12
12
  }
13
13
  static register(options) {
14
14
  if (options.computeShorthand) {
15
15
  for (const feature of options.features) {
16
- if (feature instanceof ComputeShorthand) {
16
+ if (feature instanceof ComputeShorthandFeature) {
17
17
  return;
18
18
  }
19
19
  }
20
20
  // @ts-ignore
21
- options.features.push(new ComputeShorthand());
21
+ options.features.push(new ComputeShorthandFeature());
22
22
  }
23
23
  }
24
24
  run(ast, options = {}, parent, context) {
@@ -30,7 +30,7 @@ class ComputeShorthand extends MinifyFeature {
30
30
  for (; k < j; k++) {
31
31
  // @ts-ignore
32
32
  const node = ast.chi[k];
33
- if (node.typ == 0 /* NodeType.CommentNodeType */ || node.typ == 5 /* NodeType.DeclarationNodeType */) {
33
+ if (node.typ == EnumToken.CommentNodeType || node.typ == EnumToken.DeclarationNodeType) {
34
34
  properties.add(node);
35
35
  continue;
36
36
  }
@@ -42,4 +42,4 @@ class ComputeShorthand extends MinifyFeature {
42
42
  }
43
43
  }
44
44
 
45
- export { ComputeShorthand };
45
+ export { ComputeShorthandFeature };
@@ -0,0 +1,95 @@
1
+ import { EnumToken } from '../../types.js';
2
+ import { reduceNumber } from '../../../renderer/render.js';
3
+
4
+ const gcd = (x, y) => {
5
+ x = Math.abs(x);
6
+ y = Math.abs(y);
7
+ let t;
8
+ if (x == 0 || y == 0) {
9
+ return 1;
10
+ }
11
+ while (y) {
12
+ t = y;
13
+ y = x % y;
14
+ x = t;
15
+ }
16
+ return x;
17
+ };
18
+ function compute(a, b, op) {
19
+ if (typeof a == 'number' && typeof b == 'number') {
20
+ switch (op) {
21
+ case EnumToken.Add:
22
+ return a + b;
23
+ case EnumToken.Sub:
24
+ return a - b;
25
+ case EnumToken.Mul:
26
+ return a * b;
27
+ case EnumToken.Div:
28
+ const r = simplify(a, b);
29
+ if (r[1] == 1) {
30
+ return r[0];
31
+ }
32
+ const result = a / b;
33
+ const r2 = reduceNumber(r[0]) + '/' + reduceNumber(r[1]);
34
+ return reduceNumber(result).length <= r2.length ? result : {
35
+ typ: EnumToken.FractionTokenType,
36
+ l: { typ: EnumToken.NumberTokenType, val: reduceNumber(r[0]) },
37
+ r: { typ: EnumToken.NumberTokenType, val: reduceNumber(r[1]) }
38
+ };
39
+ }
40
+ }
41
+ let l1 = typeof a == 'number' ? {
42
+ typ: EnumToken.FractionTokenType,
43
+ l: { typ: EnumToken.NumberTokenType, val: reduceNumber(a) },
44
+ r: { typ: EnumToken.NumberTokenType, val: '1' }
45
+ } : a;
46
+ let r1 = typeof b == 'number' ? {
47
+ typ: EnumToken.FractionTokenType,
48
+ l: { typ: EnumToken.NumberTokenType, val: reduceNumber(b) },
49
+ r: { typ: EnumToken.NumberTokenType, val: '1' }
50
+ } : b;
51
+ let l2;
52
+ let r2;
53
+ switch (op) {
54
+ case EnumToken.Add:
55
+ // @ts-ignore
56
+ l2 = l1.l.val * r1.r.val + l1.r.val * r1.l.val;
57
+ // @ts-ignore
58
+ r2 = l1.r.val * r1.r.val;
59
+ break;
60
+ case EnumToken.Sub:
61
+ // @ts-ignore
62
+ l2 = l1.l.val * r1.r.val - l1.r.val * r1.l.val;
63
+ // @ts-ignore
64
+ r2 = l1.r.val * r1.r.val;
65
+ break;
66
+ case EnumToken.Mul:
67
+ // @ts-ignore
68
+ l2 = l1.l.val * r1.l.val;
69
+ // @ts-ignore
70
+ r2 = l1.r.val * r1.r.val;
71
+ break;
72
+ case EnumToken.Div:
73
+ // @ts-ignore
74
+ l2 = l1.l.val * r1.r.val;
75
+ // @ts-ignore
76
+ r2 = l1.r.val * r1.l.val;
77
+ break;
78
+ }
79
+ const a2 = simplify(l2, r2);
80
+ if (a2[1] == 1) {
81
+ return a2[0];
82
+ }
83
+ const result = a2[0] / a2[1];
84
+ return reduceNumber(result).length <= reduceNumber(a2[0]).length + 1 + reduceNumber(a2[1]).length ? result : {
85
+ typ: EnumToken.FractionTokenType,
86
+ l: { typ: EnumToken.NumberTokenType, val: reduceNumber(a2[0]) },
87
+ r: { typ: EnumToken.NumberTokenType, val: reduceNumber(a2[1]) }
88
+ };
89
+ }
90
+ function simplify(a, b) {
91
+ const g = gcd(a, b);
92
+ return g > 1 ? [a / g, b / g] : [a, b];
93
+ }
94
+
95
+ export { compute, gcd, simplify };