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