@tbela99/css-parser 0.2.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.
- package/README.md +62 -0
- package/dist/config.json.js +225 -0
- package/dist/index-umd-web.js +1404 -604
- package/dist/index.cjs +1404 -604
- package/dist/lib/ast/features/calc.js +30 -190
- package/dist/lib/ast/features/index.js +3 -3
- package/dist/lib/ast/features/inlinecssvariables.js +5 -5
- package/dist/lib/ast/features/shorthand.js +4 -5
- package/dist/lib/ast/math/expression.js +185 -0
- package/dist/lib/ast/math/math.js +95 -0
- package/dist/lib/ast/types.js +30 -13
- package/dist/lib/ast/walk.js +24 -4
- package/dist/lib/fs/resolve.js +4 -3
- package/dist/lib/iterable/weakset.js +48 -0
- package/dist/lib/parser/declaration/list.js +5 -1
- package/dist/lib/parser/declaration/map.js +44 -13
- package/dist/lib/parser/declaration/set.js +41 -21
- package/dist/lib/parser/parse.js +30 -56
- package/dist/lib/parser/utils/declaration.js +67 -0
- package/dist/lib/parser/utils/syntax.js +32 -2
- package/dist/lib/renderer/render.js +77 -8
- package/dist/lib/renderer/utils/calccolor.js +238 -0
- package/dist/lib/renderer/utils/color.js +36 -164
- package/dist/lib/renderer/utils/hex.js +124 -0
- package/dist/lib/renderer/utils/hsl.js +49 -0
- package/dist/lib/renderer/utils/hsv.js +15 -0
- package/dist/lib/renderer/utils/hwb.js +50 -0
- package/dist/lib/renderer/utils/rgb.js +66 -0
- package/package.json +5 -5
- package/dist/index.d.ts +0 -862
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
import { EnumToken } from '../types.js';
|
|
2
|
-
import { reduceNumber } from '../../renderer/render.js';
|
|
3
2
|
import { walkValues } from '../walk.js';
|
|
4
3
|
import { MinifyFeature } from '../utils/minifyfeature.js';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { IterableWeakSet } from '../../iterable/weakset.js';
|
|
5
|
+
import { evaluate } from '../math/expression.js';
|
|
7
6
|
|
|
8
|
-
class
|
|
7
|
+
class ComputeCalcExpressionFeature extends MinifyFeature {
|
|
9
8
|
static get ordering() {
|
|
10
9
|
return 1;
|
|
11
10
|
}
|
|
12
11
|
static register(options) {
|
|
13
12
|
if (options.computeCalcExpression) {
|
|
14
13
|
for (const feature of options.features) {
|
|
15
|
-
if (feature instanceof
|
|
14
|
+
if (feature instanceof ComputeCalcExpressionFeature) {
|
|
16
15
|
return;
|
|
17
16
|
}
|
|
18
17
|
}
|
|
19
18
|
// @ts-ignore
|
|
20
|
-
options.features.push(new
|
|
19
|
+
options.features.push(new ComputeCalcExpressionFeature());
|
|
21
20
|
}
|
|
22
21
|
}
|
|
23
22
|
run(ast) {
|
|
@@ -30,11 +29,31 @@ class ComputeCalcExpression extends MinifyFeature {
|
|
|
30
29
|
continue;
|
|
31
30
|
}
|
|
32
31
|
const set = new IterableWeakSet;
|
|
33
|
-
for (const { parent } of walkValues(node.val)) {
|
|
34
|
-
if (
|
|
32
|
+
for (const { value, parent } of walkValues(node.val)) {
|
|
33
|
+
if (value != null && value.typ == EnumToken.FunctionTokenType && value.val == 'calc') {
|
|
35
34
|
if (!set.has(parent)) {
|
|
36
|
-
set.add(
|
|
37
|
-
|
|
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
|
+
}
|
|
38
57
|
}
|
|
39
58
|
}
|
|
40
59
|
}
|
|
@@ -42,184 +61,5 @@ class ComputeCalcExpression extends MinifyFeature {
|
|
|
42
61
|
return ast;
|
|
43
62
|
}
|
|
44
63
|
}
|
|
45
|
-
/**
|
|
46
|
-
* evaluate arithmetic operation
|
|
47
|
-
* @param l
|
|
48
|
-
* @param r
|
|
49
|
-
* @param op
|
|
50
|
-
*/
|
|
51
|
-
function doEvaluate(l, r, op) {
|
|
52
|
-
const defaultReturn = {
|
|
53
|
-
typ: EnumToken.BinaryExpressionTokenType,
|
|
54
|
-
op,
|
|
55
|
-
l,
|
|
56
|
-
r
|
|
57
|
-
};
|
|
58
|
-
if (!isScalarToken(l) || !isScalarToken(r)) {
|
|
59
|
-
return defaultReturn;
|
|
60
|
-
}
|
|
61
|
-
if ((op == EnumToken.Add || op == EnumToken.Sub)) {
|
|
62
|
-
// @ts-ignore
|
|
63
|
-
if (l.typ != r.typ) {
|
|
64
|
-
return defaultReturn;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
const typ = l.typ == EnumToken.NumberTokenType ? r.typ : l.typ;
|
|
68
|
-
// @ts-ignore
|
|
69
|
-
const val = compute(typeof l.val == 'string' ? +l.val : l.val, typeof r.val == 'string' ? +r.val : r.val, op);
|
|
70
|
-
return { ...(l.typ == EnumToken.NumberTokenType ? r : l), typ, val: typeof val == 'number' ? reduceNumber(val) : val };
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* evaluate an array of tokens
|
|
74
|
-
* @param tokens
|
|
75
|
-
*/
|
|
76
|
-
function evaluate(tokens) {
|
|
77
|
-
const nodes = inlineExpression(evaluateExpression(buildExpression(tokens)));
|
|
78
|
-
if (nodes.length <= 1) {
|
|
79
|
-
return nodes;
|
|
80
|
-
}
|
|
81
|
-
const map = new Map;
|
|
82
|
-
let token;
|
|
83
|
-
let i;
|
|
84
|
-
for (i = 0; i < nodes.length; i++) {
|
|
85
|
-
token = nodes[i];
|
|
86
|
-
if (token.typ == EnumToken.Add) {
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
if (token.typ == EnumToken.Sub) {
|
|
90
|
-
if (!isScalarToken(nodes[i + 1])) {
|
|
91
|
-
token = { typ: EnumToken.ListToken, chi: [nodes[i], nodes[i + 1]] };
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
token = doEvaluate(nodes[i + 1], { typ: EnumToken.NumberTokenType, val: '-1' }, EnumToken.Mul);
|
|
95
|
-
}
|
|
96
|
-
i++;
|
|
97
|
-
}
|
|
98
|
-
if (!map.has(token.typ)) {
|
|
99
|
-
map.set(token.typ, [token]);
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
map.get(token.typ).push(token);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return [...map].reduce((acc, curr) => {
|
|
106
|
-
const token = curr[1].reduce((acc, curr) => doEvaluate(acc, curr, EnumToken.Add));
|
|
107
|
-
if (token.typ != EnumToken.BinaryExpressionTokenType) {
|
|
108
|
-
if ('val' in token && +token.val < 0) {
|
|
109
|
-
acc.push({ typ: EnumToken.Sub }, { ...token, val: String(-token.val) });
|
|
110
|
-
return acc;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
if (acc.length > 0 && curr[0] != EnumToken.ListToken) {
|
|
114
|
-
acc.push({ typ: EnumToken.Add });
|
|
115
|
-
}
|
|
116
|
-
acc.push(token);
|
|
117
|
-
return acc;
|
|
118
|
-
}, []);
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* convert BinaryExpression into an array
|
|
122
|
-
* @param token
|
|
123
|
-
*/
|
|
124
|
-
function inlineExpression(token) {
|
|
125
|
-
const result = [];
|
|
126
|
-
if (token.typ == EnumToken.ParensTokenType && token.chi.length == 1) {
|
|
127
|
-
result.push(token.chi[0]);
|
|
128
|
-
}
|
|
129
|
-
else if (token.typ == EnumToken.BinaryExpressionTokenType) {
|
|
130
|
-
if ([EnumToken.Mul, EnumToken.Div].includes(token.op)) {
|
|
131
|
-
result.push(token);
|
|
132
|
-
}
|
|
133
|
-
else {
|
|
134
|
-
result.push(...inlineExpression(token.l), { typ: token.op }, ...inlineExpression(token.r));
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
result.push(token);
|
|
139
|
-
}
|
|
140
|
-
return result;
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* evaluate expression
|
|
144
|
-
* @param token
|
|
145
|
-
*/
|
|
146
|
-
function evaluateExpression(token) {
|
|
147
|
-
if (token.typ != EnumToken.BinaryExpressionTokenType) {
|
|
148
|
-
return token;
|
|
149
|
-
}
|
|
150
|
-
if (token.r.typ == EnumToken.BinaryExpressionTokenType) {
|
|
151
|
-
token.r = evaluateExpression(token.r);
|
|
152
|
-
}
|
|
153
|
-
if (token.l.typ == EnumToken.BinaryExpressionTokenType) {
|
|
154
|
-
token.l = evaluateExpression(token.l);
|
|
155
|
-
}
|
|
156
|
-
return doEvaluate(token.l, token.r, token.op);
|
|
157
|
-
}
|
|
158
|
-
function isScalarToken(token) {
|
|
159
|
-
return token.typ != EnumToken.BinaryExpressionTokenType && token.typ != EnumToken.ParensTokenType && token.typ != EnumToken.FunctionTokenType;
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
*
|
|
163
|
-
* generate binary expression tree
|
|
164
|
-
* @param tokens
|
|
165
|
-
*/
|
|
166
|
-
function buildExpression(tokens) {
|
|
167
|
-
return factor(factor(tokens.filter(t => t.typ != EnumToken.WhitespaceTokenType), ['/', '*']), ['+', '-'])[0];
|
|
168
|
-
}
|
|
169
|
-
function getArithmeticOperation(op) {
|
|
170
|
-
if (op == '+') {
|
|
171
|
-
return EnumToken.Add;
|
|
172
|
-
}
|
|
173
|
-
if (op == '-') {
|
|
174
|
-
return EnumToken.Sub;
|
|
175
|
-
}
|
|
176
|
-
if (op == '/') {
|
|
177
|
-
return EnumToken.Div;
|
|
178
|
-
}
|
|
179
|
-
return EnumToken.Mul;
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
*
|
|
183
|
-
* generate binary expression tree
|
|
184
|
-
* @param token
|
|
185
|
-
*/
|
|
186
|
-
function factorToken(token) {
|
|
187
|
-
if (token.typ == EnumToken.ParensTokenType || (token.typ == EnumToken.FunctionTokenType && token.val == 'calc')) {
|
|
188
|
-
if (token.typ == EnumToken.FunctionTokenType && token.val == 'calc') {
|
|
189
|
-
token = { ...token, typ: EnumToken.ParensTokenType };
|
|
190
|
-
// @ts-ignore
|
|
191
|
-
delete token.val;
|
|
192
|
-
}
|
|
193
|
-
return buildExpression(token.chi);
|
|
194
|
-
}
|
|
195
|
-
return token;
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* generate binary expression tree
|
|
199
|
-
* @param tokens
|
|
200
|
-
* @param ops
|
|
201
|
-
*/
|
|
202
|
-
function factor(tokens, ops) {
|
|
203
|
-
let isOp;
|
|
204
|
-
const opList = ops.map(x => getArithmeticOperation(x));
|
|
205
|
-
if (tokens.length == 1) {
|
|
206
|
-
return [factorToken(tokens[0])];
|
|
207
|
-
}
|
|
208
|
-
for (let i = 0; i < tokens.length; i++) {
|
|
209
|
-
isOp = opList.includes(tokens[i].typ);
|
|
210
|
-
if (isOp ||
|
|
211
|
-
// @ts-ignore
|
|
212
|
-
(tokens[i].typ == EnumToken.LiteralTokenType && ops.includes(tokens[i].val))) {
|
|
213
|
-
tokens.splice(i - 1, 3, {
|
|
214
|
-
typ: EnumToken.BinaryExpressionTokenType,
|
|
215
|
-
op: isOp ? tokens[i].typ : getArithmeticOperation(tokens[i].val),
|
|
216
|
-
l: factorToken(tokens[i - 1]),
|
|
217
|
-
r: factorToken(tokens[i + 1])
|
|
218
|
-
});
|
|
219
|
-
i--;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
return tokens;
|
|
223
|
-
}
|
|
224
64
|
|
|
225
|
-
export {
|
|
65
|
+
export { ComputeCalcExpressionFeature };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
1
|
+
export { InlineCssVariablesFeature } from './inlinecssvariables.js';
|
|
2
|
+
export { ComputeShorthandFeature } from './shorthand.js';
|
|
3
|
+
export { ComputeCalcExpressionFeature } from './calc.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EnumToken } from '../types.js';
|
|
2
2
|
import { walkValues } from '../walk.js';
|
|
3
3
|
import { MinifyFeature } from '../utils/minifyfeature.js';
|
|
4
|
-
import { IterableWeakSet } from '../../iterable/
|
|
4
|
+
import { IterableWeakSet } from '../../iterable/weakset.js';
|
|
5
5
|
|
|
6
6
|
function replace(node, variableScope) {
|
|
7
7
|
for (const { value, parent: parentValue } of walkValues(node.val)) {
|
|
@@ -26,19 +26,19 @@ function replace(node, variableScope) {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
class
|
|
29
|
+
class InlineCssVariablesFeature extends MinifyFeature {
|
|
30
30
|
static get ordering() {
|
|
31
31
|
return 0;
|
|
32
32
|
}
|
|
33
33
|
static register(options) {
|
|
34
34
|
if (options.inlineCssVariables) {
|
|
35
35
|
for (const feature of options.features) {
|
|
36
|
-
if (feature instanceof
|
|
36
|
+
if (feature instanceof InlineCssVariablesFeature) {
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
// @ts-ignore
|
|
41
|
-
options.features.push(new
|
|
41
|
+
options.features.push(new InlineCssVariablesFeature());
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
run(ast, options = {}, parent, context) {
|
|
@@ -127,4 +127,4 @@ class InlineCssVariables extends MinifyFeature {
|
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
export {
|
|
130
|
+
export { InlineCssVariablesFeature };
|
|
@@ -4,22 +4,21 @@ 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 '../../parser/declaration/map.js';
|
|
8
7
|
import { MinifyFeature } from '../utils/minifyfeature.js';
|
|
9
8
|
|
|
10
|
-
class
|
|
9
|
+
class ComputeShorthandFeature extends MinifyFeature {
|
|
11
10
|
static get ordering() {
|
|
12
11
|
return 2;
|
|
13
12
|
}
|
|
14
13
|
static register(options) {
|
|
15
14
|
if (options.computeShorthand) {
|
|
16
15
|
for (const feature of options.features) {
|
|
17
|
-
if (feature instanceof
|
|
16
|
+
if (feature instanceof ComputeShorthandFeature) {
|
|
18
17
|
return;
|
|
19
18
|
}
|
|
20
19
|
}
|
|
21
20
|
// @ts-ignore
|
|
22
|
-
options.features.push(new
|
|
21
|
+
options.features.push(new ComputeShorthandFeature());
|
|
23
22
|
}
|
|
24
23
|
}
|
|
25
24
|
run(ast, options = {}, parent, context) {
|
|
@@ -43,4 +42,4 @@ class ComputeShorthand extends MinifyFeature {
|
|
|
43
42
|
}
|
|
44
43
|
}
|
|
45
44
|
|
|
46
|
-
export {
|
|
45
|
+
export { ComputeShorthandFeature };
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { EnumToken } from '../types.js';
|
|
2
|
+
import { compute } from './math.js';
|
|
3
|
+
import { reduceNumber } from '../../renderer/render.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* evaluate an array of tokens
|
|
7
|
+
* @param tokens
|
|
8
|
+
*/
|
|
9
|
+
function evaluate(tokens) {
|
|
10
|
+
const nodes = inlineExpression(evaluateExpression(buildExpression(tokens)));
|
|
11
|
+
if (nodes.length <= 1) {
|
|
12
|
+
return nodes;
|
|
13
|
+
}
|
|
14
|
+
const map = new Map;
|
|
15
|
+
let token;
|
|
16
|
+
let i;
|
|
17
|
+
for (i = 0; i < nodes.length; i++) {
|
|
18
|
+
token = nodes[i];
|
|
19
|
+
if (token.typ == EnumToken.Add) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (token.typ == EnumToken.Sub) {
|
|
23
|
+
if (!isScalarToken(nodes[i + 1])) {
|
|
24
|
+
token = { typ: EnumToken.ListToken, chi: [nodes[i], nodes[i + 1]] };
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
token = doEvaluate(nodes[i + 1], { typ: EnumToken.NumberTokenType, val: '-1' }, EnumToken.Mul);
|
|
28
|
+
}
|
|
29
|
+
i++;
|
|
30
|
+
}
|
|
31
|
+
if (!map.has(token.typ)) {
|
|
32
|
+
map.set(token.typ, [token]);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
map.get(token.typ).push(token);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return [...map].reduce((acc, curr) => {
|
|
39
|
+
const token = curr[1].reduce((acc, curr) => doEvaluate(acc, curr, EnumToken.Add));
|
|
40
|
+
if (token.typ != EnumToken.BinaryExpressionTokenType) {
|
|
41
|
+
if ('val' in token && +token.val < 0) {
|
|
42
|
+
acc.push({ typ: EnumToken.Sub }, { ...token, val: String(-token.val) });
|
|
43
|
+
return acc;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (acc.length > 0 && curr[0] != EnumToken.ListToken) {
|
|
47
|
+
acc.push({ typ: EnumToken.Add });
|
|
48
|
+
}
|
|
49
|
+
acc.push(token);
|
|
50
|
+
return acc;
|
|
51
|
+
}, []);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* evaluate arithmetic operation
|
|
55
|
+
* @param l
|
|
56
|
+
* @param r
|
|
57
|
+
* @param op
|
|
58
|
+
*/
|
|
59
|
+
function doEvaluate(l, r, op) {
|
|
60
|
+
const defaultReturn = {
|
|
61
|
+
typ: EnumToken.BinaryExpressionTokenType,
|
|
62
|
+
op,
|
|
63
|
+
l,
|
|
64
|
+
r
|
|
65
|
+
};
|
|
66
|
+
if (!isScalarToken(l) || !isScalarToken(r)) {
|
|
67
|
+
return defaultReturn;
|
|
68
|
+
}
|
|
69
|
+
if ((op == EnumToken.Add || op == EnumToken.Sub)) {
|
|
70
|
+
// @ts-ignore
|
|
71
|
+
if (l.typ != r.typ) {
|
|
72
|
+
return defaultReturn;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const typ = l.typ == EnumToken.NumberTokenType ? r.typ : l.typ;
|
|
76
|
+
// @ts-ignore
|
|
77
|
+
const val = compute(typeof l.val == 'string' ? +l.val : l.val, typeof r.val == 'string' ? +r.val : r.val, op);
|
|
78
|
+
return { ...(l.typ == EnumToken.NumberTokenType ? r : l), typ, val: typeof val == 'number' ? reduceNumber(val) : val };
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* convert BinaryExpression into an array
|
|
82
|
+
* @param token
|
|
83
|
+
*/
|
|
84
|
+
function inlineExpression(token) {
|
|
85
|
+
const result = [];
|
|
86
|
+
if (token.typ == EnumToken.ParensTokenType && token.chi.length == 1) {
|
|
87
|
+
result.push(token.chi[0]);
|
|
88
|
+
}
|
|
89
|
+
else if (token.typ == EnumToken.BinaryExpressionTokenType) {
|
|
90
|
+
if ([EnumToken.Mul, EnumToken.Div].includes(token.op)) {
|
|
91
|
+
result.push(token);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
result.push(...inlineExpression(token.l), { typ: token.op }, ...inlineExpression(token.r));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
result.push(token);
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* evaluate expression
|
|
104
|
+
* @param token
|
|
105
|
+
*/
|
|
106
|
+
function evaluateExpression(token) {
|
|
107
|
+
if (token.typ != EnumToken.BinaryExpressionTokenType) {
|
|
108
|
+
return token;
|
|
109
|
+
}
|
|
110
|
+
if (token.r.typ == EnumToken.BinaryExpressionTokenType) {
|
|
111
|
+
token.r = evaluateExpression(token.r);
|
|
112
|
+
}
|
|
113
|
+
if (token.l.typ == EnumToken.BinaryExpressionTokenType) {
|
|
114
|
+
token.l = evaluateExpression(token.l);
|
|
115
|
+
}
|
|
116
|
+
return doEvaluate(token.l, token.r, token.op);
|
|
117
|
+
}
|
|
118
|
+
function isScalarToken(token) {
|
|
119
|
+
return 'unit' in token || [EnumToken.NumberTokenType, EnumToken.FractionTokenType, EnumToken.PercentageTokenType].includes(token.typ);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
*
|
|
123
|
+
* generate binary expression tree
|
|
124
|
+
* @param tokens
|
|
125
|
+
*/
|
|
126
|
+
function buildExpression(tokens) {
|
|
127
|
+
return factor(factor(tokens.filter(t => t.typ != EnumToken.WhitespaceTokenType), ['/', '*']), ['+', '-'])[0];
|
|
128
|
+
}
|
|
129
|
+
function getArithmeticOperation(op) {
|
|
130
|
+
if (op == '+') {
|
|
131
|
+
return EnumToken.Add;
|
|
132
|
+
}
|
|
133
|
+
if (op == '-') {
|
|
134
|
+
return EnumToken.Sub;
|
|
135
|
+
}
|
|
136
|
+
if (op == '/') {
|
|
137
|
+
return EnumToken.Div;
|
|
138
|
+
}
|
|
139
|
+
return EnumToken.Mul;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
*
|
|
143
|
+
* generate binary expression tree
|
|
144
|
+
* @param token
|
|
145
|
+
*/
|
|
146
|
+
function factorToken(token) {
|
|
147
|
+
if (token.typ == EnumToken.ParensTokenType || (token.typ == EnumToken.FunctionTokenType && token.val == 'calc')) {
|
|
148
|
+
if (token.typ == EnumToken.FunctionTokenType && token.val == 'calc') {
|
|
149
|
+
token = { ...token, typ: EnumToken.ParensTokenType };
|
|
150
|
+
// @ts-ignore
|
|
151
|
+
delete token.val;
|
|
152
|
+
}
|
|
153
|
+
return buildExpression(token.chi);
|
|
154
|
+
}
|
|
155
|
+
return token;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* generate binary expression tree
|
|
159
|
+
* @param tokens
|
|
160
|
+
* @param ops
|
|
161
|
+
*/
|
|
162
|
+
function factor(tokens, ops) {
|
|
163
|
+
let isOp;
|
|
164
|
+
const opList = ops.map(x => getArithmeticOperation(x));
|
|
165
|
+
if (tokens.length == 1) {
|
|
166
|
+
return [factorToken(tokens[0])];
|
|
167
|
+
}
|
|
168
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
169
|
+
isOp = opList.includes(tokens[i].typ);
|
|
170
|
+
if (isOp ||
|
|
171
|
+
// @ts-ignore
|
|
172
|
+
(tokens[i].typ == EnumToken.LiteralTokenType && ops.includes(tokens[i].val))) {
|
|
173
|
+
tokens.splice(i - 1, 3, {
|
|
174
|
+
typ: EnumToken.BinaryExpressionTokenType,
|
|
175
|
+
op: isOp ? tokens[i].typ : getArithmeticOperation(tokens[i].val),
|
|
176
|
+
l: factorToken(tokens[i - 1]),
|
|
177
|
+
r: factorToken(tokens[i + 1])
|
|
178
|
+
});
|
|
179
|
+
i--;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return tokens;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export { evaluate };
|
|
@@ -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 };
|
package/dist/lib/ast/types.js
CHANGED
|
@@ -57,25 +57,29 @@ var EnumToken;
|
|
|
57
57
|
EnumToken[EnumToken["BadStringTokenType"] = 54] = "BadStringTokenType";
|
|
58
58
|
EnumToken[EnumToken["BinaryExpressionTokenType"] = 55] = "BinaryExpressionTokenType";
|
|
59
59
|
EnumToken[EnumToken["UnaryExpressionTokenType"] = 56] = "UnaryExpressionTokenType";
|
|
60
|
+
EnumToken[EnumToken["FlexTokenType"] = 57] = "FlexTokenType";
|
|
60
61
|
/* catch all */
|
|
61
|
-
EnumToken[EnumToken["ListToken"] =
|
|
62
|
+
EnumToken[EnumToken["ListToken"] = 58] = "ListToken";
|
|
62
63
|
/* arithmetic tokens */
|
|
63
|
-
EnumToken[EnumToken["Add"] =
|
|
64
|
-
EnumToken[EnumToken["Mul"] =
|
|
65
|
-
EnumToken[EnumToken["Div"] =
|
|
66
|
-
EnumToken[EnumToken["Sub"] =
|
|
64
|
+
EnumToken[EnumToken["Add"] = 59] = "Add";
|
|
65
|
+
EnumToken[EnumToken["Mul"] = 60] = "Mul";
|
|
66
|
+
EnumToken[EnumToken["Div"] = 61] = "Div";
|
|
67
|
+
EnumToken[EnumToken["Sub"] = 62] = "Sub";
|
|
67
68
|
/* new tokens */
|
|
68
|
-
EnumToken[EnumToken["ColumnCombinatorTokenType"] =
|
|
69
|
-
EnumToken[EnumToken["ContainMatchTokenType"] =
|
|
70
|
-
EnumToken[EnumToken["StartMatchTokenType"] =
|
|
71
|
-
EnumToken[EnumToken["EndMatchTokenType"] =
|
|
72
|
-
EnumToken[EnumToken["MatchExpressionTokenType"] =
|
|
73
|
-
EnumToken[EnumToken["NameSpaceAttributeTokenType"] =
|
|
74
|
-
EnumToken[EnumToken["FractionTokenType"] =
|
|
69
|
+
EnumToken[EnumToken["ColumnCombinatorTokenType"] = 63] = "ColumnCombinatorTokenType";
|
|
70
|
+
EnumToken[EnumToken["ContainMatchTokenType"] = 64] = "ContainMatchTokenType";
|
|
71
|
+
EnumToken[EnumToken["StartMatchTokenType"] = 65] = "StartMatchTokenType";
|
|
72
|
+
EnumToken[EnumToken["EndMatchTokenType"] = 66] = "EndMatchTokenType";
|
|
73
|
+
EnumToken[EnumToken["MatchExpressionTokenType"] = 67] = "MatchExpressionTokenType";
|
|
74
|
+
EnumToken[EnumToken["NameSpaceAttributeTokenType"] = 68] = "NameSpaceAttributeTokenType";
|
|
75
|
+
EnumToken[EnumToken["FractionTokenType"] = 69] = "FractionTokenType";
|
|
76
|
+
EnumToken[EnumToken["IdenListTokenType"] = 70] = "IdenListTokenType";
|
|
77
|
+
EnumToken[EnumToken["GridTemplateFuncTokenType"] = 71] = "GridTemplateFuncTokenType";
|
|
75
78
|
/* aliases */
|
|
76
79
|
EnumToken[EnumToken["Time"] = 25] = "Time";
|
|
77
80
|
EnumToken[EnumToken["Iden"] = 7] = "Iden";
|
|
78
81
|
EnumToken[EnumToken["Hash"] = 28] = "Hash";
|
|
82
|
+
EnumToken[EnumToken["Flex"] = 57] = "Flex";
|
|
79
83
|
EnumToken[EnumToken["Angle"] = 24] = "Angle";
|
|
80
84
|
EnumToken[EnumToken["Color"] = 49] = "Color";
|
|
81
85
|
EnumToken[EnumToken["Comma"] = 9] = "Comma";
|
|
@@ -90,12 +94,25 @@ var EnumToken;
|
|
|
90
94
|
EnumToken[EnumToken["Frequency"] = 26] = "Frequency";
|
|
91
95
|
EnumToken[EnumToken["Resolution"] = 27] = "Resolution";
|
|
92
96
|
EnumToken[EnumToken["Whitespace"] = 36] = "Whitespace";
|
|
97
|
+
EnumToken[EnumToken["IdenList"] = 70] = "IdenList";
|
|
93
98
|
EnumToken[EnumToken["DashedIden"] = 8] = "DashedIden";
|
|
99
|
+
EnumToken[EnumToken["GridTemplateFunc"] = 71] = "GridTemplateFunc";
|
|
94
100
|
EnumToken[EnumToken["ImageFunc"] = 19] = "ImageFunc";
|
|
95
101
|
EnumToken[EnumToken["CommentNodeType"] = 0] = "CommentNodeType";
|
|
96
102
|
EnumToken[EnumToken["CDOCOMMNodeType"] = 1] = "CDOCOMMNodeType";
|
|
97
103
|
EnumToken[EnumToken["TimingFunction"] = 17] = "TimingFunction";
|
|
98
104
|
EnumToken[EnumToken["TimelineFunction"] = 16] = "TimelineFunction";
|
|
99
105
|
})(EnumToken || (EnumToken = {}));
|
|
106
|
+
const funcLike = [
|
|
107
|
+
EnumToken.ParensTokenType,
|
|
108
|
+
EnumToken.FunctionTokenType,
|
|
109
|
+
EnumToken.UrlFunctionTokenType,
|
|
110
|
+
EnumToken.StartParensTokenType,
|
|
111
|
+
EnumToken.ImageFunctionTokenType,
|
|
112
|
+
EnumToken.TimingFunctionTokenType,
|
|
113
|
+
EnumToken.TimingFunctionTokenType,
|
|
114
|
+
EnumToken.PseudoClassFuncTokenType,
|
|
115
|
+
EnumToken.GridTemplateFuncTokenType
|
|
116
|
+
];
|
|
100
117
|
|
|
101
|
-
export { EnumToken };
|
|
118
|
+
export { EnumToken, funcLike };
|