@cloudpss/expression 0.6.0-alpha.1 → 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/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 +25 -3
- package/dist/migrate.js.map +1 -1
- package/dist/migrator/access.d.ts.map +1 -1
- package/dist/migrator/access.js +44 -24
- package/dist/migrator/access.js.map +1 -1
- package/dist/migrator/call.d.ts.map +1 -1
- package/dist/migrator/call.js +254 -217
- package/dist/migrator/call.js.map +1 -1
- package/dist/migrator/concat.d.ts.map +1 -1
- package/dist/migrator/concat.js +15 -2
- package/dist/migrator/concat.js.map +1 -1
- package/dist/migrator/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 +43 -29
- 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 +20 -3
- package/dist/migrator/to-type.js.map +1 -1
- package/dist/migrator/utils.d.ts +4 -0
- package/dist/migrator/utils.d.ts.map +1 -1
- package/dist/migrator/utils.js +25 -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 +7 -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 +30 -6
- package/src/migrator/access.ts +49 -32
- package/src/migrator/call.ts +246 -203
- package/src/migrator/concat.ts +15 -2
- package/src/migrator/interface.ts +3 -1
- package/src/migrator/node.ts +1 -1
- package/src/migrator/operator.ts +47 -33
- package/src/migrator/state.ts +2 -2
- package/src/migrator/symbol.ts +13 -0
- package/src/migrator/to-type.ts +22 -3
- package/src/migrator/utils.ts +29 -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 +202 -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/src/type.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { TypeName, VmValue, VmValueMap } from '@mirascript/mirascript';
|
|
2
2
|
import { lib } from '@mirascript/mirascript/subtle';
|
|
3
|
+
const { to_string, to_number, to_boolean } = lib;
|
|
3
4
|
|
|
4
5
|
/** 类型信息 */
|
|
5
6
|
export type TypeInfo = 'string' | 'number' | 'boolean';
|
|
@@ -21,14 +22,16 @@ export type TsTypeOf<T extends TypeInfo | LegacyType> = TypeMap[T];
|
|
|
21
22
|
export type LegacyType = 's' | 'f' | 'b';
|
|
22
23
|
|
|
23
24
|
/** 类型信息 */
|
|
24
|
-
export
|
|
25
|
-
|
|
25
|
+
export namespace TypeInfo {
|
|
26
|
+
/** 解析类型 */
|
|
27
|
+
export function parse(type: TypeInfo | LegacyType): TypeInfo {
|
|
26
28
|
if (type === 's' || type === 'string') return 'string';
|
|
27
29
|
if (type === 'f' || type === 'number') return 'number';
|
|
28
30
|
if (type === 'b' || type === 'boolean') return 'boolean';
|
|
29
31
|
throw new TypeError(`Invalid type '${String(type)}'`);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
+
}
|
|
33
|
+
/** 判断类型 */
|
|
34
|
+
export function is<T extends TypeInfo | LegacyType>(value: VmValue | undefined, type: T): value is TsTypeOf<T> {
|
|
32
35
|
switch (type) {
|
|
33
36
|
case 'b':
|
|
34
37
|
case 'boolean':
|
|
@@ -43,24 +46,42 @@ export const TypeInfo = {
|
|
|
43
46
|
(type) satisfies never;
|
|
44
47
|
return false;
|
|
45
48
|
}
|
|
46
|
-
}
|
|
47
|
-
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** 转换类型 */
|
|
52
|
+
export function to<T extends TypeInfo | LegacyType>(value: VmValue | undefined, type: T): TsTypeOf<T> {
|
|
48
53
|
/** 返回类型 */
|
|
49
54
|
type R = TsTypeOf<T>;
|
|
55
|
+
value ??= null;
|
|
50
56
|
if (!type) return value as R;
|
|
51
57
|
switch (type) {
|
|
52
58
|
case 'b':
|
|
53
59
|
case 'boolean':
|
|
54
|
-
return
|
|
60
|
+
return toBoolean(value) as R;
|
|
55
61
|
case 'f':
|
|
56
62
|
case 'number':
|
|
57
|
-
return
|
|
63
|
+
return toNumber(value) as R;
|
|
58
64
|
case 's':
|
|
59
65
|
case 'string':
|
|
60
|
-
return
|
|
66
|
+
return toString(value) as R;
|
|
61
67
|
default:
|
|
62
68
|
(type) satisfies never;
|
|
63
69
|
return value as R;
|
|
64
70
|
}
|
|
65
|
-
}
|
|
66
|
-
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** 转换为字符串 */
|
|
74
|
+
export function toString(value: VmValue | undefined): string {
|
|
75
|
+
return to_string(value ?? null);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** 转换为数字 */
|
|
79
|
+
export function toNumber(value: VmValue | undefined): number {
|
|
80
|
+
return to_number(value ?? null);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** 转换为布尔值 */
|
|
84
|
+
export function toBoolean(value: VmValue | undefined): boolean {
|
|
85
|
+
return to_boolean(value ?? null);
|
|
86
|
+
}
|
|
87
|
+
}
|
package/tests/analyze.ts
CHANGED
|
@@ -1,15 +1,49 @@
|
|
|
1
1
|
import { Evaluator, Expression, Scope } from '../dist/index.js';
|
|
2
2
|
|
|
3
3
|
const e = new Evaluator();
|
|
4
|
-
|
|
4
|
+
e.import({ w: 123 });
|
|
5
|
+
const s = new Scope({ sin: 12 }, false);
|
|
5
6
|
|
|
6
|
-
describe
|
|
7
|
+
describe('Analyze', () => {
|
|
7
8
|
it('simple', () => {
|
|
8
|
-
expect(e.analyze(Expression('
|
|
9
|
+
expect(e.analyze(Expression(' '), s)).toEqual([]);
|
|
10
|
+
expect(e.analyze(Expression('a + b + @c'), s)).toEqual([['a'], ['b'], ['@c']]);
|
|
11
|
+
});
|
|
12
|
+
it('bad', () => {
|
|
13
|
+
expect(e.analyze(Expression('a + '), s)).toEqual([]);
|
|
14
|
+
expect(e.analyze(Expression('a.b.'), s)).toEqual([]);
|
|
15
|
+
expect(() => e.analyze(Expression('a.b.'))).toThrow();
|
|
16
|
+
});
|
|
17
|
+
it('local', () => {
|
|
18
|
+
expect(e.analyze(Expression('let a = 12; a + nil'), s)).toEqual([]);
|
|
19
|
+
expect(e.analyze(Expression('let a = 12; a + nil'), s)).toEqual([]);
|
|
20
|
+
expect(e.analyze(Expression('let a = 12; a + b'), s)).toEqual([['b']]);
|
|
21
|
+
});
|
|
22
|
+
it('repeat', () => {
|
|
23
|
+
expect(e.analyze(Expression('a + b + a + a.b + b.c + a * a !. b'), s)).toEqual([
|
|
24
|
+
['a'],
|
|
25
|
+
['b'],
|
|
26
|
+
['a', 'b'],
|
|
27
|
+
['b', 'c'],
|
|
28
|
+
]);
|
|
29
|
+
});
|
|
30
|
+
it('prefixed', () => {
|
|
31
|
+
expect(e.analyze(Expression('@@a + $b + c. $$ + $'), s)).toEqual([['@@a'], ['$b'], ['c', '$$'], ['$']]);
|
|
32
|
+
});
|
|
33
|
+
it('unicode', () => {
|
|
34
|
+
expect(e.analyze(Expression('变量.属性 + 变量2[索引] + 函数()'), s)).toEqual([]);
|
|
9
35
|
});
|
|
10
36
|
it('access', () => {
|
|
11
|
-
expect(e.analyze(Expression('a.b[1]+b'), s)).toEqual([['a', 'b'], ['b']]);
|
|
12
|
-
expect(e.analyze(Expression('a.b["x"]+b'), s)).toEqual([['a', 'b'
|
|
13
|
-
expect(e.analyze(Expression('a.b[x]+b'), s)).toEqual([['a', 'b'], ['x'], ['b']]);
|
|
37
|
+
expect(e.analyze(Expression('a .b [1]+b'), s)).toEqual([['a', 'b'], ['b']]);
|
|
38
|
+
expect(e.analyze(Expression('a. b["x"]+b'), s)).toEqual([['a', 'b'], ['b']]);
|
|
39
|
+
expect(e.analyze(Expression('a.b[x] + b + c.12.3'), s)).toEqual([['a', 'b'], ['x'], ['b'], ['c', 12, 3]]);
|
|
40
|
+
});
|
|
41
|
+
it('with lib', () => {
|
|
42
|
+
const e0 = new Evaluator();
|
|
43
|
+
const exp = Expression('sin(x) + y::z.t()::cos() + w.123');
|
|
44
|
+
expect(e.analyze(exp, s)).toEqual([['sin'], ['x'], ['z', 't'], ['y']]);
|
|
45
|
+
expect(e0.analyze(exp, s)).toEqual([['sin'], ['x'], ['z', 't'], ['y'], ['w', 123]]);
|
|
46
|
+
expect(e.analyze(exp)).toEqual([['x'], ['z', 't'], ['y']]);
|
|
47
|
+
expect(e0.analyze(exp)).toEqual([['x'], ['z', 't'], ['y'], ['w', 123]]);
|
|
14
48
|
});
|
|
15
49
|
});
|
package/tests/compile.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Evaluator, Expression, Scope } from '../dist/index.js';
|
|
2
|
+
|
|
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
|
+
});
|
|
11
|
+
const s = new Scope({}, false);
|
|
12
|
+
|
|
13
|
+
describe('Evaluator.compile should work correctly', () => {
|
|
14
|
+
it('should eval const', () => {
|
|
15
|
+
const result = e.compile(Expression('12'), false);
|
|
16
|
+
expect(result(s, e)).toBe(12);
|
|
17
|
+
expect(e.evaluate(result, s)).toBe(12);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should eval exp', () => {
|
|
21
|
+
const result = e.compile(Expression('exp(2)'), false);
|
|
22
|
+
expect(result(s, e)).toBe(Math.exp(2));
|
|
23
|
+
expect(e.evaluate(result, s)).toBe(Math.exp(2));
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should eval error', () => {
|
|
27
|
+
const result = e.compile(Expression('exp+++'), false);
|
|
28
|
+
expect(result(s, e)).toBe(null);
|
|
29
|
+
expect(e.evaluate(result, s)).toBe(null);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('Evaluator.compile should convert result', () => {
|
|
34
|
+
it('should eval const', () => {
|
|
35
|
+
const result = e.compile(Expression('12', 'string'), false);
|
|
36
|
+
expect(result(s, e)).toBe('12');
|
|
37
|
+
expect(e.evaluate(result, s)).toBe('12');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should eval exp', () => {
|
|
41
|
+
const result = e.compile(Expression('exp(2)', 's'), false);
|
|
42
|
+
expect(result(s, e)).toBe(Math.exp(2).toString());
|
|
43
|
+
expect(e.evaluate(result, s)).toBe(Math.exp(2).toString());
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should not convert defaults', () => {
|
|
47
|
+
{
|
|
48
|
+
const result = e.compile(Expression('nil', 's'), false);
|
|
49
|
+
expect(result(s, e)).toBe(null);
|
|
50
|
+
expect(e.evaluate(result, s, 1)).toBe(1);
|
|
51
|
+
}
|
|
52
|
+
{
|
|
53
|
+
// syntax error
|
|
54
|
+
const result = e.compile(Expression('exp+++', 's'), false);
|
|
55
|
+
expect(result(s, e)).toBe(null);
|
|
56
|
+
expect(e.evaluate(result, s, 1)).toBe(1);
|
|
57
|
+
}
|
|
58
|
+
{
|
|
59
|
+
// runtime error
|
|
60
|
+
const result = e.compile(Expression('x() + 1', 's'), false);
|
|
61
|
+
expect(result(s, e)).toBe(null);
|
|
62
|
+
expect(e.evaluate(result, s, 1)).toBe(1);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
});
|
package/tests/condition.ts
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { Evaluator, type ExpressionSource, Scope } from '../dist/index.js';
|
|
2
2
|
|
|
3
|
-
const e = new Evaluator(
|
|
3
|
+
const e = new Evaluator({
|
|
4
|
+
logger: undefined,
|
|
5
|
+
});
|
|
6
|
+
const en = new Evaluator({
|
|
7
|
+
logger: {
|
|
8
|
+
warn: () => void 0,
|
|
9
|
+
error: () => void 0,
|
|
10
|
+
info: () => void 0,
|
|
11
|
+
debug: () => void 0,
|
|
12
|
+
},
|
|
13
|
+
});
|
|
4
14
|
const s = new Scope(undefined, false);
|
|
5
15
|
|
|
6
16
|
describe('Evaluate conditions', () => {
|
|
@@ -9,7 +19,6 @@ describe('Evaluate conditions', () => {
|
|
|
9
19
|
expect(e.evaluateCondition(false, s)).toBe(false);
|
|
10
20
|
});
|
|
11
21
|
it('can evaluate empty literals', () => {
|
|
12
|
-
// @ts-expect-error null
|
|
13
22
|
expect(e.evaluateCondition(null, s)).toBe(true);
|
|
14
23
|
expect(e.evaluateCondition(undefined, s)).toBe(true);
|
|
15
24
|
});
|
|
@@ -42,8 +51,7 @@ describe('Evaluate conditions', () => {
|
|
|
42
51
|
expect(e.evaluateCondition('12<=3' as ExpressionSource<boolean>, s)).toBe(false);
|
|
43
52
|
});
|
|
44
53
|
it('can return default on error', () => {
|
|
45
|
-
expect(
|
|
46
|
-
|
|
47
|
-
expect(e.evaluateCondition('12>>3' as ExpressionSource<boolean>, null, false)).toBe(false);
|
|
54
|
+
expect(en.evaluateCondition('12>>3' as ExpressionSource<boolean>, undefined, true)).toBe(true);
|
|
55
|
+
expect(en.evaluateCondition('12>>3' as ExpressionSource<boolean>, null, false)).toBe(false);
|
|
48
56
|
});
|
|
49
57
|
});
|
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', () => {
|