@cloudpss/expression 0.6.0-alpha.10 → 0.6.0-alpha.11

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/tests/migrate.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { migrateMathJs } from '@cloudpss/expression/migrate';
2
2
  import type { ExpressionSource } from '../dist/expression.js';
3
3
  import { Scope } from '../dist/scope.js';
4
+ import { Evaluator, Expression } from '../dist/index.js';
5
+ import dedent from 'dedent';
4
6
 
5
7
  const s = new Scope({
6
8
  a: [1, 2, 3],
@@ -9,9 +11,14 @@ const s = new Scope({
9
11
  [3, 4],
10
12
  ],
11
13
  f: 1,
12
- s: 's',
14
+ s: 'abc',
13
15
  b: false,
16
+ o: {
17
+ x: 1,
18
+ y: 2,
19
+ },
14
20
  });
21
+ const e = new Evaluator();
15
22
 
16
23
  describe('migrate', () => {
17
24
  it('should migrate constant expressions', () => {
@@ -29,49 +36,167 @@ describe('migrate', () => {
29
36
  });
30
37
 
31
38
  it.each([
32
- ['sin(0)', 'sin(0)'],
33
- ['sin(f)', 'sin(f)'],
34
- ['f', 'f'],
35
- ['$a', '$a'],
36
- ['$a + 1', 'matrix.add($a, 1)'],
37
- ['size(a)[1]', 'len(a)'],
38
- ['size(s)[1]', 'len(chars(s))'],
39
- ['(a).length', 'len((a))'],
40
- ['(s).length', 'len(chars((s)))'],
41
- ['count(s)', 'len(chars(s))'],
42
- ['b ? true : false', 'b'],
43
- ['b ? false : true', '!b'],
44
- ['is(f, "string") ? count(f) != 0 : false', "type(f) == 'string' && f != ''"],
45
- ['is(f, "string") ? equalText(f, "xyz") : false', "f == 'xyz'"],
46
- ['b ? 1 : 2', 'if b { 1 } else { 2 }'],
47
- ['f >0', 'f > 0'],
48
- ['f >=0', 'f >= 0'],
49
- ['f <0', 'f < 0'],
50
- ['1<f<2', '1 < f && f < 2'],
51
- ['1 + 2 + f', '1 + 2 + f'],
52
- ['PI', '@pi'],
53
- ['pi', '@pi'],
54
- ['E', '@e'],
55
- ['e', '@e'],
56
- ['[1,2,3]', '[1, 2, 3]'],
57
- ['[1;2;3]', '[[1], [2], [3]]'],
58
- ['{ x: 1, y: 2 }', '(x: 1, y: 2)'],
59
- ['{ x: f, y: b }', '(x: f, y: b)'],
60
- ['equalText("a", "b")', "'a' == 'b'"],
61
- ['equalText("a", s)', "'a' == s"],
62
- ['equalText(s, "b")', "s == 'b'"],
63
- ['equalText(s, f)', 's == to_string(f)'],
64
- ['b | b', 'to_number(b || b)'],
65
- ['b & b', 'to_number(b && b)'],
66
- ['not b', '!b'],
67
- ['12!', 'factorial(12)'],
68
- ['- b', '-b'],
69
- ['+ b', '+b'],
70
- ['- f', '-f'],
71
- ['size(f)', 'matrix.size(f)'],
72
- ['size(m)', 'matrix.size(m)'],
73
- ])('should migrate expression: %s', (f, t) => {
74
- const m = (e: string) => migrateMathJs(e as ExpressionSource, false, s);
75
- expect(m(f)).toBe(t);
39
+ ['sin(0)', 'sin(0)', 0],
40
+ ['sin(f)', 'sin(f)', Math.sin(1)],
41
+ ['f', 'f', 1],
42
+ ['$a', '$a', null],
43
+ ['$a + 1', 'matrix.add($a, 1)', 1],
44
+ ['size(a)[1]', 'len(a)', 3],
45
+ ['size(s)[1]', 'len(chars(s))', 3],
46
+ ['(a).length', 'len((a))', 3],
47
+ ['(s).length', 'len(chars((s)))', 3],
48
+ ['count(s)', 'len(chars(s))', 3],
49
+ ['b ? true : false', 'b', false],
50
+ ['b ? false : true', '!b', true],
51
+ ['is(f, "string") ? count(f) != 0 : false', "type(f) == 'string' && f != ''", false],
52
+ ['is(f, "string") ? equalText(f, "xyz") : false', "f == 'xyz'", false],
53
+ ['b ? 1 : 2', 'if b { 1 } else { 2 }', 2],
54
+ ['f >0', 'f > 0', true],
55
+ ['f >=0', 'f >= 0', true],
56
+ ['f <0', 'f < 0', false],
57
+ ['1<f<2', '1 < f && f < 2', false],
58
+ ['1 + 2 + f', '1 + 2 + f', 4],
59
+ ['PI', '@pi', Math.PI],
60
+ ['pi', '@pi', Math.PI],
61
+ ['E', '@e', Math.E],
62
+ ['e', '@e', Math.E],
63
+ ['[1,2,3]', '[1, 2, 3]', [1, 2, 3]],
64
+ ['[1;2;3]', '[[1], [2], [3]]', [[1], [2], [3]]],
65
+ ['{ x: 1, y: 2 }', '(x: 1, y: 2)', { x: 1, y: 2 }],
66
+ ['{ x: f, y: b }', '(x: f, y: b)', { x: 1, y: false }],
67
+ ['equalText("a", "b")', "'a' == 'b'", false],
68
+ ['equalText("a", s)', "'a' == s", false],
69
+ ['equalText(s, "b")', "s == 'b'", false],
70
+ ['equalText(s, f)', 's == to_string(f)', false],
71
+ ['b | b', 'to_number(b || b)', 0],
72
+ ['b & b', 'to_number(b && b)', 0],
73
+ ['not b', '!b', true],
74
+ ['12!', 'factorial(12)', 479_001_600],
75
+ ['- b', '-b', -0],
76
+ ['+ b', '+b', +0],
77
+ ['- f', '-f', -1],
78
+ ['size(f)', 'matrix.size(f)', []],
79
+ ['size(m)', 'matrix.size(m)', [2, 2]],
80
+ [
81
+ 'u.length',
82
+ dedent`
83
+ return @@length(u);
84
+ // # 帮助函数
85
+ fn @@length(x) { if type(x) == 'string' { len(chars(x)) } else if type(x) == 'array' { len(x) } else { x.length } }
86
+ // # 转换日志
87
+ // - W: 符号 'u' 未定义
88
+ // # 原始 math.js 表达式
89
+ // u.length`,
90
+ null,
91
+ ],
92
+ ['o["x"]', 'o.x', 1],
93
+ ['o.x', 'o.x', 1],
94
+ [
95
+ 'o[s]',
96
+ dedent`
97
+ return o[@@index(s)];
98
+ // # 帮助函数
99
+ fn @@index(index) { if type(index) == 'number' { index - 1 } else { index } }
100
+ // # 原始 math.js 表达式
101
+ // o[s]`,
102
+ null,
103
+ ],
104
+ [
105
+ 'o[f]',
106
+ dedent`
107
+ return o[@@index(f)];
108
+ // # 帮助函数
109
+ fn @@index(index) { if type(index) == 'number' { index - 1 } else { index } }
110
+ // # 原始 math.js 表达式
111
+ // o[f]`,
112
+ null,
113
+ ],
114
+ [`{x:1,y:2}['x']`, `(x: 1, y: 2).x`, 1],
115
+ [`{x:1,y:2}[s]`, `(x: 1, y: 2)[s]`, null],
116
+ [`[1,2,3][f]`, `[1, 2, 3][f - 1]`, 1],
117
+ ['"abc"[1]', "chars('abc')[0]", 'a'],
118
+ ['s[1]', 'chars(s)[0]', 'a'],
119
+ ['[1,2,3][2]', '[1, 2, 3][1]', 2],
120
+ ['a[2]', 'a[1]', 2],
121
+ [
122
+ 'a[u]',
123
+ dedent`
124
+ return a[@@index(u)];
125
+ // # 帮助函数
126
+ fn @@index(index) { if type(index) == 'number' { index - 1 } else { index } }
127
+ // # 转换日志
128
+ // - W: 符号 'u' 未定义
129
+ // # 原始 math.js 表达式
130
+ // a[u]`,
131
+ 1,
132
+ ],
133
+ [
134
+ 'u[1]',
135
+ dedent`
136
+ return @@maybe_chars(u)[0];
137
+ // # 帮助函数
138
+ fn @@maybe_chars(x) { if type(x) == 'string' { chars(x) } else { x } }
139
+ // # 转换日志
140
+ // - W: 符号 'u' 未定义
141
+ // # 原始 math.js 表达式
142
+ // u[1]`,
143
+ null,
144
+ ],
145
+ [
146
+ 'm[1,2]',
147
+ dedent`
148
+ m[0][1]
149
+ // # 转换日志
150
+ // - W: 多维索引已拆分为多次单维索引
151
+ // # 原始 math.js 表达式
152
+ // m[1,2]`,
153
+ 2,
154
+ ],
155
+ [
156
+ 'm[f,2]',
157
+ dedent`
158
+ m[f - 1][1]
159
+ // # 转换日志
160
+ // - W: 多维索引已拆分为多次单维索引
161
+ // # 原始 math.js 表达式
162
+ // m[f,2]`,
163
+ 2,
164
+ ],
165
+ [
166
+ 'filter(x) = x > 1; a.filter(filter)',
167
+ dedent`
168
+ fn filter(x) { x > 1 }
169
+ a::global.filter(filter)
170
+ // # 转换日志
171
+ // - W: 使用了非精确转换的语法或函数,结果可能不准确
172
+ // - W: '>' 不支持矩阵,计算结果可能不一致
173
+ // # 原始 math.js 表达式
174
+ // filter(x) = x > 1; a.filter(filter)`,
175
+ [2, 3],
176
+ ],
177
+ [`print('hello world, $s!', {s:s})`, '`hello world, $(s)!`', `hello world, abc!`],
178
+ [`print('hello world, $1!', [s])`, '`hello world, $(s)!`', `hello world, abc!`],
179
+ [`concat('Value: ', f, string(1 >= 0))`, '`Value: $(f)$(1 >= 0)`', 'Value: 1true'],
180
+ [`concat(s, f, string(1 >= 0))`, '`$(s)$(f)$(1 >= 0)`', 'abc1true'],
181
+ [
182
+ String.raw`'Value: '.concat('\\x', '$', 1, f, string(1 >= 0))`,
183
+ '`Value: \\\\x\\$1$(f)$(1 >= 0)`',
184
+ String.raw`Value: \x$11true`,
185
+ ],
186
+ [
187
+ `concat([1], a)`,
188
+ dedent`
189
+ flatten([[1], a])
190
+ // # 转换日志
191
+ // - W: 矩阵连接时结果可能不一致
192
+ // # 原始 math.js 表达式
193
+ // concat([1], a)
194
+ `,
195
+ [1, 1, 2, 3],
196
+ ],
197
+ ])('should migrate expression: %s', (f, t, r) => {
198
+ const migrated = migrateMathJs(f as ExpressionSource, false, s);
199
+ expect(migrated).toBe(t);
200
+ expect(e.evaluate(Expression(migrated), s)).toEqual(r);
76
201
  });
77
202
  });