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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/dist/analyze.d.ts +6 -3
  2. package/dist/analyze.d.ts.map +1 -1
  3. package/dist/analyze.js +67 -33
  4. package/dist/analyze.js.map +1 -1
  5. package/dist/definitions/argument.d.ts +2 -10
  6. package/dist/definitions/argument.d.ts.map +1 -1
  7. package/dist/definitions/constraint.d.ts +2 -2
  8. package/dist/definitions/constraint.d.ts.map +1 -1
  9. package/dist/definitions/constraint.js +1 -1
  10. package/dist/definitions/constraint.js.map +1 -1
  11. package/dist/definitions/parameter-decoration.d.ts +3 -3
  12. package/dist/definitions/parameter-decoration.d.ts.map +1 -1
  13. package/dist/definitions/parameter-decoration.js +0 -7
  14. package/dist/definitions/parameter-decoration.js.map +1 -1
  15. package/dist/definitions/parameter-group.d.ts +0 -4
  16. package/dist/definitions/parameter-group.d.ts.map +1 -1
  17. package/dist/definitions/parameter-group.js +5 -17
  18. package/dist/definitions/parameter-group.js.map +1 -1
  19. package/dist/definitions/parameter.d.ts +47 -40
  20. package/dist/definitions/parameter.d.ts.map +1 -1
  21. package/dist/definitions/parameter.js +9 -21
  22. package/dist/definitions/parameter.js.map +1 -1
  23. package/dist/definitions/utils.d.ts +19 -0
  24. package/dist/definitions/utils.d.ts.map +1 -0
  25. package/dist/definitions/utils.js +177 -0
  26. package/dist/definitions/utils.js.map +1 -0
  27. package/dist/definitions/variable.d.ts +0 -2
  28. package/dist/definitions/variable.d.ts.map +1 -1
  29. package/dist/definitions/variable.js +1 -5
  30. package/dist/definitions/variable.js.map +1 -1
  31. package/dist/definitions.d.ts +1 -0
  32. package/dist/definitions.d.ts.map +1 -1
  33. package/dist/definitions.js +1 -0
  34. package/dist/definitions.js.map +1 -1
  35. package/dist/eval.d.ts +3 -5
  36. package/dist/eval.d.ts.map +1 -1
  37. package/dist/eval.js +12 -20
  38. package/dist/eval.js.map +1 -1
  39. package/dist/expression.d.ts +10 -4
  40. package/dist/expression.d.ts.map +1 -1
  41. package/dist/expression.js +4 -4
  42. package/dist/expression.js.map +1 -1
  43. package/dist/index.d.ts +3 -1
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +1 -0
  46. package/dist/index.js.map +1 -1
  47. package/dist/interface.d.ts +30 -0
  48. package/dist/interface.d.ts.map +1 -0
  49. package/dist/interface.js +6 -0
  50. package/dist/interface.js.map +1 -0
  51. package/dist/main.d.ts +41 -28
  52. package/dist/main.d.ts.map +1 -1
  53. package/dist/main.js +145 -141
  54. package/dist/main.js.map +1 -1
  55. package/dist/migrate.d.ts +3 -2
  56. package/dist/migrate.d.ts.map +1 -1
  57. package/dist/migrate.js +12 -3
  58. package/dist/migrate.js.map +1 -1
  59. package/dist/migrator/access.d.ts.map +1 -1
  60. package/dist/migrator/access.js +22 -24
  61. package/dist/migrator/access.js.map +1 -1
  62. package/dist/migrator/call.d.ts.map +1 -1
  63. package/dist/migrator/call.js +235 -209
  64. package/dist/migrator/call.js.map +1 -1
  65. package/dist/migrator/interface.d.ts +3 -1
  66. package/dist/migrator/interface.d.ts.map +1 -1
  67. package/dist/migrator/interface.js.map +1 -1
  68. package/dist/migrator/node.js +1 -1
  69. package/dist/migrator/node.js.map +1 -1
  70. package/dist/migrator/operator.d.ts.map +1 -1
  71. package/dist/migrator/operator.js +19 -5
  72. package/dist/migrator/operator.js.map +1 -1
  73. package/dist/migrator/state.d.ts +2 -2
  74. package/dist/migrator/state.d.ts.map +1 -1
  75. package/dist/migrator/state.js +1 -2
  76. package/dist/migrator/state.js.map +1 -1
  77. package/dist/migrator/symbol.d.ts.map +1 -1
  78. package/dist/migrator/symbol.js +13 -0
  79. package/dist/migrator/symbol.js.map +1 -1
  80. package/dist/migrator/to-type.d.ts.map +1 -1
  81. package/dist/migrator/to-type.js +16 -0
  82. package/dist/migrator/to-type.js.map +1 -1
  83. package/dist/migrator/utils.d.ts +2 -0
  84. package/dist/migrator/utils.d.ts.map +1 -1
  85. package/dist/migrator/utils.js +18 -0
  86. package/dist/migrator/utils.js.map +1 -1
  87. package/dist/parser.d.ts +2 -2
  88. package/dist/parser.d.ts.map +1 -1
  89. package/dist/parser.js +25 -8
  90. package/dist/parser.js.map +1 -1
  91. package/dist/re-exports.d.ts +4 -0
  92. package/dist/re-exports.d.ts.map +1 -0
  93. package/dist/re-exports.js +3 -0
  94. package/dist/re-exports.js.map +1 -0
  95. package/dist/scope.d.ts +13 -16
  96. package/dist/scope.d.ts.map +1 -1
  97. package/dist/scope.js +56 -49
  98. package/dist/scope.js.map +1 -1
  99. package/dist/type.d.ts +14 -5
  100. package/dist/type.d.ts.map +1 -1
  101. package/dist/type.js +35 -11
  102. package/dist/type.js.map +1 -1
  103. package/package.json +4 -4
  104. package/src/analyze.ts +77 -37
  105. package/src/definitions/argument.ts +2 -12
  106. package/src/definitions/constraint.ts +3 -3
  107. package/src/definitions/parameter-decoration.ts +3 -9
  108. package/src/definitions/parameter-group.ts +4 -19
  109. package/src/definitions/parameter.ts +62 -61
  110. package/src/definitions/utils.ts +175 -0
  111. package/src/definitions/variable.ts +1 -6
  112. package/src/definitions.ts +1 -0
  113. package/src/eval.ts +13 -26
  114. package/src/expression.ts +14 -6
  115. package/src/index.ts +3 -1
  116. package/src/interface.ts +35 -0
  117. package/src/main.ts +213 -194
  118. package/src/migrate.ts +15 -6
  119. package/src/migrator/access.ts +21 -26
  120. package/src/migrator/call.ts +225 -194
  121. package/src/migrator/interface.ts +3 -1
  122. package/src/migrator/node.ts +1 -1
  123. package/src/migrator/operator.ts +19 -5
  124. package/src/migrator/state.ts +2 -2
  125. package/src/migrator/symbol.ts +13 -0
  126. package/src/migrator/to-type.ts +16 -0
  127. package/src/migrator/utils.ts +21 -0
  128. package/src/parser.ts +27 -8
  129. package/src/re-exports.ts +28 -0
  130. package/src/scope.ts +75 -61
  131. package/src/type.ts +32 -11
  132. package/tests/analyze.ts +40 -6
  133. package/tests/compile.ts +65 -0
  134. package/tests/condition.ts +13 -5
  135. package/tests/definition.ts +205 -18
  136. package/tests/eval-complex.ts +7 -10
  137. package/tests/eval.ts +59 -12
  138. package/tests/import.ts +18 -4
  139. package/tests/main.ts +9 -0
  140. package/tests/migrate.ts +77 -0
  141. package/tests/scope.ts +3 -3
  142. package/tests/template.ts +36 -0
  143. package/dist/context.d.ts +0 -41
  144. package/dist/context.d.ts.map +0 -1
  145. package/dist/context.js +0 -18
  146. package/dist/context.js.map +0 -1
  147. package/jest.config.js +0 -3
  148. package/src/context.ts +0 -54
  149. package/tests/tsconfig.json +0 -3
  150. package/tsconfig.json +0 -3
@@ -1,6 +1,6 @@
1
1
  import type { VmPrimitive, VmRecord } from '@mirascript/mirascript';
2
- import type { ExpressionOrValue } from '../expression.js';
3
- import type { ArgumentMap, ArgumentValue, ConditionExpression, ParameterFunction } from './argument.js';
2
+ import type { ExpressionFunction, ExpressionOrValue } from '../expression.js';
3
+ import type { ArgumentMap, ArgumentValue, ConditionExpression } from './argument.js';
4
4
  import type { Constraint } from './constraint.js';
5
5
  import type { ParameterDecoration } from './parameter-decoration.js';
6
6
  import type { ParameterGroup } from './parameter-group.js';
@@ -65,13 +65,10 @@ export interface IntegerParameter extends NumericParameter<'integer'> {}
65
65
  /** 可用于选项的值 */
66
66
  export type ChoiceArgumentValue = NonNullable<VmPrimitive>;
67
67
 
68
- /** 表示一个选项 Key,当其值为数字时,默认值为其在数组中的索引 */
69
- type ChoiceKey<V extends ChoiceArgumentValue> = V extends number ? number | null : V;
70
-
71
68
  /** 表示一个选项 */
72
- export type Choice<V extends ChoiceArgumentValue> = {
73
- /** 选中该选项将存储的参数值 */
74
- key: ChoiceKey<V>;
69
+ export type Choice<V extends ChoiceArgumentValue = ChoiceArgumentValue> = {
70
+ /** 选中该选项将存储的参数值,默认值为其在数组中的索引 */
71
+ key: V;
75
72
  /** 选项名称 */
76
73
  name: string;
77
74
  /** 选项详细描述 */
@@ -81,64 +78,56 @@ export type Choice<V extends ChoiceArgumentValue> = {
81
78
  };
82
79
 
83
80
  /** 是否为选项 */
84
- export function isChoice<V extends NonNullable<VmPrimitive>>(value: unknown): value is Choice<V> {
81
+ export function isChoice<V extends ChoiceArgumentValue = ChoiceArgumentValue>(value: unknown): value is Choice<V> {
85
82
  if (value == null || typeof value != 'object') return false;
86
83
  const c = value as Choice<V>;
87
- return typeof c.name === 'string' && typeof c.description == 'string' && !('items' in c) && !('value' in c);
88
- }
89
- /** 创建数值选项 */
90
- export function Choice(key?: ChoiceKey<number>): Choice<number>;
91
- /** 创建布尔选项 */
92
- export function Choice(key: ChoiceKey<boolean>): Choice<boolean>;
93
- /** 创建字符串选项 */
94
- export function Choice(key: ChoiceKey<string>): Choice<string>;
95
- /** 创建选项 */
96
- export function Choice<V extends NonNullable<VmPrimitive> = number>(key: ChoiceKey<V>): Choice<V>;
97
- /** 创建选项 */
98
- export function Choice<V extends NonNullable<VmPrimitive> = number>(key: ChoiceKey<V>): Choice<V> {
99
- return {
100
- key: key ?? (null as never),
101
- name: '',
102
- description: '',
103
- };
84
+ return (
85
+ typeof c.name === 'string' &&
86
+ typeof c.description == 'string' &&
87
+ !('items' in c) &&
88
+ !('value' in c) &&
89
+ !('span' in c)
90
+ );
104
91
  }
105
-
106
92
  /**
107
93
  * 表示值为选择项的参数定义
108
94
  */
109
- export interface ChoiceParameter<V extends ChoiceArgumentValue> extends ParameterBase<'choice', V> {
95
+ export interface ChoiceParameter<V extends ChoiceArgumentValue = ChoiceArgumentValue>
96
+ extends ParameterBase<'choice', V> {
110
97
  /**
111
98
  * 可选取值及其对应的说明文本
112
99
  */
113
- choices: ExpressionOrValue<Array<Choice<V>>> | ParameterFunction<Array<Choice<V>>>;
100
+ choices: ExpressionOrValue<Array<Choice<V>>> | ExpressionFunction<ReadonlyArray<Choice<V>>>;
114
101
  }
115
102
  /**
116
103
  * 表示值为多选选择项的参数定义
117
104
  */
118
- export interface MultiSelectParameter<V extends readonly ChoiceArgumentValue[]>
105
+ export interface MultiSelectParameter<V extends readonly ChoiceArgumentValue[] = readonly ChoiceArgumentValue[]>
119
106
  extends ParameterBase<'multiSelect', V> {
120
107
  /**
121
108
  * 可选取值及其对应的说明文本
122
109
  */
123
- choices: ExpressionOrValue<Array<Choice<V[number]>>> | ParameterFunction<Array<Choice<V[number]>>>;
110
+ choices: ExpressionOrValue<Array<Choice<V[number]>>> | ExpressionFunction<ReadonlyArray<Choice<V[number]>>>;
124
111
  }
125
112
 
126
113
  /**
127
114
  * 表示值为布尔量的参数定义
128
115
  */
129
- export interface LogicalParameter<V extends ChoiceArgumentValue> extends ParameterBase<'logical', V> {
116
+ export interface LogicalParameter<V extends ChoiceArgumentValue = ChoiceArgumentValue>
117
+ extends ParameterBase<'logical', V> {
130
118
  /**
131
119
  * 可选取值及其对应的说明文本
132
120
  */
133
121
  choices?:
134
122
  | ExpressionOrValue<[false: Choice<V>, true: Choice<V>]>
135
- | ParameterFunction<[false: Choice<V>, true: Choice<V>]>;
123
+ | ExpressionFunction<readonly [false: Choice<V>, true: Choice<V>]>;
136
124
  }
137
125
 
138
126
  /**
139
127
  * 表示值为表格的参数定义
140
128
  */
141
- export interface TableParameter<V extends readonly ArgumentValue[]> extends ParameterBase<'table', V> {
129
+ export interface TableParameter<V extends readonly ArgumentValue[] = readonly ArgumentValue[]>
130
+ extends ParameterBase<'table', V> {
142
131
  /** 最小行数 */
143
132
  minRowCount?: number;
144
133
  /** 最大行数 */
@@ -152,7 +141,15 @@ export interface TableParameter<V extends readonly ArgumentValue[]> extends Para
152
141
  *
153
142
  * 否则,表格参数的值为记录类型数组,每个记录包含各列定义的键值
154
143
  */
155
- columns: Parameter[] | ParameterFunction<Parameter[]>;
144
+ columns: Parameter[] | ExpressionFunction<readonly Parameter[]>;
145
+ /** 添加额外属性以跟踪表格行 */
146
+ trackTag?: string;
147
+ }
148
+
149
+ /** 生成用于跟踪的额外属性值 */
150
+ export function generateTrackId(): number {
151
+ // 生成 1 ~ 2^31-1 之间的随机整数
152
+ return Math.trunc(1 + Math.random() * 0x7fff_ffff);
156
153
  }
157
154
 
158
155
  /**
@@ -162,7 +159,7 @@ export interface TableParameter<V extends readonly ArgumentValue[]> extends Para
162
159
  *
163
160
  * 字段中可包含占位符,占位符在主轴上尺寸可自定义。
164
161
  */
165
- export interface RecordParameter<V extends VmRecord> extends ParameterBase<'record', V> {
162
+ export interface RecordParameter<V extends VmRecord = VmRecord> extends ParameterBase<'record', V> {
166
163
  /** 主轴的优先方向 */
167
164
  direction?: 'row' | 'column';
168
165
  /** 包含的元素 */
@@ -176,7 +173,7 @@ export interface RecordParameter<V extends VmRecord> extends ParameterBase<'reco
176
173
  *
177
174
  * 各分组沿主轴排列时占据位置由 span 定义。
178
175
  */
179
- export interface GroupedParameter<V extends VmRecord> extends ParameterBase<'grouped', V> {
176
+ export interface GroupedParameter<V extends VmRecord = VmRecord> extends ParameterBase<'grouped', V> {
180
177
  /** 主轴的优先方向 */
181
178
  direction?: 'row' | 'column';
182
179
  /** 包含的元素 */
@@ -227,23 +224,41 @@ export interface FileParameter extends ParameterBase<'file', string> {
227
224
  /**
228
225
  * 已定义的参数类型
229
226
  */
230
- export type ParameterMap = {
227
+ export interface ParameterMap {
228
+ /** 实数参数 */
231
229
  real: RealParameter;
230
+ /** 整数参数 */
232
231
  integer: IntegerParameter;
233
- choice: ChoiceParameter<string> | ChoiceParameter<number> | ChoiceParameter<boolean>;
234
- multiSelect: MultiSelectParameter<string[]> | MultiSelectParameter<number[]> | MultiSelectParameter<boolean[]>;
235
- logical: LogicalParameter<string> | LogicalParameter<number> | LogicalParameter<boolean>;
236
- table: TableParameter<ArgumentValue[]>;
232
+ /** 选择参数 */
233
+ choice: ChoiceParameter;
234
+ /** 多选参数 */
235
+ multiSelect: MultiSelectParameter;
236
+ /** 布尔参数 */
237
+ logical: LogicalParameter;
238
+ /** 表格参数 */
239
+ table: TableParameter;
240
+ /** 文本参数 */
237
241
  text: TextParameter;
242
+ /** 代码参数 */
238
243
  code: CodeParameter;
244
+ /** 文件参数 */
239
245
  file: FileParameter;
246
+ /** 记录参数 */
240
247
  record: RecordParameter<VmRecord>;
248
+ /** 分组记录参数 */
241
249
  grouped: GroupedParameter<VmRecord>;
242
- };
243
- /**
244
- * 已定义的参数类型
245
- */
246
- export type Parameter = ParameterMap[keyof ParameterMap];
250
+ }
251
+
252
+ /** 已定义的参数类型 type */
253
+ export type ParameterType = keyof ParameterMap;
254
+
255
+ /** 已定义的参数类型 */
256
+ export type Parameter = ParameterMap[ParameterType];
257
+
258
+ /** 已定义的选择参数类型 */
259
+ export type ChoiceParameterType = {
260
+ [K in keyof ParameterMap]: ParameterMap[K] extends { choices?: infer _ } ? ParameterMap[K]['type'] : never;
261
+ }[keyof ParameterMap];
247
262
 
248
263
  /**
249
264
  * 是否为参数定义
@@ -260,17 +275,3 @@ export function isParameter(value: unknown): value is Parameter {
260
275
  'value' in v
261
276
  );
262
277
  }
263
-
264
- /**
265
- * 创建参数定义
266
- */
267
- export function Parameter(): RealParameter {
268
- return {
269
- key: '',
270
- name: '',
271
- description: '',
272
- condition: '' as ConditionExpression,
273
- type: 'real',
274
- value: 0,
275
- };
276
- }
@@ -0,0 +1,175 @@
1
+ import { klona } from 'klona';
2
+ import { isVmArray, type VmPrimitive, type VmValue } from '@mirascript/mirascript';
3
+ import { Expression, isExpression } from '../expression.js';
4
+ import type { ChoiceParameterType, Parameter, ParameterMap } from './parameter.js';
5
+ import { TypeInfo } from '../type.js';
6
+ import type { ArgumentMap, ArgumentValue } from './argument.js';
7
+ import type { ParameterGroup } from './parameter-group.js';
8
+ const { isArray } = Array;
9
+
10
+ /** 推测枚举类型 */
11
+ export function enumType(definition: Pick<ParameterMap[ChoiceParameterType], 'type' | 'choices'>): TypeInfo | null {
12
+ const { choices } = definition;
13
+ if (typeof choices == 'function' || isExpression(choices)) return null;
14
+ let defaultType: TypeInfo = definition.type === 'logical' ? 'boolean' : 'number';
15
+ if ('value' in definition) {
16
+ const { value } = definition;
17
+ if (typeof value == 'boolean') defaultType = 'boolean';
18
+ else if (typeof value == 'number') defaultType = 'number';
19
+ else if (typeof value == 'string') defaultType = 'string';
20
+ }
21
+ if (choices == null || choices.length === 0) return defaultType;
22
+
23
+ let type: TypeInfo | null = null;
24
+ for (const choice of choices) {
25
+ const v = choice?.key;
26
+ const t = v == null ? defaultType : typeof v;
27
+ if (t === 'string') {
28
+ if (type == null) type = 'string';
29
+ else if (type !== 'string') return null;
30
+ } else if (t === 'number') {
31
+ if (type == null) type = 'number';
32
+ else if (type !== 'number') return null;
33
+ } else if (t === 'boolean') {
34
+ if (type == null) type = 'boolean';
35
+ else if (type !== 'boolean') return null;
36
+ } else {
37
+ return null;
38
+ }
39
+ }
40
+ return type;
41
+ }
42
+
43
+ /**
44
+ * 转换参数值的类型,不回退到 {@link Parameter.value} 提供的默认值
45
+ */
46
+ export function toArgumentValue<V extends ArgumentValue>(value: VmValue, definition: Parameter): V {
47
+ // 避免无效的 VmValue 导致错误
48
+ value ??= null;
49
+
50
+ switch (definition.type) {
51
+ case 'real':
52
+ case 'integer':
53
+ return TypeInfo.toNumber(value) as V;
54
+ case 'text':
55
+ case 'file':
56
+ case 'code':
57
+ case 'pinLike' as never:
58
+ case 'cssColor' as never:
59
+ case 'cssBackground' as never:
60
+ case 'resourceId' as never:
61
+ return TypeInfo.toString(value) as V;
62
+
63
+ case 'choice':
64
+ case 'logical': {
65
+ if (value == null && Array.isArray(definition.choices) && definition.choices.length > 0) {
66
+ value = definition.choices[0]?.key;
67
+ }
68
+ const type = enumType(definition);
69
+ if (!type) return value as V;
70
+ return TypeInfo.to(value, type) as V;
71
+ }
72
+
73
+ case 'multiSelect': {
74
+ const v = isVmArray(value) ? value : value != null ? ([value] as const) : [];
75
+ if (v.length === 0) return v as V;
76
+ const type = enumType(definition);
77
+ if (!type) return v as V;
78
+ return v.map((x) => TypeInfo.to(x, type)) as readonly VmPrimitive[] as V;
79
+ }
80
+
81
+ case 'table': {
82
+ const v = isVmArray(value) ? value : value != null ? ([value] as const) : [];
83
+ return v as V;
84
+ }
85
+
86
+ case 'grouped':
87
+ case 'record':
88
+ default:
89
+ return value as V;
90
+ }
91
+ }
92
+
93
+ /** 参数定义数组 */
94
+ type ParameterDefinitions = ReadonlyArray<Pick<ParameterGroup, 'items'>>;
95
+ /** 是否为包含参数组的参数定义数组 */
96
+ function checkParameterDefinitions(value: ParameterDefinitions | undefined): value is ParameterDefinitions {
97
+ return value != null && isArray(value as unknown[]) && value.length > 0;
98
+ }
99
+
100
+ /** 查找指定参数 */
101
+ function findParameterImpl(items: readonly Parameter[], key: string): Parameter | undefined {
102
+ if (items.length === 0) return undefined;
103
+ for (const item of items) {
104
+ if (item == null) continue;
105
+ if (item.key === key) return item;
106
+ }
107
+ return undefined;
108
+ }
109
+
110
+ /** 查找指定参数 */
111
+ export function findParameter(definition: ParameterDefinitions | undefined, key: string): Parameter | undefined {
112
+ if (!checkParameterDefinitions(definition)) return undefined;
113
+ for (const group of definition) {
114
+ if (group == null || !isArray(group.items)) continue;
115
+ const found = findParameterImpl(group.items, key);
116
+ if (found) return found;
117
+ }
118
+ return undefined;
119
+ }
120
+
121
+ /** 获取参数默认值,修复现有的参数,填充缺失的参数,删除未定义的参数 */
122
+ export function fillArgumentMap<T extends Record<string, ArgumentValue>>(
123
+ definition: ParameterDefinitions | undefined,
124
+ args?: ArgumentMap<T> | null,
125
+ ): ArgumentMap<T> {
126
+ args ??= {} as ArgumentMap<T>;
127
+ if (!checkParameterDefinitions(definition)) return args;
128
+
129
+ /** 参数键的类型 */
130
+ type K = keyof T & string;
131
+ /** 参数值的类型 */
132
+ type V = NonNullable<T[K]>;
133
+ const keys = new Set(Object.keys(args) as K[]);
134
+
135
+ // 根据定义填充或修复参数
136
+ for (const group of definition) {
137
+ for (const param of group.items) {
138
+ const key = param.key as K;
139
+ if (!key) continue;
140
+ const currentValue = keys.has(key) ? args[key] : undefined;
141
+ if (currentValue == null) {
142
+ // 使用默认值填充
143
+ const defaultValue = param.value;
144
+ if (isExpression(defaultValue)) {
145
+ args[key] = Expression<V>(defaultValue.source);
146
+ } else {
147
+ const value =
148
+ defaultValue != null && typeof defaultValue == 'object' ? klona(defaultValue) : defaultValue;
149
+ args[key] = toArgumentValue<V>(value, param);
150
+ }
151
+ } else {
152
+ // 已存在的参数值
153
+ if (isExpression(currentValue)) {
154
+ // 保留表达式
155
+ } else {
156
+ // 修复现有的参数值
157
+ const castedValue = toArgumentValue<V>(currentValue, param);
158
+ if (castedValue != null && castedValue !== currentValue) {
159
+ args[key] = castedValue;
160
+ }
161
+ }
162
+ }
163
+ keys.delete(key);
164
+ }
165
+ }
166
+
167
+ // 删除多余的参数
168
+ for (const key of keys) {
169
+ // 保留特殊参数和私有字段
170
+ const k0 = key[0];
171
+ if (k0 === '_' || k0 === '$' || k0 === '@' || k0 === 'ɵ') continue;
172
+ delete args[key];
173
+ }
174
+ return args;
175
+ }
@@ -12,12 +12,7 @@ export type Variable<T extends ArgumentValue = ArgumentValue> = {
12
12
  /** 检查是否为 `Variable` */
13
13
  export function isVariable(obj: unknown): obj is Variable {
14
14
  if (obj == null || typeof obj != 'object') return false;
15
- if ('condition' in obj || 'description' in obj) return false;
15
+ if ('condition' in obj || 'description' in obj || 'type' in obj) return false;
16
16
  const v = obj as Variable;
17
17
  return typeof v.key == 'string' && 'value' in v;
18
18
  }
19
-
20
- /** 创建空白 `Variable` */
21
- export function Variable(): Variable {
22
- return { key: '', value: '' };
23
- }
@@ -4,3 +4,4 @@ export * from './definitions/parameter.js';
4
4
  export * from './definitions/parameter-group.js';
5
5
  export * from './definitions/parameter-decoration.js';
6
6
  export * from './definitions/variable.js';
7
+ export * from './definitions/utils.js';
package/src/eval.ts CHANGED
@@ -1,64 +1,51 @@
1
1
  import type { VmValue } from '@mirascript/mirascript';
2
- import type { Context } from './context.js';
3
2
  import type { EvalExpressionCache, ExpressionCache } from './parser.js';
4
3
  import { Scope, unwrap } from './scope.js';
5
- import { TypeInfo } from './type.js';
6
-
7
- export const DEFAULTS = Symbol('defaults');
4
+ import type { Evaluator } from './main.js';
8
5
 
9
6
  /**
10
7
  * 表达式求值
11
8
  */
12
9
  export function evaluateEval<T extends VmValue>(
13
- context: Context,
10
+ evaluator: Evaluator,
14
11
  expression: EvalExpressionCache,
15
12
  scope: Scope,
16
- ): T | typeof DEFAULTS {
13
+ ): T | null {
17
14
  try {
18
15
  const result = expression.func(scope.proxy);
19
- if (result == null) return DEFAULTS;
16
+ if (result == null) return null;
20
17
  return unwrap(result as T);
21
18
  } catch (error: unknown) {
22
19
  if (scope.throws) throw error;
23
- context.logger.warn(
20
+ evaluator.logger.warn(
24
21
  `Failed to execute expression "${expression.source}": ${(error as Error).message || String(error)}.`,
25
22
  {
26
23
  error,
27
24
  scope,
28
25
  },
29
26
  );
30
- return DEFAULTS;
27
+ return null;
31
28
  }
32
29
  }
33
30
 
34
31
  /**
35
32
  * 表达式求值
36
33
  */
37
- export function evaluate<T extends VmValue, D = T>(
38
- context: Context,
39
- expression: ExpressionCache,
40
- returnType: TypeInfo | null,
41
- scope: Scope | undefined,
42
- defaults: D,
43
- ): D | T {
44
- let ret: T | typeof DEFAULTS;
34
+ export function evaluate<T extends VmValue>(evaluator: Evaluator, expression: ExpressionCache, scope: Scope): T | null {
35
+ let ret: T | null = null;
45
36
  if (expression.func != null) {
46
37
  scope ??= new Scope();
47
- const reset = scope.reset(context);
38
+ const reset = scope.reset(evaluator);
48
39
  try {
49
- ret = evaluateEval<T>(context, expression, scope);
40
+ ret = evaluateEval<T>(evaluator, expression, scope);
50
41
  } finally {
51
42
  reset();
52
43
  }
53
44
  } else if (expression.error != null) {
54
- if (scope?.throws ?? true) {
45
+ if (scope.throws) {
55
46
  throw expression.error;
56
47
  }
57
- ret = DEFAULTS;
58
- } else {
59
- ret = DEFAULTS;
60
48
  }
61
- if (ret === DEFAULTS) return defaults;
62
- if (!returnType) return ret;
63
- return TypeInfo.to(ret, returnType) as T;
49
+ if (ret == null) return null;
50
+ return ret;
64
51
  }
package/src/expression.ts CHANGED
@@ -2,6 +2,7 @@ import type { VmValue } from '@mirascript/mirascript';
2
2
  import type { Tagged } from 'type-fest';
3
3
  import type { LegacyType, TsTypeOf, TypeInfo } from './type.js';
4
4
  import type { Scope } from './scope.js';
5
+ import type { Evaluator } from './main.js';
5
6
 
6
7
  /** 表达式的标记属性 */
7
8
  export const ExpressionTag = 'ɵexp' as const;
@@ -18,10 +19,7 @@ export type Expression<T extends VmValue = VmValue> = {
18
19
  /**
19
20
  * 编译后的表达式
20
21
  */
21
- export interface CompiledExpression<T extends VmValue = VmValue> extends Expression<T> {
22
- (scope: Scope, defaults: T): T;
23
- (scope?: Scope): T | undefined;
24
- }
22
+ export type CompiledExpression<T extends VmValue = VmValue> = Expression<T> & ExpressionFunction<T>;
25
23
 
26
24
  /** 表示一个表达式内容 */
27
25
  export type ExpressionSource<T extends VmValue = VmValue> = Tagged<string, 'ExpressionResult', T>;
@@ -41,9 +39,9 @@ export function Expression<T extends VmValue = VmValue>(
41
39
  source: string | Expression<T>,
42
40
  returnType: TypeInfo | LegacyType | '' = '',
43
41
  ): Expression<T> {
44
- if (!source) throw new Error(`Invalid expression ${String(source)}`);
42
+ if (source == null) throw new TypeError(`Invalid expression ${String(source)}`);
45
43
  const s = isExpression(source) ? source.source : source;
46
- if (!s || typeof s != 'string') throw new Error(`Invalid expression ${String(s)}`);
44
+ if (typeof s != 'string') throw new TypeError(`Invalid expression ${String(s)}`);
47
45
  return { [ExpressionTag]: returnType, source: s as ExpressionSource<T> };
48
46
  }
49
47
 
@@ -60,3 +58,13 @@ export type ExpressionResult<T> = T extends Expression<infer R> ? R : T;
60
58
  export type ExpressionResultObject<T> = {
61
59
  [K in keyof T]: ExpressionResult<T[K]>;
62
60
  };
61
+
62
+ /**
63
+ * 表示一个具有类似表达式功能的 JS 函数
64
+ */
65
+ export type ExpressionFunction<out T> = (
66
+ /** 当前作用域 */
67
+ scope: Scope,
68
+ /** 当前求值器 */
69
+ evaluator: Evaluator,
70
+ ) => T | null;
package/src/index.ts CHANGED
@@ -1,5 +1,7 @@
1
- export type { Options, Context } from './context.js';
1
+ export type { Options, Logger } from './interface.js';
2
2
  export { Scope } from './scope.js';
3
3
  export { Evaluator } from './main.js';
4
+ export type { AccessChain } from './analyze.js';
4
5
  export * from './expression.js';
5
6
  export * from './type.js';
7
+ export * from './re-exports.js';
@@ -0,0 +1,35 @@
1
+ /** 日志 */
2
+ export interface Logger {
3
+ /**
4
+ * error
5
+ */
6
+ error(...args: unknown[]): void;
7
+ /**
8
+ * warning
9
+ */
10
+ warn(...args: unknown[]): void;
11
+ /**
12
+ * info
13
+ */
14
+ info(...args: unknown[]): void;
15
+ /**
16
+ * debug
17
+ */
18
+ debug(...args: unknown[]): void;
19
+ }
20
+
21
+ /** 选项 */
22
+ export interface Options {
23
+ /** 日志 */
24
+ logger: Logger;
25
+ /** 表达式缓存 */
26
+ expressionCacheSize: number;
27
+ /** 模板缓存 */
28
+ templateCacheSize: number;
29
+ }
30
+
31
+ export const defaultOptions: Options = {
32
+ logger: console,
33
+ expressionCacheSize: 50,
34
+ templateCacheSize: 50,
35
+ };