@cloudpss/expression 0.6.0-alpha.9 → 0.6.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/dist/analyze.d.ts +6 -3
- package/dist/analyze.d.ts.map +1 -1
- package/dist/analyze.js +13 -33
- package/dist/analyze.js.map +1 -1
- package/dist/definitions/argument.d.ts +3 -11
- package/dist/definitions/argument.d.ts.map +1 -1
- package/dist/definitions/constraint.d.ts +2 -2
- package/dist/definitions/constraint.d.ts.map +1 -1
- package/dist/definitions/constraint.js +1 -1
- package/dist/definitions/constraint.js.map +1 -1
- package/dist/definitions/parameter-group.js +4 -4
- package/dist/definitions/parameter-group.js.map +1 -1
- package/dist/definitions/parameter.d.ts +22 -14
- package/dist/definitions/parameter.d.ts.map +1 -1
- package/dist/definitions/parameter.js +10 -1
- package/dist/definitions/parameter.js.map +1 -1
- package/dist/definitions/utils.d.ts +28 -0
- package/dist/definitions/utils.d.ts.map +1 -0
- package/dist/definitions/utils.js +272 -0
- package/dist/definitions/utils.js.map +1 -0
- package/dist/definitions/variable.js +1 -1
- package/dist/definitions/variable.js.map +1 -1
- package/dist/definitions.d.ts +1 -2
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +1 -1
- package/dist/definitions.js.map +1 -1
- package/dist/eval.d.ts +3 -5
- package/dist/eval.d.ts.map +1 -1
- package/dist/eval.js +12 -20
- package/dist/eval.js.map +1 -1
- package/dist/expression.d.ts +10 -4
- package/dist/expression.d.ts.map +1 -1
- package/dist/expression.js +6 -6
- package/dist/expression.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/interface.d.ts +30 -0
- package/dist/interface.d.ts.map +1 -0
- package/dist/interface.js +6 -0
- package/dist/interface.js.map +1 -0
- package/dist/main.d.ts +41 -28
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +165 -149
- package/dist/main.js.map +1 -1
- package/dist/migrate.d.ts +1 -1
- package/dist/migrate.d.ts.map +1 -1
- package/dist/migrate.js +25 -4
- package/dist/migrate.js.map +1 -1
- package/dist/migrator/access.d.ts.map +1 -1
- package/dist/migrator/access.js +64 -29
- package/dist/migrator/access.js.map +1 -1
- package/dist/migrator/call.d.ts.map +1 -1
- package/dist/migrator/call.js +298 -201
- package/dist/migrator/call.js.map +1 -1
- package/dist/migrator/concat.d.ts.map +1 -1
- package/dist/migrator/concat.js +15 -2
- package/dist/migrator/concat.js.map +1 -1
- package/dist/migrator/function.d.ts +6 -0
- package/dist/migrator/function.d.ts.map +1 -0
- package/dist/migrator/function.js +25 -0
- package/dist/migrator/function.js.map +1 -0
- package/dist/migrator/interface.d.ts +3 -1
- package/dist/migrator/interface.d.ts.map +1 -1
- package/dist/migrator/interface.js.map +1 -1
- package/dist/migrator/node.d.ts.map +1 -1
- package/dist/migrator/node.js +55 -7
- package/dist/migrator/node.js.map +1 -1
- package/dist/migrator/operator.d.ts.map +1 -1
- package/dist/migrator/operator.js +107 -60
- package/dist/migrator/operator.js.map +1 -1
- package/dist/migrator/serialize.d.ts +4 -0
- package/dist/migrator/serialize.d.ts.map +1 -0
- package/dist/migrator/serialize.js +21 -0
- package/dist/migrator/serialize.js.map +1 -0
- package/dist/migrator/special.d.ts.map +1 -1
- package/dist/migrator/special.js +31 -0
- package/dist/migrator/special.js.map +1 -1
- package/dist/migrator/state.d.ts +4 -4
- package/dist/migrator/state.d.ts.map +1 -1
- package/dist/migrator/state.js +29 -31
- package/dist/migrator/state.js.map +1 -1
- package/dist/migrator/symbol.d.ts.map +1 -1
- package/dist/migrator/symbol.js +34 -12
- package/dist/migrator/symbol.js.map +1 -1
- package/dist/migrator/to-type.d.ts.map +1 -1
- package/dist/migrator/to-type.js +21 -4
- package/dist/migrator/to-type.js.map +1 -1
- package/dist/migrator/utils.d.ts +6 -0
- package/dist/migrator/utils.d.ts.map +1 -1
- package/dist/migrator/utils.js +48 -1
- package/dist/migrator/utils.js.map +1 -1
- package/dist/parser.d.ts +2 -2
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +27 -8
- package/dist/parser.js.map +1 -1
- package/dist/re-exports.d.ts +4 -0
- package/dist/re-exports.d.ts.map +1 -0
- package/dist/re-exports.js +3 -0
- package/dist/re-exports.js.map +1 -0
- package/dist/scope.d.ts +16 -17
- package/dist/scope.d.ts.map +1 -1
- package/dist/scope.js +127 -66
- package/dist/scope.js.map +1 -1
- package/dist/type.d.ts +22 -10
- package/dist/type.d.ts.map +1 -1
- package/dist/type.js +21 -24
- package/dist/type.js.map +1 -1
- package/package.json +8 -5
- package/src/analyze.ts +20 -39
- package/src/definitions/argument.ts +3 -13
- package/src/definitions/constraint.ts +3 -3
- package/src/definitions/parameter-group.ts +4 -4
- package/src/definitions/parameter.ts +47 -24
- package/src/definitions/utils.ts +288 -0
- package/src/definitions/variable.ts +1 -1
- package/src/definitions.ts +1 -28
- package/src/eval.ts +16 -25
- package/src/expression.ts +16 -8
- package/src/index.ts +3 -1
- package/src/interface.ts +35 -0
- package/src/main.ts +232 -200
- package/src/migrate.ts +27 -4
- package/src/migrator/access.ts +67 -37
- package/src/migrator/call.ts +287 -190
- package/src/migrator/concat.ts +15 -2
- package/src/migrator/function.ts +27 -0
- package/src/migrator/interface.ts +3 -1
- package/src/migrator/node.ts +56 -6
- package/src/migrator/operator.ts +110 -64
- package/src/migrator/serialize.ts +21 -0
- package/src/migrator/special.ts +31 -0
- package/src/migrator/state.ts +31 -34
- package/src/migrator/symbol.ts +33 -12
- package/src/migrator/to-type.ts +23 -4
- package/src/migrator/utils.ts +48 -1
- package/src/parser.ts +33 -8
- package/src/re-exports.ts +47 -0
- package/src/scope.ts +146 -77
- package/src/type.ts +40 -25
- package/tests/analyze.ts +45 -6
- package/tests/compile.ts +65 -0
- package/tests/condition.ts +33 -17
- package/tests/definition.ts +237 -18
- package/tests/eval-complex.ts +79 -13
- package/tests/eval.ts +59 -12
- package/tests/import.ts +21 -7
- package/tests/main.ts +58 -0
- package/tests/migrate.ts +317 -0
- package/tests/scope.ts +3 -3
- package/tests/template.ts +36 -0
- package/dist/context.d.ts +0 -41
- package/dist/context.d.ts.map +0 -1
- package/dist/context.js +0 -18
- package/dist/context.js.map +0 -1
- package/src/context.ts +0 -54
package/tests/migrate.ts
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import { migrateMathJs } from '@cloudpss/expression/migrate';
|
|
2
|
+
import type { ExpressionSource } from '../dist/expression.js';
|
|
3
|
+
import { Scope } from '../dist/scope.js';
|
|
4
|
+
import { Evaluator, Expression, VmError } from '../dist/index.js';
|
|
5
|
+
import dedent from 'dedent';
|
|
6
|
+
|
|
7
|
+
const s = new Scope({
|
|
8
|
+
a: [1, 2, 3],
|
|
9
|
+
m: [
|
|
10
|
+
[1, 2],
|
|
11
|
+
[3, 4],
|
|
12
|
+
],
|
|
13
|
+
f: 1,
|
|
14
|
+
s: 'abc',
|
|
15
|
+
b: false,
|
|
16
|
+
o: {
|
|
17
|
+
x: 1,
|
|
18
|
+
y: 2,
|
|
19
|
+
},
|
|
20
|
+
type: 'keyword',
|
|
21
|
+
});
|
|
22
|
+
const e = new Evaluator();
|
|
23
|
+
|
|
24
|
+
describe('migrate', () => {
|
|
25
|
+
it('should migrate constant expressions', () => {
|
|
26
|
+
const m = (e: string) => migrateMathJs(e as ExpressionSource, false, undefined);
|
|
27
|
+
expect(m('')).toBe('');
|
|
28
|
+
expect(m(' ')).toBe('');
|
|
29
|
+
expect(m('undefined')).toBe('');
|
|
30
|
+
expect(m('null')).toBe('nil');
|
|
31
|
+
expect(m('true')).toBe('true');
|
|
32
|
+
expect(m('false')).toBe('false');
|
|
33
|
+
expect(m('123')).toBe('123');
|
|
34
|
+
expect(m('-123.45e+6')).toBe('-123.45e+6');
|
|
35
|
+
expect(m('+123.45e-6')).toBe('+123.45e-6');
|
|
36
|
+
expect(m('.45e-6')).toBe('4.5e-7');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it.each([
|
|
40
|
+
['sin(0)', 'sin(0)', 0],
|
|
41
|
+
['sin(f)', 'sin(f)', Math.sin(1)],
|
|
42
|
+
['f', 'f', 1],
|
|
43
|
+
['o == null', 'o == nil', false],
|
|
44
|
+
['o == undefined', 'o == nil', false],
|
|
45
|
+
['o == undefined', 'o == nil', false],
|
|
46
|
+
['b == false', 'b =~ 0', true],
|
|
47
|
+
['true != b', '1 !~ b', true],
|
|
48
|
+
['f == true', 'f =~ 1', true],
|
|
49
|
+
['false == f', '0 =~ f', false],
|
|
50
|
+
['0 <= f + 1 <= 2', 'f + 1 is 0..2', true],
|
|
51
|
+
['$a', '$a', VmError],
|
|
52
|
+
['$a + 1', 'matrix.add($a, 1)', VmError],
|
|
53
|
+
['size(a)[1]', 'len(a)', 3],
|
|
54
|
+
['size(s)[1]', 'len(chars(s))', 3],
|
|
55
|
+
['(a).length', 'len((a))', 3],
|
|
56
|
+
['(s).length', 'len(chars((s)))', 3],
|
|
57
|
+
['count(s)', 'len(chars(s))', 3],
|
|
58
|
+
['b ? true : false', 'b', false],
|
|
59
|
+
['b ? false : true', '!b', true],
|
|
60
|
+
['is(f, "string") ? count(f) != 0 : false', "type(f) == 'string' && f != ''", false],
|
|
61
|
+
['is(f, "string") ? equalText(f, "xyz") : false', "f == 'xyz'", false],
|
|
62
|
+
['b ? 1 : 2', 'if b { 1 } else { 2 }', 2],
|
|
63
|
+
['f >0', 'f > 0', true],
|
|
64
|
+
['f >=0', 'f >= 0', true],
|
|
65
|
+
['f <0', 'f < 0', false],
|
|
66
|
+
['f == 1', 'f =~ 1', true],
|
|
67
|
+
['f != 1', 'f !~ 1', false],
|
|
68
|
+
['1<f<2', '1 < f && f < 2', false],
|
|
69
|
+
['1 + 2 + f', '1 + 2 + f', 4],
|
|
70
|
+
['PI', 'PI', Math.PI],
|
|
71
|
+
['pi', 'PI', Math.PI],
|
|
72
|
+
['E', 'E', Math.E],
|
|
73
|
+
['e', 'E', Math.E],
|
|
74
|
+
['[1,2,3]', '[1, 2, 3]', [1, 2, 3]],
|
|
75
|
+
['[1;2;3]', '[[1], [2], [3]]', [[1], [2], [3]]],
|
|
76
|
+
['{ x: 1, y: 2 }', '(x: 1, y: 2)', { x: 1, y: 2 }],
|
|
77
|
+
['{ x: f, y: b }', '(x: f, y: b)', { x: 1, y: false }],
|
|
78
|
+
['equalText("a", "b")', "'a' == 'b'", false],
|
|
79
|
+
['equalText("a", s)', "'a' == s", false],
|
|
80
|
+
['equalText(s, "b")', "s == 'b'", false],
|
|
81
|
+
['equalText(s, f)', 's == to_string(f)', false],
|
|
82
|
+
['b | b', 'to_number(b || b)', 0],
|
|
83
|
+
['b & b', 'to_number(b && b)', 0],
|
|
84
|
+
['not b', '!b', true],
|
|
85
|
+
['12!', 'factorial(12)', 479_001_600],
|
|
86
|
+
['- b', '-b', -0],
|
|
87
|
+
['+ b', '+b', +0],
|
|
88
|
+
['- f', '-f', -1],
|
|
89
|
+
['b ^| f', 'b_xor(b, f)', 1],
|
|
90
|
+
['b ^| (not b)', 'to_number(b != (!b))', 1],
|
|
91
|
+
[
|
|
92
|
+
'not b xor f + 1',
|
|
93
|
+
dedent`
|
|
94
|
+
return (!b) != @@to_boolean(f + 1);
|
|
95
|
+
// # 帮助函数
|
|
96
|
+
fn @@to_boolean { if it is nil { nil } else { it != '' && it != '0' && it != 0 && it is not nan && it != false } }
|
|
97
|
+
// # 原始 math.js 表达式
|
|
98
|
+
// not b xor f + 1`,
|
|
99
|
+
false,
|
|
100
|
+
],
|
|
101
|
+
['size(f)', 'matrix.size(f)', []],
|
|
102
|
+
['size(m)', 'matrix.size(m)', [2, 2]],
|
|
103
|
+
[`[1,2,3] == f`, `[1, 2, 3]::map(fn { it =~ f })`, [true, false, false]],
|
|
104
|
+
[`$V != [1,2,3]`, `[1, 2, 3]::map(fn { $V !~ it })`, VmError],
|
|
105
|
+
[
|
|
106
|
+
'u.length',
|
|
107
|
+
dedent`
|
|
108
|
+
return @@length(u);
|
|
109
|
+
// # 帮助函数
|
|
110
|
+
fn @@length(x) { if type(x) == 'string' { len(chars(x)) } else if type(x) == 'array' { len(x) } else { x.length } }
|
|
111
|
+
// # 转换日志
|
|
112
|
+
// - W: 符号 'u' 未定义
|
|
113
|
+
// # 原始 math.js 表达式
|
|
114
|
+
// u.length`,
|
|
115
|
+
VmError,
|
|
116
|
+
],
|
|
117
|
+
['o["x"]', 'o.x', 1],
|
|
118
|
+
['o.x', 'o.x', 1],
|
|
119
|
+
[
|
|
120
|
+
'o[s]',
|
|
121
|
+
dedent`
|
|
122
|
+
return o[@@index(s)];
|
|
123
|
+
// # 帮助函数
|
|
124
|
+
fn @@index(index) { if type(index) == 'number' { index - 1 } else { index } }
|
|
125
|
+
// # 原始 math.js 表达式
|
|
126
|
+
// o[s]`,
|
|
127
|
+
null,
|
|
128
|
+
],
|
|
129
|
+
[
|
|
130
|
+
'o[f]',
|
|
131
|
+
dedent`
|
|
132
|
+
return o[@@index(f)];
|
|
133
|
+
// # 帮助函数
|
|
134
|
+
fn @@index(index) { if type(index) == 'number' { index - 1 } else { index } }
|
|
135
|
+
// # 原始 math.js 表达式
|
|
136
|
+
// o[f]`,
|
|
137
|
+
null,
|
|
138
|
+
],
|
|
139
|
+
[`{x:1,y:2}['x']`, `(x: 1, y: 2).x`, 1],
|
|
140
|
+
[`{x:1,y:2}[s]`, `(x: 1, y: 2)[s]`, null],
|
|
141
|
+
[`[1,2,3][f]`, `[1, 2, 3][f - 1]`, 1],
|
|
142
|
+
['"abc"[1]', "chars('abc')[0]", 'a'],
|
|
143
|
+
['s[1]', 'chars(s)[0]', 'a'],
|
|
144
|
+
['[1,2,3][2]', '[1, 2, 3][1]', 2],
|
|
145
|
+
['a[2]', 'a[1]', 2],
|
|
146
|
+
[
|
|
147
|
+
'a[u]',
|
|
148
|
+
dedent`
|
|
149
|
+
return a[@@index(u)];
|
|
150
|
+
// # 帮助函数
|
|
151
|
+
fn @@index(index) { if type(index) == 'number' { index - 1 } else { index } }
|
|
152
|
+
// # 转换日志
|
|
153
|
+
// - W: 符号 'u' 未定义
|
|
154
|
+
// # 原始 math.js 表达式
|
|
155
|
+
// a[u]`,
|
|
156
|
+
VmError,
|
|
157
|
+
],
|
|
158
|
+
[
|
|
159
|
+
'u[1]',
|
|
160
|
+
dedent`
|
|
161
|
+
return @@maybe_chars(u)[0];
|
|
162
|
+
// # 帮助函数
|
|
163
|
+
fn @@maybe_chars(x) { if type(x) == 'string' { chars(x) } else { x } }
|
|
164
|
+
// # 转换日志
|
|
165
|
+
// - W: 符号 'u' 未定义
|
|
166
|
+
// # 原始 math.js 表达式
|
|
167
|
+
// u[1]`,
|
|
168
|
+
VmError,
|
|
169
|
+
],
|
|
170
|
+
[
|
|
171
|
+
'm[1,2]',
|
|
172
|
+
dedent`
|
|
173
|
+
m[0][1]
|
|
174
|
+
// # 转换日志
|
|
175
|
+
// - W: 多维索引已拆分为多次单维索引
|
|
176
|
+
// # 原始 math.js 表达式
|
|
177
|
+
// m[1,2]`,
|
|
178
|
+
2,
|
|
179
|
+
],
|
|
180
|
+
[
|
|
181
|
+
'm[f,2]',
|
|
182
|
+
dedent`
|
|
183
|
+
m[f - 1][1]
|
|
184
|
+
// # 转换日志
|
|
185
|
+
// - W: 多维索引已拆分为多次单维索引
|
|
186
|
+
// # 原始 math.js 表达式
|
|
187
|
+
// m[f,2]`,
|
|
188
|
+
2,
|
|
189
|
+
],
|
|
190
|
+
[
|
|
191
|
+
'filter(x) = x > 1; a.filter(filter)',
|
|
192
|
+
dedent`
|
|
193
|
+
fn filter(x) { matrix.entrywise(x, 1, fn (a, b) { a > b }) }
|
|
194
|
+
a::global.filter(filter)
|
|
195
|
+
// # 转换日志
|
|
196
|
+
// - W: 使用了非精确转换的语法或函数,结果可能不准确
|
|
197
|
+
// # 原始 math.js 表达式
|
|
198
|
+
// filter(x) = x > 1; a.filter(filter)`,
|
|
199
|
+
[2, 3],
|
|
200
|
+
],
|
|
201
|
+
[`print('hello world, $s!', {s:s})`, '`hello world, $(s)!`', `hello world, abc!`],
|
|
202
|
+
[`print('hello world, $1!', [s])`, '`hello world, $(s)!`', `hello world, abc!`],
|
|
203
|
+
[`concat('Value: ', f, string(1 >= 0))`, '`Value: $(f)$(1 >= 0)`', 'Value: 1true'],
|
|
204
|
+
[`concat(s, f, string(1 >= 0))`, '`$(s)$(f)$(1 >= 0)`', 'abc1true'],
|
|
205
|
+
[
|
|
206
|
+
String.raw`'Value: '.concat('\\x', '$', 1, f, string(1 >= 0))`,
|
|
207
|
+
'`Value: \\\\x\\$1$(f)$(1 >= 0)`',
|
|
208
|
+
String.raw`Value: \x$11true`,
|
|
209
|
+
],
|
|
210
|
+
[
|
|
211
|
+
`concat([1], a)`,
|
|
212
|
+
dedent`
|
|
213
|
+
flatten([[1], a])
|
|
214
|
+
// # 转换日志
|
|
215
|
+
// - W: 矩阵连接时结果可能不一致
|
|
216
|
+
// # 原始 math.js 表达式
|
|
217
|
+
// concat([1], a)
|
|
218
|
+
`,
|
|
219
|
+
[1, 1, 2, 3],
|
|
220
|
+
],
|
|
221
|
+
[`equalText(type, "keyword")`, `global.type == 'keyword'`, true],
|
|
222
|
+
[
|
|
223
|
+
`type = { "a": [1,2,3] }; type.a[1]`,
|
|
224
|
+
dedent`
|
|
225
|
+
let __type__ = (a: [1, 2, 3]);
|
|
226
|
+
return @@maybe_chars(__type__.a)[0];
|
|
227
|
+
// # 帮助函数
|
|
228
|
+
fn @@maybe_chars(x) { if type(x) == 'string' { chars(x) } else { x } }
|
|
229
|
+
// # 转换日志
|
|
230
|
+
// - W: 变量名 'type' 是 MiraScript 关键字,已转换为 '__type__'
|
|
231
|
+
// # 原始 math.js 表达式
|
|
232
|
+
// type = { "a": [1,2,3] }; type.a[1]
|
|
233
|
+
`,
|
|
234
|
+
1,
|
|
235
|
+
],
|
|
236
|
+
[
|
|
237
|
+
'[1,2,3].map(f(x,y,z) = x^2)',
|
|
238
|
+
dedent`
|
|
239
|
+
return [1, 2, 3]::map(f);
|
|
240
|
+
// # 帮助函数
|
|
241
|
+
fn f(x, y, z) { x^2 }
|
|
242
|
+
// # 转换日志
|
|
243
|
+
// - W: 使用了非精确转换的语法或函数,结果可能不准确
|
|
244
|
+
// - W: '^' 不支持矩阵,计算结果可能不一致
|
|
245
|
+
// # 原始 math.js 表达式
|
|
246
|
+
// [1,2,3].map(f(x,y,z) = x^2)
|
|
247
|
+
`,
|
|
248
|
+
[1, 4, 9],
|
|
249
|
+
],
|
|
250
|
+
['', '', null],
|
|
251
|
+
['#', '//', null],
|
|
252
|
+
['#xx', '//xx', null],
|
|
253
|
+
['(random() - 1) < 0', '(random() - 1) < 0', true],
|
|
254
|
+
[
|
|
255
|
+
're(12) + im(i)',
|
|
256
|
+
dedent`
|
|
257
|
+
/* re */(12) + /* im */(i)
|
|
258
|
+
// # 转换日志
|
|
259
|
+
// - E: 不支持复数
|
|
260
|
+
// # 原始 math.js 表达式
|
|
261
|
+
// re(12) + im(i)
|
|
262
|
+
`,
|
|
263
|
+
VmError,
|
|
264
|
+
],
|
|
265
|
+
['is(a, "number")', "type(a) == 'number'", false],
|
|
266
|
+
['is(a, "string")', "type(a) == 'string'", false],
|
|
267
|
+
['is(a, "boolean")', "type(a) == 'boolean'", false],
|
|
268
|
+
['is(a, "null")', "type(a) == 'nil'", false],
|
|
269
|
+
['is(a, "undefined")', "type(a) == 'nil'", false],
|
|
270
|
+
[`sum([a > 1])`, `sum([matrix.entrywise(a, 1, fn (a, b) { a > b })]::flatten())`, 2],
|
|
271
|
+
[`prod(1,2,3)`, `product(1, 2, 3)`, 6],
|
|
272
|
+
[`sum(true)`, `sum(true)`, 1],
|
|
273
|
+
[`sum(m)`, `sum(m::flatten())`, 10],
|
|
274
|
+
[`prod([1,2,3])`, `product([1, 2, 3])`, 6],
|
|
275
|
+
[`prod(f)`, `product(f)`, 1],
|
|
276
|
+
[`abs(f) + round(f) + f`, `abs(f) + round(f) + f`, 3],
|
|
277
|
+
[
|
|
278
|
+
`abs([1,2,3;-4,-5,-6])`,
|
|
279
|
+
`matrix.entrywise([[1, 2, 3], [-4, -5, -6]], nil, abs)`,
|
|
280
|
+
[
|
|
281
|
+
[1, 2, 3],
|
|
282
|
+
[4, 5, 6],
|
|
283
|
+
],
|
|
284
|
+
],
|
|
285
|
+
[`max(1, 2, f) + f`, `max(1, 2, f) + f`, 3],
|
|
286
|
+
[`min(1, 2, f) + f`, `min(1, 2, f) + f`, 2],
|
|
287
|
+
[
|
|
288
|
+
`max([1,2;3,4], 1)`,
|
|
289
|
+
dedent`
|
|
290
|
+
max([[1, 2], [3, 4]], 1)
|
|
291
|
+
// # 转换日志
|
|
292
|
+
// - W: 函数行为可能不一致: max
|
|
293
|
+
// # 原始 math.js 表达式
|
|
294
|
+
// max([1,2;3,4], 1)`,
|
|
295
|
+
VmError,
|
|
296
|
+
],
|
|
297
|
+
[`0:(f + 1)`, `[0..(f + 1)]`, [0, 1, 2]],
|
|
298
|
+
[`3:1`, `[3..1]`, []],
|
|
299
|
+
[`1:+1:2`, `[1..2]`, [1, 2]],
|
|
300
|
+
[`3:-1:1`, `[1..3]`, [1, 2, 3]],
|
|
301
|
+
[`1:4 + 1`, `[1..4 + 1]`, [1, 2, 3, 4, 5]],
|
|
302
|
+
[`1.2:2*3`, `[1.2..2 * 3]`, [1.2, 2.2, 3.2, 4.2, 5.2]],
|
|
303
|
+
[`a[1:2]`, 'a[0..1]', [1, 2]],
|
|
304
|
+
[`a[2:-1:1]`, 'a[0..1]::reverse()', [2, 1]],
|
|
305
|
+
[`not b and f > 0`, `!b && f > 0`, true],
|
|
306
|
+
])('should migrate expression: %s', (f, t, r) => {
|
|
307
|
+
const migrated = migrateMathJs(f as ExpressionSource, false, s);
|
|
308
|
+
expect(migrated).toBe(t);
|
|
309
|
+
if (typeof r === 'function' && r.prototype instanceof Error) {
|
|
310
|
+
expect(() => {
|
|
311
|
+
e.evaluate(Expression(migrated), s);
|
|
312
|
+
}).toThrow(r);
|
|
313
|
+
} else {
|
|
314
|
+
expect(e.evaluate(Expression(migrated), s)).toEqual(r);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
});
|
package/tests/scope.ts
CHANGED
|
@@ -10,7 +10,7 @@ describe('Scope should work correctly', () => {
|
|
|
10
10
|
it('can create from function', () => {
|
|
11
11
|
const s = new Scope((k) => (k === 'a' ? 12 : undefined), false);
|
|
12
12
|
expect(e.evaluate(Expression('a'), s)).toBe(12);
|
|
13
|
-
expect(e.evaluate(Expression('b'), s)).toBe(
|
|
13
|
+
expect(e.evaluate(Expression('`b` in global'), s)).toBe(false);
|
|
14
14
|
});
|
|
15
15
|
it('can create from object', () => {
|
|
16
16
|
const s = new Scope({ a: 12, b: Expression('a + 1') }, false);
|
|
@@ -22,8 +22,8 @@ describe('Scope should work correctly', () => {
|
|
|
22
22
|
describe('Scope should not leak dangerous objects', () => {
|
|
23
23
|
it('should not access prototype fields', () => {
|
|
24
24
|
const s = new Scope({}, false);
|
|
25
|
-
expect(e.evaluate(Expression('__proto__'), s)).toBe(
|
|
26
|
-
expect(e.evaluate(Expression('toString'), s)).toBe(
|
|
25
|
+
expect(e.evaluate(Expression('`__proto__` in global'), s)).toBe(false);
|
|
26
|
+
expect(e.evaluate(Expression('`toString` in global'), s)).toBe(false);
|
|
27
27
|
});
|
|
28
28
|
it('should access same name props', () => {
|
|
29
29
|
const s = new Scope({ ['__proto__']: 12, toString: 'x' }, false);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Evaluator, Expression, Scope } from '../dist/index.js';
|
|
2
|
+
|
|
3
|
+
const e = new Evaluator();
|
|
4
|
+
const s = new Scope({}, false);
|
|
5
|
+
|
|
6
|
+
describe('Evaluator.template should work correctly', () => {
|
|
7
|
+
it('should eval null', () => {
|
|
8
|
+
const result = e.template(null, s);
|
|
9
|
+
expect(result).toBe('');
|
|
10
|
+
});
|
|
11
|
+
it('should eval undefined', () => {
|
|
12
|
+
const result = e.template(undefined, s);
|
|
13
|
+
expect(result).toBe('');
|
|
14
|
+
});
|
|
15
|
+
it('should eval empty', () => {
|
|
16
|
+
const result = e.template('', s);
|
|
17
|
+
expect(result).toBe('');
|
|
18
|
+
});
|
|
19
|
+
it('should eval const', () => {
|
|
20
|
+
const result = e.template('12', s);
|
|
21
|
+
expect(result).toBe('12');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should eval exp', () => {
|
|
25
|
+
const result = e.template('$(1 + 1)', s);
|
|
26
|
+
expect(result).toBe('2');
|
|
27
|
+
});
|
|
28
|
+
it('should eval error', () => {
|
|
29
|
+
const result = e.template('$(exp+++)', s);
|
|
30
|
+
expect(result).toBe('$(exp+++)');
|
|
31
|
+
});
|
|
32
|
+
it('should eval bad type', () => {
|
|
33
|
+
// @ts-expect-error 测试错误输入
|
|
34
|
+
expect(() => e.template(new Date(0), s)).toThrow(TypeError);
|
|
35
|
+
});
|
|
36
|
+
});
|
package/dist/context.d.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { LRUCache } from 'lru-cache';
|
|
2
|
-
import type { ExpressionCache } from './parser.js';
|
|
3
|
-
import type { VmValue } from '@mirascript/mirascript';
|
|
4
|
-
/** 日志 */
|
|
5
|
-
export interface Logger {
|
|
6
|
-
/**
|
|
7
|
-
* error
|
|
8
|
-
*/
|
|
9
|
-
error(...args: unknown[]): void;
|
|
10
|
-
/**
|
|
11
|
-
* warning
|
|
12
|
-
*/
|
|
13
|
-
warn(...args: unknown[]): void;
|
|
14
|
-
/**
|
|
15
|
-
* info
|
|
16
|
-
*/
|
|
17
|
-
info(...args: unknown[]): void;
|
|
18
|
-
/**
|
|
19
|
-
* debug
|
|
20
|
-
*/
|
|
21
|
-
debug(...args: unknown[]): void;
|
|
22
|
-
}
|
|
23
|
-
/** 选项 */
|
|
24
|
-
export interface Options {
|
|
25
|
-
/** 日志 */
|
|
26
|
-
logger: Logger;
|
|
27
|
-
/** 表达式缓存 */
|
|
28
|
-
expressionCacheSize: number;
|
|
29
|
-
}
|
|
30
|
-
/** 执行上下文 */
|
|
31
|
-
export declare class Context {
|
|
32
|
-
constructor(options?: Partial<Options>);
|
|
33
|
-
readonly imported: Map<string, VmValue>;
|
|
34
|
-
/** Logger */
|
|
35
|
-
get logger(): Logger;
|
|
36
|
-
/** 选项 */
|
|
37
|
-
readonly options: Options;
|
|
38
|
-
/** 表达式缓存 */
|
|
39
|
-
readonly expressionCache: LRUCache<string, ExpressionCache, unknown>;
|
|
40
|
-
}
|
|
41
|
-
//# sourceMappingURL=context.d.ts.map
|
package/dist/context.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEtD,SAAS;AACT,MAAM,WAAW,MAAM;IACnB;;OAEG;IACH,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChC;;OAEG;IACH,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC/B;;OAEG;IACH,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC/B;;OAEG;IACH,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CACnC;AAED,SAAS;AACT,MAAM,WAAW,OAAO;IACpB,SAAS;IACT,MAAM,EAAE,MAAM,CAAC;IACf,YAAY;IACZ,mBAAmB,EAAE,MAAM,CAAC;CAC/B;AAOD,YAAY;AACZ,qBAAa,OAAO;gBACJ,OAAO,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC;IAItC,QAAQ,CAAC,QAAQ,uBAA8B;IAC/C,aAAa;IACb,IAAI,MAAM,IAAI,MAAM,CAEnB;IACD,SAAS;IACT,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAE1B,YAAY;IACZ,QAAQ,CAAC,eAAe,6CAAC;CAC5B"}
|
package/dist/context.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { LRUCache } from 'lru-cache';
|
|
2
|
-
const defaultOptions = {
|
|
3
|
-
logger: console,
|
|
4
|
-
expressionCacheSize: 50,
|
|
5
|
-
};
|
|
6
|
-
/** 执行上下文 */
|
|
7
|
-
export class Context {
|
|
8
|
-
constructor(options) {
|
|
9
|
-
this.imported = new Map();
|
|
10
|
-
this.options = { ...options, ...defaultOptions };
|
|
11
|
-
this.expressionCache = new LRUCache({ max: this.options.expressionCacheSize });
|
|
12
|
-
}
|
|
13
|
-
/** Logger */
|
|
14
|
-
get logger() {
|
|
15
|
-
return this.options.logger ?? console;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
//# sourceMappingURL=context.js.map
|
package/dist/context.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAgCrC,MAAM,cAAc,GAAY;IAC5B,MAAM,EAAE,OAAO;IACf,mBAAmB,EAAE,EAAE;CAC1B,CAAC;AAEF,YAAY;AACZ,MAAM,OAAO,OAAO;IAChB,YAAY,OAA0B;QAI7B,aAAQ,GAAG,IAAI,GAAG,EAAmB,CAAC;QAH3C,IAAI,CAAC,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;QACjD,IAAI,CAAC,eAAe,GAAG,IAAI,QAAQ,CAA0B,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC;IAC5G,CAAC;IAED,aAAa;IACb,IAAI,MAAM;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC;IAC1C,CAAC;CAMJ"}
|
package/src/context.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { LRUCache } from 'lru-cache';
|
|
2
|
-
import type { ExpressionCache } from './parser.js';
|
|
3
|
-
import type { VmValue } from '@mirascript/mirascript';
|
|
4
|
-
|
|
5
|
-
/** 日志 */
|
|
6
|
-
export interface Logger {
|
|
7
|
-
/**
|
|
8
|
-
* error
|
|
9
|
-
*/
|
|
10
|
-
error(...args: unknown[]): void;
|
|
11
|
-
/**
|
|
12
|
-
* warning
|
|
13
|
-
*/
|
|
14
|
-
warn(...args: unknown[]): void;
|
|
15
|
-
/**
|
|
16
|
-
* info
|
|
17
|
-
*/
|
|
18
|
-
info(...args: unknown[]): void;
|
|
19
|
-
/**
|
|
20
|
-
* debug
|
|
21
|
-
*/
|
|
22
|
-
debug(...args: unknown[]): void;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** 选项 */
|
|
26
|
-
export interface Options {
|
|
27
|
-
/** 日志 */
|
|
28
|
-
logger: Logger;
|
|
29
|
-
/** 表达式缓存 */
|
|
30
|
-
expressionCacheSize: number;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const defaultOptions: Options = {
|
|
34
|
-
logger: console,
|
|
35
|
-
expressionCacheSize: 50,
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
/** 执行上下文 */
|
|
39
|
-
export class Context {
|
|
40
|
-
constructor(options?: Partial<Options>) {
|
|
41
|
-
this.options = { ...options, ...defaultOptions };
|
|
42
|
-
this.expressionCache = new LRUCache<string, ExpressionCache>({ max: this.options.expressionCacheSize });
|
|
43
|
-
}
|
|
44
|
-
readonly imported = new Map<string, VmValue>();
|
|
45
|
-
/** Logger */
|
|
46
|
-
get logger(): Logger {
|
|
47
|
-
return this.options.logger ?? console;
|
|
48
|
-
}
|
|
49
|
-
/** 选项 */
|
|
50
|
-
readonly options: Options;
|
|
51
|
-
|
|
52
|
-
/** 表达式缓存 */
|
|
53
|
-
readonly expressionCache;
|
|
54
|
-
}
|