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

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 (150) hide show
  1. package/dist/analyze.d.ts +6 -3
  2. package/dist/analyze.d.ts.map +1 -1
  3. package/dist/analyze.js +67 -33
  4. package/dist/analyze.js.map +1 -1
  5. package/dist/definitions/argument.d.ts +2 -10
  6. package/dist/definitions/argument.d.ts.map +1 -1
  7. package/dist/definitions/constraint.d.ts +2 -2
  8. package/dist/definitions/constraint.d.ts.map +1 -1
  9. package/dist/definitions/constraint.js +1 -1
  10. package/dist/definitions/constraint.js.map +1 -1
  11. package/dist/definitions/parameter-decoration.d.ts +3 -3
  12. package/dist/definitions/parameter-decoration.d.ts.map +1 -1
  13. package/dist/definitions/parameter-decoration.js +0 -7
  14. package/dist/definitions/parameter-decoration.js.map +1 -1
  15. package/dist/definitions/parameter-group.d.ts +0 -4
  16. package/dist/definitions/parameter-group.d.ts.map +1 -1
  17. package/dist/definitions/parameter-group.js +5 -17
  18. package/dist/definitions/parameter-group.js.map +1 -1
  19. package/dist/definitions/parameter.d.ts +47 -40
  20. package/dist/definitions/parameter.d.ts.map +1 -1
  21. package/dist/definitions/parameter.js +9 -21
  22. package/dist/definitions/parameter.js.map +1 -1
  23. package/dist/definitions/utils.d.ts +19 -0
  24. package/dist/definitions/utils.d.ts.map +1 -0
  25. package/dist/definitions/utils.js +177 -0
  26. package/dist/definitions/utils.js.map +1 -0
  27. package/dist/definitions/variable.d.ts +0 -2
  28. package/dist/definitions/variable.d.ts.map +1 -1
  29. package/dist/definitions/variable.js +1 -5
  30. package/dist/definitions/variable.js.map +1 -1
  31. package/dist/definitions.d.ts +1 -0
  32. package/dist/definitions.d.ts.map +1 -1
  33. package/dist/definitions.js +1 -0
  34. package/dist/definitions.js.map +1 -1
  35. package/dist/eval.d.ts +3 -5
  36. package/dist/eval.d.ts.map +1 -1
  37. package/dist/eval.js +12 -20
  38. package/dist/eval.js.map +1 -1
  39. package/dist/expression.d.ts +10 -4
  40. package/dist/expression.d.ts.map +1 -1
  41. package/dist/expression.js +4 -4
  42. package/dist/expression.js.map +1 -1
  43. package/dist/index.d.ts +3 -1
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +1 -0
  46. package/dist/index.js.map +1 -1
  47. package/dist/interface.d.ts +30 -0
  48. package/dist/interface.d.ts.map +1 -0
  49. package/dist/interface.js +6 -0
  50. package/dist/interface.js.map +1 -0
  51. package/dist/main.d.ts +41 -28
  52. package/dist/main.d.ts.map +1 -1
  53. package/dist/main.js +145 -141
  54. package/dist/main.js.map +1 -1
  55. package/dist/migrate.d.ts +3 -2
  56. package/dist/migrate.d.ts.map +1 -1
  57. package/dist/migrate.js +12 -3
  58. package/dist/migrate.js.map +1 -1
  59. package/dist/migrator/access.d.ts.map +1 -1
  60. package/dist/migrator/access.js +22 -24
  61. package/dist/migrator/access.js.map +1 -1
  62. package/dist/migrator/call.d.ts.map +1 -1
  63. package/dist/migrator/call.js +235 -209
  64. package/dist/migrator/call.js.map +1 -1
  65. package/dist/migrator/interface.d.ts +3 -1
  66. package/dist/migrator/interface.d.ts.map +1 -1
  67. package/dist/migrator/interface.js.map +1 -1
  68. package/dist/migrator/node.js +1 -1
  69. package/dist/migrator/node.js.map +1 -1
  70. package/dist/migrator/operator.d.ts.map +1 -1
  71. package/dist/migrator/operator.js +19 -5
  72. package/dist/migrator/operator.js.map +1 -1
  73. package/dist/migrator/state.d.ts +2 -2
  74. package/dist/migrator/state.d.ts.map +1 -1
  75. package/dist/migrator/state.js +1 -2
  76. package/dist/migrator/state.js.map +1 -1
  77. package/dist/migrator/symbol.d.ts.map +1 -1
  78. package/dist/migrator/symbol.js +13 -0
  79. package/dist/migrator/symbol.js.map +1 -1
  80. package/dist/migrator/to-type.d.ts.map +1 -1
  81. package/dist/migrator/to-type.js +16 -0
  82. package/dist/migrator/to-type.js.map +1 -1
  83. package/dist/migrator/utils.d.ts +2 -0
  84. package/dist/migrator/utils.d.ts.map +1 -1
  85. package/dist/migrator/utils.js +18 -0
  86. package/dist/migrator/utils.js.map +1 -1
  87. package/dist/parser.d.ts +2 -2
  88. package/dist/parser.d.ts.map +1 -1
  89. package/dist/parser.js +25 -8
  90. package/dist/parser.js.map +1 -1
  91. package/dist/re-exports.d.ts +4 -0
  92. package/dist/re-exports.d.ts.map +1 -0
  93. package/dist/re-exports.js +3 -0
  94. package/dist/re-exports.js.map +1 -0
  95. package/dist/scope.d.ts +13 -16
  96. package/dist/scope.d.ts.map +1 -1
  97. package/dist/scope.js +56 -49
  98. package/dist/scope.js.map +1 -1
  99. package/dist/type.d.ts +14 -5
  100. package/dist/type.d.ts.map +1 -1
  101. package/dist/type.js +35 -11
  102. package/dist/type.js.map +1 -1
  103. package/package.json +4 -4
  104. package/src/analyze.ts +77 -37
  105. package/src/definitions/argument.ts +2 -12
  106. package/src/definitions/constraint.ts +3 -3
  107. package/src/definitions/parameter-decoration.ts +3 -9
  108. package/src/definitions/parameter-group.ts +4 -19
  109. package/src/definitions/parameter.ts +62 -61
  110. package/src/definitions/utils.ts +175 -0
  111. package/src/definitions/variable.ts +1 -6
  112. package/src/definitions.ts +1 -0
  113. package/src/eval.ts +13 -26
  114. package/src/expression.ts +14 -6
  115. package/src/index.ts +3 -1
  116. package/src/interface.ts +35 -0
  117. package/src/main.ts +213 -194
  118. package/src/migrate.ts +15 -6
  119. package/src/migrator/access.ts +21 -26
  120. package/src/migrator/call.ts +225 -194
  121. package/src/migrator/interface.ts +3 -1
  122. package/src/migrator/node.ts +1 -1
  123. package/src/migrator/operator.ts +19 -5
  124. package/src/migrator/state.ts +2 -2
  125. package/src/migrator/symbol.ts +13 -0
  126. package/src/migrator/to-type.ts +16 -0
  127. package/src/migrator/utils.ts +21 -0
  128. package/src/parser.ts +27 -8
  129. package/src/re-exports.ts +28 -0
  130. package/src/scope.ts +75 -61
  131. package/src/type.ts +32 -11
  132. package/tests/analyze.ts +40 -6
  133. package/tests/compile.ts +65 -0
  134. package/tests/condition.ts +13 -5
  135. package/tests/definition.ts +205 -18
  136. package/tests/eval-complex.ts +7 -10
  137. package/tests/eval.ts +59 -12
  138. package/tests/import.ts +18 -4
  139. package/tests/main.ts +9 -0
  140. package/tests/migrate.ts +77 -0
  141. package/tests/scope.ts +3 -3
  142. package/tests/template.ts +36 -0
  143. package/dist/context.d.ts +0 -41
  144. package/dist/context.d.ts.map +0 -1
  145. package/dist/context.js +0 -18
  146. package/dist/context.js.map +0 -1
  147. package/jest.config.js +0 -3
  148. package/src/context.ts +0 -54
  149. package/tests/tsconfig.json +0 -3
  150. package/tsconfig.json +0 -3
@@ -1,42 +1,229 @@
1
+ import { jest } from '@jest/globals';
1
2
  import * as def from '../dist/definitions.js';
3
+ import { Expression } from '../dist/expression.js';
2
4
 
3
5
  describe('definitions', () => {
4
6
  it('should handle parameter', () => {
5
- expect(def.Parameter()).toBeDefined();
6
- expect(def.isParameter(def.Parameter())).toBe(true);
7
+ expect(def.isParameter(null)).toBe(false);
8
+ expect(def.isParameter(() => void 0)).toBe(false);
9
+ expect(def.isParameter({ key: '', name: '', description: '', type: 'real', value: 0 })).toBe(true);
10
+ expect(def.isParameter({ type: 'label' })).toBe(false);
11
+ expect(def.isParameter({ name: '', description: '', items: [] })).toBe(false);
7
12
  });
8
13
 
9
14
  it('should handle parameter group', () => {
10
- expect(def.ParameterGroup()).toBeDefined();
11
- expect(def.isParameterGroup(def.ParameterGroup())).toBe(true);
15
+ expect(def.isParameterGroup(null)).toBe(false);
16
+ expect(def.isParameterGroup(() => void 0)).toBe(false);
17
+ expect(def.isParameterGroup({ name: '', description: '', items: [] })).toBe(true);
18
+ expect(def.isParameterGroup({ items: [] })).toBe(false);
19
+ expect(def.isParameterGroup({ key: '', name: '', description: '', items: [] })).toBe(false);
12
20
  });
13
21
 
14
22
  it('should handle parameter decoration', () => {
15
- expect(def.ParameterDecoration()).toBeDefined();
16
- expect(def.isParameterDecoration(def.ParameterDecoration())).toBe(true);
23
+ expect(def.isParameterDecoration(null)).toBe(false);
24
+ expect(def.isParameterDecoration(() => void 0)).toBe(false);
25
+ expect(def.isParameterDecoration({ type: 'label' })).toBe(true);
26
+ expect(def.isParameterDecoration({ name: '', description: '', items: [] })).toBe(false);
27
+ expect(def.isParameterDecoration({ key: '', name: '', description: '', type: 'real', value: 0 })).toBe(false);
17
28
  });
18
29
 
19
30
  it('should handle parameter decoration group', () => {
20
- expect(def.ParameterDecorationGroup()).toBeDefined();
21
- expect(def.isParameterDecorationGroup(def.ParameterDecorationGroup())).toBe(true);
31
+ expect(def.isParameterDecorationGroup(null)).toBe(false);
32
+ expect(def.isParameterDecorationGroup(() => void 0)).toBe(false);
33
+ expect(def.isParameterDecorationGroup({ items: [] })).toBe(true);
34
+ expect(def.isParameterDecorationGroup({ name: '', description: '', items: [] })).toBe(false);
22
35
  });
23
36
 
24
37
  it('should handle variable', () => {
25
- expect(def.Variable()).toBeDefined();
26
- expect(def.isVariable(def.Variable())).toBe(true);
38
+ expect(def.isVariable(null)).toBe(false);
39
+ expect(def.isVariable(() => void 0)).toBe(false);
40
+ expect(def.isVariable({ key: '', value: 0 })).toBe(true);
41
+ expect(def.isVariable({ key: '', name: '', description: '', type: 'real', value: 0 })).toBe(false);
27
42
  });
28
43
 
29
44
  it('should handle choice', () => {
30
- expect(def.Choice()).toBeDefined();
31
- expect(def.isChoice(def.Choice())).toBe(true);
45
+ expect(def.isChoice(null)).toBe(false);
46
+ expect(def.isChoice(() => void 0)).toBe(false);
47
+ expect(def.isChoice({ name: '', description: '' })).toBe(true);
48
+ expect(def.isChoice({ key: null, name: '', description: '' })).toBe(true);
49
+ expect(def.isChoice({ key: '', name: '', description: '' })).toBe(true);
50
+ });
51
+
52
+ it('should handle constraint', () => {
53
+ expect(def.isConstraint(null)).toBe(false);
54
+ expect(def.isConstraint(() => void 0)).toBe(false);
55
+ expect(def.isConstraint({ name: '', description: '' })).toBe(false);
56
+ expect(def.isConstraint({ key: null, name: '', description: '' })).toBe(false);
57
+ expect(def.isConstraint({ key: '', name: '', description: '' })).toBe(false);
58
+ expect(def.isConstraint({ message: '' })).toBe(false);
59
+ expect(def.isConstraint({ condition: '' })).toBe(false);
60
+ expect(def.isConstraint({ message: '', condition: '' })).toBe(true);
61
+ expect(def.isConstraint({ message: '', condition: '', level: 'error' })).toBe(true);
62
+ expect(def.isConstraint({ message: '', condition: '', level: 'error', messageData: '' })).toBe(true);
63
+ expect(def.isConstraint({ message: '', condition: '', messageData: {} })).toBe(true);
64
+ expect(def.isConstraint({ message: '', condition: '', messageData: null })).toBe(true);
65
+ expect(def.isConstraint({ message: '', condition: '', messageData: undefined })).toBe(true);
66
+ expect(def.isConstraint({ message: '', condition: '', messageData: () => void 0 })).toBe(true);
67
+ expect(def.isConstraint({ message: '', condition: '', messageData: 1 })).toBe(false);
68
+ });
32
69
 
33
- expect(def.Choice('x').key).toBe('x');
34
- expect(def.isChoice(def.Choice('x'))).toBe(true);
70
+ it('should generate track id', () => {
71
+ const mockRandom = jest
72
+ .spyOn(Math, 'random')
73
+ .mockReturnValueOnce(0)
74
+ .mockReturnValueOnce(1 - 2 ** -53);
75
+ const id1 = def.generateTrackId();
76
+ const id2 = def.generateTrackId();
77
+ mockRandom.mockRestore();
78
+ expect(id1).toBe(1);
79
+ expect(id2).toBe(0x7fff_ffff);
80
+ });
35
81
 
36
- expect(def.Choice(0).key).toBe(0);
37
- expect(def.isChoice(def.Choice(0))).toBe(true);
82
+ it('should convert argument value', () => {
83
+ // @ts-expect-error 未知类型
84
+ expect(def.toArgumentValue(undefined, { type: 'xxx', key: '', name: '', description: '', value: 1 })).toBe(
85
+ null,
86
+ );
87
+ // @ts-expect-error 测试 undefined 输入
88
+ expect(def.toArgumentValue(undefined, { type: 'real', key: '', name: '', description: '', value: 1 })).toBe(0);
89
+ expect(def.toArgumentValue(null, { type: 'real', key: '', name: '', description: '', value: 1 })).toBe(0);
90
+ expect(def.toArgumentValue('12', { type: 'real', key: '', name: '', description: '', value: 1 })).toBe(12);
91
+ expect(def.toArgumentValue(null, { type: 'text', key: '', name: '', description: '', value: '1' })).toBe('');
92
+ expect(def.toArgumentValue(12, { type: 'text', key: '', name: '', description: '', value: '1' })).toBe('12');
93
+ expect(
94
+ def.toArgumentValue(null, { type: 'grouped', key: '', name: '', description: '', value: {}, items: [] }),
95
+ ).toBe(null);
38
96
 
39
- expect(def.Choice(false).key).toBe(false);
40
- expect(def.isChoice(def.Choice(false))).toBe(true);
97
+ expect(
98
+ def.toArgumentValue(null, { type: 'choice', key: '', name: '', description: '', value: 1, choices: [] }),
99
+ ).toBe(0);
100
+ expect(
101
+ def.toArgumentValue(null, {
102
+ type: 'choice',
103
+ key: '',
104
+ name: '',
105
+ description: '',
106
+ value: 1,
107
+ choices: [{ key: '0', name: '', description: '' }],
108
+ }),
109
+ ).toBe('0');
110
+ expect(
111
+ def.toArgumentValue(null, {
112
+ type: 'choice',
113
+ key: '',
114
+ name: '',
115
+ description: '',
116
+ value: 1,
117
+ choices: [
118
+ { key: '0', name: '', description: '' },
119
+ { key: 1, name: '', description: '' },
120
+ ],
121
+ }),
122
+ ).toBe('0');
123
+ expect(def.toArgumentValue(null, { type: 'logical', key: '', name: '', description: '', value: 1 })).toBe(0);
124
+ expect(
125
+ def.toArgumentValue(null, {
126
+ type: 'logical',
127
+ key: '',
128
+ name: '',
129
+ description: '',
130
+ value: false,
131
+ choices: [
132
+ { key: 0, name: '', description: '' },
133
+ { key: 1, name: '', description: '' },
134
+ ],
135
+ }),
136
+ ).toBe(0);
137
+ expect(
138
+ def.toArgumentValue(null, {
139
+ type: 'logical',
140
+ key: '',
141
+ name: '',
142
+ description: '',
143
+ value: true,
144
+ }),
145
+ ).toBe(false);
146
+ expect(
147
+ def.toArgumentValue(null, {
148
+ type: 'logical',
149
+ key: '',
150
+ name: '',
151
+ description: '',
152
+ value: 'true',
153
+ }),
154
+ ).toBe('');
155
+ expect(
156
+ def.toArgumentValue(null, {
157
+ type: 'logical',
158
+ key: '',
159
+ name: '',
160
+ description: '',
161
+ value: 'true',
162
+ choices: [
163
+ { key: '0', name: '', description: '' },
164
+ { key: '1', name: '', description: '' },
165
+ ],
166
+ }),
167
+ ).toBe('0');
168
+ expect(
169
+ def.toArgumentValue(null, {
170
+ type: 'multiSelect',
171
+ key: '',
172
+ name: '',
173
+ description: '',
174
+ value: [1],
175
+ choices: [],
176
+ }),
177
+ ).toStrictEqual([]);
178
+ expect(
179
+ def.toArgumentValue(1, {
180
+ type: 'multiSelect',
181
+ key: '',
182
+ name: '',
183
+ description: '',
184
+ value: [1],
185
+ choices: [],
186
+ }),
187
+ ).toStrictEqual([1]);
188
+ expect(
189
+ def.toArgumentValue('', {
190
+ type: 'multiSelect',
191
+ key: '',
192
+ name: '',
193
+ description: '',
194
+ value: [1],
195
+ choices: [],
196
+ }),
197
+ ).toStrictEqual([0]);
198
+ expect(
199
+ def.toArgumentValue('', {
200
+ type: 'multiSelect',
201
+ key: '',
202
+ name: '',
203
+ description: '',
204
+ value: [1],
205
+ choices: Expression(''),
206
+ }),
207
+ ).toStrictEqual(['']);
208
+ expect(
209
+ def.toArgumentValue(['', '1'], {
210
+ type: 'multiSelect',
211
+ key: '',
212
+ name: '',
213
+ description: '',
214
+ value: [1],
215
+ choices: [],
216
+ }),
217
+ ).toStrictEqual([0, 1]);
218
+ expect(
219
+ def.toArgumentValue(['', '1'], {
220
+ type: 'multiSelect',
221
+ key: '',
222
+ name: '',
223
+ description: '',
224
+ value: [1],
225
+ choices: Expression(''),
226
+ }),
227
+ ).toStrictEqual(['', '1']);
41
228
  });
42
229
  });
@@ -44,18 +44,15 @@ describe('Evaluator should work correctly', () => {
44
44
  const result = e.evaluate(Expression('a.0'), s);
45
45
  expect(result).toBe(36);
46
46
  });
47
- it('should eval deep with extern', () => {
47
+ it('should not eval deep with extern', () => {
48
48
  const s = new Scope(
49
49
  {
50
- a: new VmExtern([Expression('b.0 + d.0')]),
51
- b: new VmExtern([Expression('c.0 + d.0')]),
52
- c: new VmExtern([12]),
53
- d: new VmExtern([Expression('c.0')]),
50
+ a: new VmExtern([Expression('1')]),
54
51
  },
55
52
  false,
56
53
  );
57
- const result = e.evaluate(Expression('a.0'), s);
58
- expect(result).toBe(36);
54
+ const result = e.evaluate<VmExtern>(Expression('a.0'), s);
55
+ expect(result?.value).toStrictEqual(Expression('1'));
59
56
  });
60
57
  it('should eval deep with compiled expression', () => {
61
58
  const s = new Scope(
@@ -132,7 +129,7 @@ describe('Evaluator should work correctly', () => {
132
129
  a: new ArrayBuffer(0),
133
130
  v: new DataView(new ArrayBuffer(0)),
134
131
  test() {
135
- expect(this).toBeProxy();
132
+ expect(this).not.toBeProxy();
136
133
  expect(this.d).not.toBeProxy();
137
134
  expect(this.r).not.toBeProxy();
138
135
  // eslint-disable-next-line @typescript-eslint/unbound-method
@@ -144,7 +141,7 @@ describe('Evaluator should work correctly', () => {
144
141
  },
145
142
  });
146
143
  const s = new Scope({ o }, true);
147
- expect(e.evaluate(Expression('o.test()'), s)).toBe(3);
148
- expect(e.evaluate(Expression('o.z'), s)).toBe(3);
144
+ expect(e.evaluate<VmExtern>(Expression('o.test()'), s)?.value).toStrictEqual(Expression('o.y+o.x.p'));
145
+ expect(e.evaluate<VmExtern>(Expression('o.z'), s)?.value).toStrictEqual(Expression('o.y+o.x.p'));
149
146
  });
150
147
  });
package/tests/eval.ts CHANGED
@@ -1,9 +1,17 @@
1
- import { Evaluator, Expression, Scope } from '../dist/index.js';
1
+ import { Evaluator, Expression, Scope, VmFunction } from '../dist/index.js';
2
2
 
3
- const e = new Evaluator();
3
+ const e = new Evaluator({
4
+ logger: {
5
+ warn: () => void 0,
6
+ error: () => void 0,
7
+ info: () => void 0,
8
+ debug: () => void 0,
9
+ },
10
+ });
4
11
  const s = new Scope({}, false);
12
+ const st = new Scope(null, true);
5
13
 
6
- describe('Evaluator should work correctly', () => {
14
+ describe('Evaluator.evaluate should work correctly', () => {
7
15
  it('should eval const', () => {
8
16
  const result = e.evaluate(Expression('12'), s);
9
17
  expect(result).toBe(12);
@@ -16,11 +24,39 @@ describe('Evaluator should work correctly', () => {
16
24
 
17
25
  it('should eval error', () => {
18
26
  const result = e.evaluate(Expression('exp+++'), s);
19
- expect(result).toBe(undefined);
27
+ expect(result).toBe(null);
28
+ });
29
+
30
+ it('should eval null', () => {
31
+ const result = e.evaluate(null, s);
32
+ expect(result).toBe(null);
33
+ });
34
+ it('should eval undefined', () => {
35
+ const result = e.evaluate(undefined, s);
36
+ expect(result).toBe(null);
37
+ });
38
+ it('should eval value', () => {
39
+ {
40
+ const result = e.evaluate(1, s);
41
+ expect(result).toBe(1);
42
+ }
43
+ {
44
+ const result = e.evaluate('', s);
45
+ expect(result).toBe('');
46
+ }
47
+ {
48
+ const result = e.evaluate(false, s);
49
+ expect(result).toBe(false);
50
+ }
51
+ });
52
+ it('should eval vm function', () => {
53
+ const f = VmFunction(() => 1);
54
+ const result = e.evaluate(f, s);
55
+ expect(result).toBe(f);
20
56
  });
21
57
  });
22
58
 
23
- describe('Evaluator should convert result', () => {
59
+ describe('Evaluator.evaluate should convert result', () => {
24
60
  it('should eval const', () => {
25
61
  const result = e.evaluate(Expression('12', 'string'), s);
26
62
  expect(result).toBe('12');
@@ -31,12 +67,23 @@ describe('Evaluator should convert result', () => {
31
67
  expect(result).toBe(Math.exp(2).toString());
32
68
  });
33
69
 
34
- it('should not convert when error', () => {
35
- // syntax error
36
- const result = e.evaluate(Expression('exp+++', 's'), s, 1);
37
- expect(result).toBe(1);
38
- // runtime error
39
- const result2 = e.evaluate(Expression('x() + 1', 's'), s, 1);
40
- expect(result2).toBe(1);
70
+ it('should not convert defaults', () => {
71
+ {
72
+ const result = e.evaluate(Expression('nil', 's'), s, 1);
73
+ expect(result).toBe(1);
74
+ }
75
+ {
76
+ // syntax error
77
+ expect(() => e.evaluate(Expression('exp+++', 's'), undefined, 1)).toThrow();
78
+ }
79
+ {
80
+ // syntax error cached
81
+ expect(() => e.evaluate(Expression('exp+++', 's'), st)).toThrow();
82
+ }
83
+ {
84
+ // runtime error
85
+ const result = e.evaluate(Expression('x() + 1', 's'), s, 1);
86
+ expect(result).toBe(1);
87
+ }
41
88
  });
42
89
  });
package/tests/import.ts CHANGED
@@ -2,8 +2,22 @@ import { VmFunction } from '@mirascript/mirascript';
2
2
  import { Evaluator, Expression, Scope } from '../dist/index.js';
3
3
  import { lib } from '@mirascript/mirascript/subtle';
4
4
 
5
- const e = new Evaluator();
6
- const e2 = new Evaluator();
5
+ const e = new Evaluator({
6
+ logger: {
7
+ warn: () => void 0,
8
+ error: () => void 0,
9
+ info: () => void 0,
10
+ debug: () => void 0,
11
+ },
12
+ });
13
+ const e2 = new Evaluator({
14
+ logger: {
15
+ warn: () => void 0,
16
+ error: () => void 0,
17
+ info: () => void 0,
18
+ debug: () => void 0,
19
+ },
20
+ });
7
21
  const s = new Scope(undefined, false);
8
22
 
9
23
  describe('Import should work correctly', () => {
@@ -11,7 +25,7 @@ describe('Import should work correctly', () => {
11
25
  e.import({ add: (x: number, y: number) => x + y });
12
26
  expect(e.evaluate(Expression('add(1,2)'), s)).toBe(3);
13
27
  expect(e.evaluate(Expression('add::type()'), s)).toBe('extern');
14
- expect(e2.evaluate(Expression('add(1,2)'), s)).toBe(undefined);
28
+ expect(e2.evaluate(Expression('add(1,2)'), s)).toBe(null);
15
29
  expect(e2.evaluate(Expression('add::type()'), s)).toBe('nil');
16
30
  });
17
31
 
@@ -19,7 +33,7 @@ describe('Import should work correctly', () => {
19
33
  e.import({ add: (x: number, y: number) => x + y });
20
34
  expect(e.evaluate(Expression('add(1,2)'), s)).toBe(3);
21
35
  e.import({ add: undefined });
22
- expect(e.evaluate(Expression('add(1,2)'), s)).toBe(undefined);
36
+ expect(e.evaluate(Expression('add(1,2)'), s)).toBe(null);
23
37
  });
24
38
 
25
39
  it('can replace modules', () => {
package/tests/main.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { Evaluator } from '../dist/main.js';
2
+
3
+ describe('Evaluator', () => {
4
+ it('should have logger', () => {
5
+ expect(new Evaluator().logger).toBeTruthy();
6
+ expect(new Evaluator(null).logger).toBeTruthy();
7
+ expect(new Evaluator({}).logger).toBeTruthy();
8
+ });
9
+ });
@@ -0,0 +1,77 @@
1
+ import { migrateMathJs } from '@cloudpss/expression/migrate';
2
+ import type { ExpressionSource } from '../dist/expression.js';
3
+ import { Scope } from '../dist/scope.js';
4
+
5
+ const s = new Scope({
6
+ a: [1, 2, 3],
7
+ m: [
8
+ [1, 2],
9
+ [3, 4],
10
+ ],
11
+ f: 1,
12
+ s: 's',
13
+ b: false,
14
+ });
15
+
16
+ describe('migrate', () => {
17
+ it('should migrate constant expressions', () => {
18
+ const m = (e: string) => migrateMathJs(e as ExpressionSource, false, undefined);
19
+ expect(m('')).toBe('');
20
+ expect(m(' ')).toBe('');
21
+ expect(m('undefined')).toBe('');
22
+ expect(m('null')).toBe('nil');
23
+ expect(m('true')).toBe('true');
24
+ expect(m('false')).toBe('false');
25
+ expect(m('123')).toBe('123');
26
+ expect(m('-123.45e+6')).toBe('-123.45e+6');
27
+ expect(m('+123.45e-6')).toBe('+123.45e-6');
28
+ expect(m('.45e-6')).toBe('4.5e-7');
29
+ });
30
+
31
+ 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);
76
+ });
77
+ });
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(undefined);
13
+ expect(e.evaluate(Expression('b'), s)).toBe(null);
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(undefined);
26
- expect(e.evaluate(Expression('toString'), s)).toBe(undefined);
25
+ expect(e.evaluate(Expression('__proto__'), s)).toBe(null);
26
+ expect(e.evaluate(Expression('toString'), s)).toBe(null);
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
@@ -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
@@ -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/jest.config.js DELETED
@@ -1,3 +0,0 @@
1
- import { config } from '../jest.config.js';
2
-
3
- export default { ...config };