@cloudpss/expression 0.6.0-alpha.9 → 0.6.0-beta.1

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 (157) hide show
  1. package/dist/analyze.d.ts +6 -3
  2. package/dist/analyze.d.ts.map +1 -1
  3. package/dist/analyze.js +13 -33
  4. package/dist/analyze.js.map +1 -1
  5. package/dist/definitions/argument.d.ts +3 -11
  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-group.js +4 -4
  12. package/dist/definitions/parameter-group.js.map +1 -1
  13. package/dist/definitions/parameter.d.ts +22 -14
  14. package/dist/definitions/parameter.d.ts.map +1 -1
  15. package/dist/definitions/parameter.js +10 -1
  16. package/dist/definitions/parameter.js.map +1 -1
  17. package/dist/definitions/utils.d.ts +28 -0
  18. package/dist/definitions/utils.d.ts.map +1 -0
  19. package/dist/definitions/utils.js +272 -0
  20. package/dist/definitions/utils.js.map +1 -0
  21. package/dist/definitions/variable.js +1 -1
  22. package/dist/definitions/variable.js.map +1 -1
  23. package/dist/definitions.d.ts +1 -2
  24. package/dist/definitions.d.ts.map +1 -1
  25. package/dist/definitions.js +1 -1
  26. package/dist/definitions.js.map +1 -1
  27. package/dist/eval.d.ts +3 -5
  28. package/dist/eval.d.ts.map +1 -1
  29. package/dist/eval.js +12 -20
  30. package/dist/eval.js.map +1 -1
  31. package/dist/expression.d.ts +10 -4
  32. package/dist/expression.d.ts.map +1 -1
  33. package/dist/expression.js +6 -6
  34. package/dist/expression.js.map +1 -1
  35. package/dist/index.d.ts +3 -1
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +1 -0
  38. package/dist/index.js.map +1 -1
  39. package/dist/interface.d.ts +30 -0
  40. package/dist/interface.d.ts.map +1 -0
  41. package/dist/interface.js +6 -0
  42. package/dist/interface.js.map +1 -0
  43. package/dist/main.d.ts +41 -28
  44. package/dist/main.d.ts.map +1 -1
  45. package/dist/main.js +165 -149
  46. package/dist/main.js.map +1 -1
  47. package/dist/migrate.d.ts +1 -1
  48. package/dist/migrate.d.ts.map +1 -1
  49. package/dist/migrate.js +25 -4
  50. package/dist/migrate.js.map +1 -1
  51. package/dist/migrator/access.d.ts.map +1 -1
  52. package/dist/migrator/access.js +64 -29
  53. package/dist/migrator/access.js.map +1 -1
  54. package/dist/migrator/call.d.ts.map +1 -1
  55. package/dist/migrator/call.js +298 -201
  56. package/dist/migrator/call.js.map +1 -1
  57. package/dist/migrator/concat.d.ts.map +1 -1
  58. package/dist/migrator/concat.js +15 -2
  59. package/dist/migrator/concat.js.map +1 -1
  60. package/dist/migrator/function.d.ts +6 -0
  61. package/dist/migrator/function.d.ts.map +1 -0
  62. package/dist/migrator/function.js +25 -0
  63. package/dist/migrator/function.js.map +1 -0
  64. package/dist/migrator/interface.d.ts +3 -1
  65. package/dist/migrator/interface.d.ts.map +1 -1
  66. package/dist/migrator/interface.js.map +1 -1
  67. package/dist/migrator/node.d.ts.map +1 -1
  68. package/dist/migrator/node.js +55 -7
  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 +107 -60
  72. package/dist/migrator/operator.js.map +1 -1
  73. package/dist/migrator/serialize.d.ts +4 -0
  74. package/dist/migrator/serialize.d.ts.map +1 -0
  75. package/dist/migrator/serialize.js +21 -0
  76. package/dist/migrator/serialize.js.map +1 -0
  77. package/dist/migrator/special.d.ts.map +1 -1
  78. package/dist/migrator/special.js +31 -0
  79. package/dist/migrator/special.js.map +1 -1
  80. package/dist/migrator/state.d.ts +4 -4
  81. package/dist/migrator/state.d.ts.map +1 -1
  82. package/dist/migrator/state.js +29 -31
  83. package/dist/migrator/state.js.map +1 -1
  84. package/dist/migrator/symbol.d.ts.map +1 -1
  85. package/dist/migrator/symbol.js +34 -12
  86. package/dist/migrator/symbol.js.map +1 -1
  87. package/dist/migrator/to-type.d.ts.map +1 -1
  88. package/dist/migrator/to-type.js +21 -4
  89. package/dist/migrator/to-type.js.map +1 -1
  90. package/dist/migrator/utils.d.ts +6 -0
  91. package/dist/migrator/utils.d.ts.map +1 -1
  92. package/dist/migrator/utils.js +49 -1
  93. package/dist/migrator/utils.js.map +1 -1
  94. package/dist/parser.d.ts +2 -2
  95. package/dist/parser.d.ts.map +1 -1
  96. package/dist/parser.js +27 -8
  97. package/dist/parser.js.map +1 -1
  98. package/dist/re-exports.d.ts +4 -0
  99. package/dist/re-exports.d.ts.map +1 -0
  100. package/dist/re-exports.js +3 -0
  101. package/dist/re-exports.js.map +1 -0
  102. package/dist/scope.d.ts +16 -17
  103. package/dist/scope.d.ts.map +1 -1
  104. package/dist/scope.js +84 -53
  105. package/dist/scope.js.map +1 -1
  106. package/dist/type.d.ts +22 -10
  107. package/dist/type.d.ts.map +1 -1
  108. package/dist/type.js +21 -24
  109. package/dist/type.js.map +1 -1
  110. package/package.json +8 -5
  111. package/src/analyze.ts +20 -39
  112. package/src/definitions/argument.ts +3 -13
  113. package/src/definitions/constraint.ts +3 -3
  114. package/src/definitions/parameter-group.ts +4 -4
  115. package/src/definitions/parameter.ts +47 -24
  116. package/src/definitions/utils.ts +288 -0
  117. package/src/definitions/variable.ts +1 -1
  118. package/src/definitions.ts +1 -28
  119. package/src/eval.ts +16 -25
  120. package/src/expression.ts +16 -8
  121. package/src/index.ts +3 -1
  122. package/src/interface.ts +35 -0
  123. package/src/main.ts +232 -200
  124. package/src/migrate.ts +27 -4
  125. package/src/migrator/access.ts +67 -37
  126. package/src/migrator/call.ts +287 -190
  127. package/src/migrator/concat.ts +15 -2
  128. package/src/migrator/function.ts +27 -0
  129. package/src/migrator/interface.ts +3 -1
  130. package/src/migrator/node.ts +56 -6
  131. package/src/migrator/operator.ts +110 -64
  132. package/src/migrator/serialize.ts +21 -0
  133. package/src/migrator/special.ts +31 -0
  134. package/src/migrator/state.ts +31 -34
  135. package/src/migrator/symbol.ts +33 -12
  136. package/src/migrator/to-type.ts +23 -4
  137. package/src/migrator/utils.ts +49 -1
  138. package/src/parser.ts +33 -8
  139. package/src/re-exports.ts +47 -0
  140. package/src/scope.ts +98 -62
  141. package/src/type.ts +40 -25
  142. package/tests/analyze.ts +45 -6
  143. package/tests/compile.ts +65 -0
  144. package/tests/condition.ts +33 -17
  145. package/tests/definition.ts +237 -18
  146. package/tests/eval-complex.ts +19 -11
  147. package/tests/eval.ts +59 -12
  148. package/tests/import.ts +21 -7
  149. package/tests/main.ts +58 -0
  150. package/tests/migrate.ts +317 -0
  151. package/tests/scope.ts +3 -3
  152. package/tests/template.ts +36 -0
  153. package/dist/context.d.ts +0 -41
  154. package/dist/context.d.ts.map +0 -1
  155. package/dist/context.js +0 -18
  156. package/dist/context.js.map +0 -1
  157. package/src/context.ts +0 -54
@@ -1,42 +1,261 @@
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
+ expect(def.toArgumentValue(undefined, { type: 'real', key: '', name: '', description: '', value: 1 })).toBe(
88
+ null,
89
+ );
90
+ expect(def.toArgumentValue(null, { type: 'real', key: '', name: '', description: '', value: 1 })).toBe(null);
91
+ expect(def.toArgumentValue('12', { type: 'real', key: '', name: '', description: '', value: 1 })).toBe(12);
92
+ expect(def.toArgumentValue(null, { type: 'text', key: '', name: '', description: '', value: '1' })).toBe('');
93
+ expect(def.toArgumentValue(12, { type: 'text', key: '', name: '', description: '', value: '1' })).toBe('12');
94
+ expect(
95
+ def.toArgumentValue(null, { type: 'grouped', key: '', name: '', description: '', value: {}, items: [] }),
96
+ ).toBe(null);
38
97
 
39
- expect(def.Choice(false).key).toBe(false);
40
- expect(def.isChoice(def.Choice(false))).toBe(true);
98
+ expect(
99
+ def.toArgumentValue(null, { type: 'choice', key: '', name: '', description: '', value: 1, choices: [] }),
100
+ ).toBe(null);
101
+ expect(
102
+ def.toArgumentValue(null, {
103
+ type: 'choice',
104
+ key: '',
105
+ name: '',
106
+ description: '',
107
+ value: 1,
108
+ choices: [{ key: '0', name: '', description: '' }],
109
+ }),
110
+ ).toBe('');
111
+ expect(
112
+ def.toArgumentValue(null, {
113
+ type: 'choice',
114
+ key: '',
115
+ name: '',
116
+ description: '',
117
+ value: 1,
118
+ choices: [
119
+ { key: '0', name: '', description: '' },
120
+ { key: 1, name: '', description: '' },
121
+ ],
122
+ }),
123
+ ).toBe('');
124
+ expect(def.toArgumentValue(null, { type: 'logical', key: '', name: '', description: '', value: 1 })).toBe(null);
125
+ expect(def.toArgumentValue('0', { type: 'logical', key: '', name: '', description: '', value: 1 })).toBe(0);
126
+ expect(
127
+ def.toArgumentValue(null, {
128
+ type: 'logical',
129
+ key: '',
130
+ name: '',
131
+ description: '',
132
+ value: false,
133
+ choices: [
134
+ { key: 0, name: '', description: '' },
135
+ { key: 1, name: '', description: '' },
136
+ ],
137
+ }),
138
+ ).toBe(null);
139
+ expect(
140
+ def.toArgumentValue(null, {
141
+ type: 'logical',
142
+ key: '',
143
+ name: '',
144
+ description: '',
145
+ value: true,
146
+ }),
147
+ ).toBe(null);
148
+ expect(
149
+ def.toArgumentValue(null, {
150
+ type: 'logical',
151
+ key: '',
152
+ name: '',
153
+ description: '',
154
+ value: 'true',
155
+ }),
156
+ ).toBe('');
157
+ expect(
158
+ def.toArgumentValue(null, {
159
+ type: 'logical',
160
+ key: '',
161
+ name: '',
162
+ description: '',
163
+ value: 'true',
164
+ choices: [
165
+ { key: '0', name: '', description: '' },
166
+ { key: '1', name: '', description: '' },
167
+ ],
168
+ }),
169
+ ).toBe('');
170
+ expect(
171
+ def.toArgumentValue(null, {
172
+ type: 'multiSelect',
173
+ key: '',
174
+ name: '',
175
+ description: '',
176
+ value: [1],
177
+ choices: [],
178
+ }),
179
+ ).toStrictEqual([]);
180
+ expect(
181
+ def.toArgumentValue(1, {
182
+ type: 'multiSelect',
183
+ key: '',
184
+ name: '',
185
+ description: '',
186
+ value: [1],
187
+ choices: [],
188
+ }),
189
+ ).toStrictEqual([1]);
190
+ expect(
191
+ def.toArgumentValue('', {
192
+ type: 'multiSelect',
193
+ key: '',
194
+ name: '',
195
+ description: '',
196
+ value: [1],
197
+ choices: [],
198
+ }),
199
+ ).toStrictEqual(null);
200
+ expect(
201
+ def.toArgumentValue('', {
202
+ type: 'multiSelect',
203
+ key: '',
204
+ name: '',
205
+ description: '',
206
+ value: [1],
207
+ choices: Expression(''),
208
+ }),
209
+ ).toStrictEqual(null);
210
+ expect(
211
+ def.toArgumentValue(['', '1', ' 2 '], {
212
+ type: 'multiSelect',
213
+ key: '',
214
+ name: '',
215
+ description: '',
216
+ value: [1],
217
+ choices: [],
218
+ }),
219
+ ).toStrictEqual(null);
220
+ expect(
221
+ def.toArgumentValue(['0', '1', ' 2 '], {
222
+ type: 'multiSelect',
223
+ key: '',
224
+ name: '',
225
+ description: '',
226
+ value: [1],
227
+ choices: [],
228
+ }),
229
+ ).toStrictEqual([0, 1, 2]);
230
+ expect(
231
+ def.toArgumentValue(['0', '1', ' 2 '], {
232
+ type: 'multiSelect',
233
+ key: '',
234
+ name: '',
235
+ description: '',
236
+ value: [],
237
+ choices: [],
238
+ }),
239
+ ).toStrictEqual([0, 1, 2]);
240
+ expect(
241
+ def.toArgumentValue([1, 2], {
242
+ type: 'multiSelect',
243
+ key: '',
244
+ name: '',
245
+ description: '',
246
+ value: ['1'],
247
+ choices: [],
248
+ }),
249
+ ).toStrictEqual(['1', '2']);
250
+ expect(
251
+ def.toArgumentValue(['', '1', ' 2 '], {
252
+ type: 'multiSelect',
253
+ key: '',
254
+ name: '',
255
+ description: '',
256
+ value: [1],
257
+ choices: Expression(''),
258
+ }),
259
+ ).toStrictEqual(null);
41
260
  });
42
261
  });
@@ -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(
@@ -105,7 +102,7 @@ describe('Evaluator should work correctly', () => {
105
102
  const result = e.evaluate(Expression('a + a + a + a + a + a + a + a + a + a'), s);
106
103
  expect(result).toBe(10);
107
104
  });
108
- it('should report loop', () => {
105
+ it('should report loop by scope', () => {
109
106
  const s = new Scope(
110
107
  {
111
108
  a: Expression('b'),
@@ -114,6 +111,17 @@ describe('Evaluator should work correctly', () => {
114
111
  },
115
112
  true,
116
113
  );
114
+ expect(() => e.evaluate(Expression('a'), s)).toThrow(/Execution recursion exceeds limit/);
115
+ });
116
+ it('should report loop by mirascript', () => {
117
+ const s = new Scope(
118
+ {
119
+ a: Expression('fn x{b}x()'),
120
+ b: Expression('fn x{c}x()'),
121
+ c: Expression('fn x{a}x()'),
122
+ },
123
+ true,
124
+ );
117
125
  expect(() => e.evaluate(Expression('a'), s)).toThrow(/Maximum call depth exceeded/);
118
126
  });
119
127
 
@@ -132,7 +140,7 @@ describe('Evaluator should work correctly', () => {
132
140
  a: new ArrayBuffer(0),
133
141
  v: new DataView(new ArrayBuffer(0)),
134
142
  test() {
135
- expect(this).toBeProxy();
143
+ expect(this).not.toBeProxy();
136
144
  expect(this.d).not.toBeProxy();
137
145
  expect(this.r).not.toBeProxy();
138
146
  // eslint-disable-next-line @typescript-eslint/unbound-method
@@ -144,7 +152,7 @@ describe('Evaluator should work correctly', () => {
144
152
  },
145
153
  });
146
154
  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);
155
+ expect(e.evaluate<VmExtern>(Expression('o.test()'), s)?.value).toStrictEqual(Expression('o.y+o.x.p'));
156
+ expect(e.evaluate<VmExtern>(Expression('o.z'), s)?.value).toStrictEqual(Expression('o.y+o.x.p'));
149
157
  });
150
158
  });
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
@@ -1,9 +1,23 @@
1
1
  import { VmFunction } from '@mirascript/mirascript';
2
2
  import { Evaluator, Expression, Scope } from '../dist/index.js';
3
- import { lib } from '@mirascript/mirascript/subtle';
3
+ import { convert, 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,21 +25,21 @@ 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);
15
- expect(e2.evaluate(Expression('add::type()'), s)).toBe('nil');
28
+ expect(e2.evaluate(Expression('add(1,2)'), s)).toBe(null);
29
+ expect(e2.evaluate(Expression('add::type()'), s)).toBe(null);
16
30
  });
17
31
 
18
32
  it('can remove modules', () => {
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', () => {
26
40
  e.import({ add: (x: number, y: number) => x + y });
27
41
  expect(e.evaluate(Expression('add::type()'), s)).toBe('extern');
28
- e.import({ add: VmFunction((x, y) => lib.to_number(x) + lib.to_number(y)) });
42
+ e.import({ add: VmFunction((x, y) => convert.toNumber(x, 0) + convert.toNumber(y, 0)) });
29
43
  expect(e.evaluate(Expression('add::type()'), s)).toBe('function');
30
44
  });
31
45
  });
package/tests/main.ts ADDED
@@ -0,0 +1,58 @@
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
+
10
+ describe('can evaluate choices', () => {
11
+ const e = new Evaluator();
12
+
13
+ it('on logical type', () => {
14
+ const c0 = e.evaluateChoices({ type: 'logical', value: null as never }, null);
15
+ expect(c0.length).toBe(2);
16
+ expect(c0[0].key).toBe(false);
17
+ expect(c0[1].key).toBe(true);
18
+
19
+ const c1 = e.evaluateChoices(
20
+ {
21
+ type: 'logical',
22
+ // @ts-expect-error Incomplete choice definition
23
+ choices: [{}, { key: true, name: 'Yes' }],
24
+ value: null as never,
25
+ },
26
+ null,
27
+ );
28
+ expect(c1.length).toBe(2);
29
+ expect(c1[0].key).toBe(false);
30
+ expect(c1[1].key).toBe(true);
31
+ expect(c1[0].name).toBe('');
32
+ expect(c1[1].name).toBe('Yes');
33
+
34
+ const c2 = e.evaluateChoices(
35
+ {
36
+ type: 'logical',
37
+ // @ts-expect-error Incomplete choice definition
38
+ choices: [{ key: 0 }, { key: '1' }, { key: 2 }],
39
+ value: null as never,
40
+ },
41
+ null,
42
+ );
43
+ expect(c2.length).toBe(2);
44
+ expect(c2[0].key).toBe(0);
45
+ expect(c2[1].key).toBe(1);
46
+
47
+ const c3 = e.evaluateChoices({ type: 'logical', choices: [], value: 0 }, null);
48
+ expect(c3.length).toBe(2);
49
+ expect(c3[0].key).toBe(0);
50
+ expect(c3[1].key).toBe(1);
51
+
52
+ const c4 = e.evaluateChoices({ type: 'logical', value: 'x' }, null);
53
+ expect(c4.length).toBe(2);
54
+ expect(c4[0].key).toBe('0');
55
+ expect(c4[1].key).toBe('1');
56
+ });
57
+ });
58
+ });