@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.
- package/dist/analyze.d.ts +6 -3
- package/dist/analyze.d.ts.map +1 -1
- package/dist/analyze.js +67 -33
- package/dist/analyze.js.map +1 -1
- package/dist/definitions/argument.d.ts +2 -10
- 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-decoration.d.ts +3 -3
- package/dist/definitions/parameter-decoration.d.ts.map +1 -1
- package/dist/definitions/parameter-decoration.js +0 -7
- package/dist/definitions/parameter-decoration.js.map +1 -1
- package/dist/definitions/parameter-group.d.ts +0 -4
- package/dist/definitions/parameter-group.d.ts.map +1 -1
- package/dist/definitions/parameter-group.js +5 -17
- package/dist/definitions/parameter-group.js.map +1 -1
- package/dist/definitions/parameter.d.ts +47 -40
- package/dist/definitions/parameter.d.ts.map +1 -1
- package/dist/definitions/parameter.js +9 -21
- package/dist/definitions/parameter.js.map +1 -1
- package/dist/definitions/utils.d.ts +19 -0
- package/dist/definitions/utils.d.ts.map +1 -0
- package/dist/definitions/utils.js +177 -0
- package/dist/definitions/utils.js.map +1 -0
- package/dist/definitions/variable.d.ts +0 -2
- package/dist/definitions/variable.d.ts.map +1 -1
- package/dist/definitions/variable.js +1 -5
- package/dist/definitions/variable.js.map +1 -1
- package/dist/definitions.d.ts +1 -0
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +1 -0
- 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 +4 -4
- 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 +145 -141
- package/dist/main.js.map +1 -1
- package/dist/migrate.d.ts +3 -2
- package/dist/migrate.d.ts.map +1 -1
- package/dist/migrate.js +12 -3
- package/dist/migrate.js.map +1 -1
- package/dist/migrator/access.d.ts.map +1 -1
- package/dist/migrator/access.js +22 -24
- package/dist/migrator/access.js.map +1 -1
- package/dist/migrator/call.d.ts.map +1 -1
- package/dist/migrator/call.js +235 -209
- package/dist/migrator/call.js.map +1 -1
- 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.js +1 -1
- package/dist/migrator/node.js.map +1 -1
- package/dist/migrator/operator.d.ts.map +1 -1
- package/dist/migrator/operator.js +19 -5
- package/dist/migrator/operator.js.map +1 -1
- package/dist/migrator/state.d.ts +2 -2
- package/dist/migrator/state.d.ts.map +1 -1
- package/dist/migrator/state.js +1 -2
- package/dist/migrator/state.js.map +1 -1
- package/dist/migrator/symbol.d.ts.map +1 -1
- package/dist/migrator/symbol.js +13 -0
- package/dist/migrator/symbol.js.map +1 -1
- package/dist/migrator/to-type.d.ts.map +1 -1
- package/dist/migrator/to-type.js +16 -0
- package/dist/migrator/to-type.js.map +1 -1
- package/dist/migrator/utils.d.ts +2 -0
- package/dist/migrator/utils.d.ts.map +1 -1
- package/dist/migrator/utils.js +18 -0
- 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 +25 -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 +13 -16
- package/dist/scope.d.ts.map +1 -1
- package/dist/scope.js +56 -49
- package/dist/scope.js.map +1 -1
- package/dist/type.d.ts +14 -5
- package/dist/type.d.ts.map +1 -1
- package/dist/type.js +35 -11
- package/dist/type.js.map +1 -1
- package/package.json +4 -4
- package/src/analyze.ts +77 -37
- package/src/definitions/argument.ts +2 -12
- package/src/definitions/constraint.ts +3 -3
- package/src/definitions/parameter-decoration.ts +3 -9
- package/src/definitions/parameter-group.ts +4 -19
- package/src/definitions/parameter.ts +62 -61
- package/src/definitions/utils.ts +175 -0
- package/src/definitions/variable.ts +1 -6
- package/src/definitions.ts +1 -0
- package/src/eval.ts +13 -26
- package/src/expression.ts +14 -6
- package/src/index.ts +3 -1
- package/src/interface.ts +35 -0
- package/src/main.ts +213 -194
- package/src/migrate.ts +15 -6
- package/src/migrator/access.ts +21 -26
- package/src/migrator/call.ts +225 -194
- package/src/migrator/interface.ts +3 -1
- package/src/migrator/node.ts +1 -1
- package/src/migrator/operator.ts +19 -5
- package/src/migrator/state.ts +2 -2
- package/src/migrator/symbol.ts +13 -0
- package/src/migrator/to-type.ts +16 -0
- package/src/migrator/utils.ts +21 -0
- package/src/parser.ts +27 -8
- package/src/re-exports.ts +28 -0
- package/src/scope.ts +75 -61
- package/src/type.ts +32 -11
- package/tests/analyze.ts +40 -6
- package/tests/compile.ts +65 -0
- package/tests/condition.ts +13 -5
- package/tests/definition.ts +205 -18
- package/tests/eval-complex.ts +7 -10
- package/tests/eval.ts +59 -12
- package/tests/import.ts +18 -4
- package/tests/main.ts +9 -0
- package/tests/migrate.ts +77 -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/jest.config.js +0 -3
- package/src/context.ts +0 -54
- package/tests/tsconfig.json +0 -3
- package/tsconfig.json +0 -3
package/tests/definition.ts
CHANGED
|
@@ -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.
|
|
6
|
-
expect(def.isParameter(
|
|
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.
|
|
11
|
-
expect(def.isParameterGroup(
|
|
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.
|
|
16
|
-
expect(def.isParameterDecoration(
|
|
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.
|
|
21
|
-
expect(def.isParameterDecorationGroup(
|
|
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.
|
|
26
|
-
expect(def.isVariable(
|
|
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.
|
|
31
|
-
expect(def.isChoice(
|
|
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
|
-
|
|
34
|
-
|
|
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
|
-
|
|
37
|
-
expect
|
|
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(
|
|
40
|
-
|
|
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
|
});
|
package/tests/eval-complex.ts
CHANGED
|
@@ -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('
|
|
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).
|
|
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)).
|
|
148
|
-
expect(e.evaluate(Expression('o.z'), s)).
|
|
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(
|
|
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
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
+
});
|
package/tests/migrate.ts
ADDED
|
@@ -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(
|
|
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(
|
|
26
|
-
expect(e.evaluate(Expression('toString'), s)).toBe(
|
|
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
|
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/jest.config.js
DELETED