@codehz/json-expr 0.3.0 → 0.5.0

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/README.md CHANGED
@@ -6,12 +6,16 @@
6
6
 
7
7
  ## 特性
8
8
 
9
- - 🎯 **类型安全** - 使用 TypeScript 和 Zod 进行完整的类型推导和验证
9
+ - 🎯 **类型安全** - 使用 TypeScript 泛型进行完整的编译时类型推导
10
10
  - 📦 **可序列化** - 编译后的表达式为纯 JSON 格式,易于传输和存储
11
11
  - 🔧 **灵活的表达式** - 支持任意 JavaScript 表达式,包括函数调用和对象属性访问
12
- - ⚡ **高性能** - 使用 `new Function()` 进行优化执行
12
+ - ⚡ **高性能** - 优化的表达式编译和执行
13
13
  - 🧩 **可组合** - 表达式可以相互组合,形成复杂的计算树
14
- - 🔐 **类型验证** - 运行时通过 Zod schema 进行数据验证
14
+ - 🔄 **短路求值** - 支持 `&&`、`||`、`??` 和三元表达式的控制流优化
15
+ - 📝 **内联优化** - 自动内联只被引用一次的子表达式
16
+ - 🔗 **Proxy 变量系统** - 支持链式属性访问和方法调用,如 `config.timeout`、`user.profile.name`
17
+ - 🎛️ **Lambda 表达式** - 类型安全的数组方法支持(map、filter、reduce 等)
18
+ - 🛡️ **错误检测** - 编译时检测未定义变量和类型错误
15
19
 
16
20
  ## 快速开始
17
21
 
@@ -24,12 +28,11 @@ bun install @codehz/json-expr
24
28
  ### 基本用法
25
29
 
26
30
  ```typescript
27
- import { z } from "zod";
28
- import { variable, expr, compile, evaluate, constant } from "@codehz/json-expr";
31
+ import { variable, expr, compile, evaluate, t, lambda } from "@codehz/json-expr";
29
32
 
30
- // 定义类型化变量
31
- const x = variable(z.number());
32
- const y = variable(z.number());
33
+ // 定义类型化变量(使用 TypeScript 泛型)
34
+ const x = variable<number>();
35
+ const y = variable<number>();
33
36
 
34
37
  // 构建表达式
35
38
  const sum = expr({ x, y })("x + y");
@@ -43,23 +46,29 @@ const compiled = compile(result, { x, y });
43
46
  // 执行编译后的表达式
44
47
  const value = evaluate(compiled, { x: 2, y: 3 });
45
48
  // => 11 (2+3 + 2*3 = 5 + 6 = 11)
49
+
50
+ // 使用模板字符串
51
+ const name = variable<string>();
52
+ const greeting = t`Hello, ${name}!`;
53
+
54
+ // 使用 lambda 表达式
55
+ const numbers = variable<number[]>();
56
+ const doubled = numbers.map(lambda<[number], number>((n) => expr({ n })("n * 2")));
46
57
  ```
47
58
 
48
59
  ## 核心概念
49
60
 
50
61
  ### Variable(变量)
51
62
 
52
- 变量是表达式中的占位符,通过 Zod schema 定义其类型和验证规则。
63
+ 变量是表达式中的占位符,使用 TypeScript 泛型定义其类型。
53
64
 
54
65
  ```typescript
55
- const age = variable(z.number().int().min(0).max(150));
56
- const name = variable(z.string().min(1));
57
- const config = variable(
58
- z.object({
59
- debug: z.boolean(),
60
- timeout: z.number(),
61
- })
62
- );
66
+ const age = variable<number>();
67
+ const name = variable<string>();
68
+ const config = variable<{
69
+ debug: boolean;
70
+ timeout: number;
71
+ }>();
63
72
  ```
64
73
 
65
74
  ### Expression(表达式)
@@ -67,8 +76,8 @@ const config = variable(
67
76
  表达式对变量或其他表达式进行运算,使用字符串形式描述。
68
77
 
69
78
  ```typescript
70
- const x = variable(z.number());
71
- const y = variable(z.number());
79
+ const x = variable<number>();
80
+ const y = variable<number>();
72
81
 
73
82
  // 简单表达式
74
83
  const sum = expr({ x, y })("x + y");
@@ -93,51 +102,23 @@ const compiled = compile(result, { x, y });
93
102
 
94
103
  ## API 参考
95
104
 
96
- ### `constant<T>(value: T): Expression<{}, T>`
97
-
98
- 创建一个编译期常量表达式。这是 `expr({})(JSON.stringify(value))` 的快速路径,用于在表达式中嵌入静态值,避免在运行时传入或在多处重复编写。
99
-
100
- **参数:**
101
-
102
- - `value` - 要嵌入的常量值(必须是 JSON 可序列化的:string、number、boolean、null、数组或对象)
103
-
104
- **返回值:** Expression 对象
105
-
106
- **示例:**
107
-
108
- ```typescript
109
- import { constant, expr, variable, compile, evaluate } from "@codehz/json-expr";
110
- import { z } from "zod";
111
-
112
- // 创建常量
113
- const PI = constant(3.14159);
114
- const config = constant({ maxRetries: 3, timeout: 5000 });
115
-
116
- // 在表达式中使用常量
117
- const radius = variable(z.number());
118
- const area = expr({ PI, radius })("PI * radius * radius");
119
-
120
- const compiled = compile(area, { radius });
121
- const result = evaluate(compiled, { radius: 2 });
122
- // => 12.56636
123
- ```
124
-
125
- ### `variable<T>(schema: T): Variable<T>`
105
+ ### `variable<T>(): Variable<T>`
126
106
 
127
107
  创建一个类型化变量。
128
108
 
129
- **参数:**
130
-
131
- - `schema` - Zod schema,定义变量的类型和验证规则
109
+ **参数:** 无(类型通过泛型参数 `T` 指定)
132
110
 
133
- **返回值:** Variable 对象
111
+ **返回值:** Variable 对象,支持属性访问和方法调用
134
112
 
135
113
  **示例:**
136
114
 
137
115
  ```typescript
138
- const num = variable(z.number());
139
- const str = variable(z.string());
140
- const date = variable(z.date());
116
+ const num = variable<number>();
117
+ const str = variable<string>();
118
+ const config = variable<{ timeout: number }>();
119
+
120
+ // 支持链式属性访问
121
+ const timeout = config.timeout; // 自动转换为表达式
141
122
  ```
142
123
 
143
124
  ### `expr<TContext>(context: TContext): (source: string) => Expression<TContext, TResult>`
@@ -153,21 +134,21 @@ const date = variable(z.date());
153
134
  **示例:**
154
135
 
155
136
  ```typescript
156
- const x = variable(z.number());
157
- const y = variable(z.number());
137
+ const x = variable<number>();
138
+ const y = variable<number>();
158
139
 
159
140
  const sum = expr({ x, y })("x + y");
160
141
  const result = expr({ sum, x })("sum * x");
161
142
  ```
162
143
 
163
- ### `compile<TResult>(expression: Expression<any, TResult>, variables: Record<string, Variable<any>>, options?: CompileOptions): CompiledData`
144
+ ### `compile<TResult>(expression: Expression<any, TResult>, variables: Record<string, Variable<any>> | Variable<any>[], options?: CompileOptions): CompiledData`
164
145
 
165
146
  将表达式树编译为可序列化的 JSON 结构。
166
147
 
167
148
  **参数:**
168
149
 
169
150
  - `expression` - 要编译的表达式
170
- - `variables` - 表达式中使用的所有变量映射
151
+ - `variables` - 表达式中使用的所有变量映射或数组
171
152
  - `options` - 编译选项(可选)
172
153
  - `inline?: boolean` - 是否启用内联优化,将只被引用一次的子表达式内联到使用位置(默认:true)
173
154
  - `shortCircuit?: boolean` - 是否启用短路求值,为 &&, ||, ??, 和三元表达式生成控制流节点(默认:true)
@@ -177,14 +158,14 @@ const result = expr({ sum, x })("sum * x");
177
158
  **示例:**
178
159
 
179
160
  ```typescript
180
- const x = variable(z.number());
181
- const y = variable(z.number());
161
+ const x = variable<number>();
162
+ const y = variable<number>();
182
163
  const sum = expr({ x, y })("x + y");
183
164
  const product = expr({ x, y })("x * y");
184
165
  const result = expr({ sum, product })("sum + product");
185
166
 
186
167
  const compiled = compile(result, { x, y });
187
- // [["x", "y"], "($0+$1)", "($0*$1)", "$2+$3"]
168
+ // [["x", "y"], "$0+$1", "$0*$1", "$2+$3"]
188
169
 
189
170
  // 禁用内联优化
190
171
  const noInline = compile(result, { x, y }, { inline: false });
@@ -209,30 +190,222 @@ const noShortCircuit = compile(result, { x, y }, { shortCircuit: false });
209
190
  **示例:**
210
191
 
211
192
  ```typescript
193
+ const x = variable<number>();
194
+ const y = variable<number>();
195
+ const sum = expr({ x, y })("x + y");
196
+ const product = expr({ x, y })("x * y");
197
+ const result = expr({ sum, product })("sum + product");
198
+
212
199
  const compiled = compile(result, { x, y });
213
200
  const value = evaluate(compiled, { x: 5, y: 3 });
214
201
  // => 23 ((5+3) + (5*3) = 8 + 15 = 23)
215
202
  ```
216
203
 
204
+ ### `t(strings: TemplateStringsArray, ...values: unknown[]): Proxify<string>`
205
+
206
+ 使用标签模板函数创建包含变量的字符串表达式。
207
+
208
+ **参数:**
209
+
210
+ - `strings` - 模板字符串的静态部分
211
+ - `values` - 模板中插值的变量和表达式
212
+
213
+ **返回值:** 字符串类型的 Proxy Expression
214
+
215
+ **示例:**
216
+
217
+ ```typescript
218
+ const name = variable<string>();
219
+ const count = variable<number>();
220
+
221
+ const greeting = t`Hello, ${name}!`;
222
+ const message = t`You have ${count} items.`;
223
+
224
+ const compiled = compile(greeting, { name });
225
+ const result = evaluate(compiled, { name: "Alice" });
226
+ // => "Hello, Alice!"
227
+ ```
228
+
229
+ ### `lambda<Args, R>(builder: LambdaBuilder<Args, R>): Lambda<Args, R>`
230
+
231
+ 创建类型安全的 lambda 表达式,用于数组方法(map、filter、reduce 等)。
232
+
233
+ **参数:**
234
+
235
+ - `builder` - Lambda 构建函数,接收参数代理,返回函数体表达式
236
+
237
+ **返回值:** Lambda 表达式,可在数组方法中使用
238
+
239
+ **示例:**
240
+
241
+ ```typescript
242
+ import { lambda } from "@codehz/json-expr";
243
+
244
+ // 单参数 lambda
245
+ const numbers = variable<number[]>();
246
+ const doubled = numbers.map(lambda<[number], number>((n) => expr({ n })("n * 2")));
247
+
248
+ const compiled = compile(doubled, { numbers });
249
+ const result = evaluate(compiled, { numbers: [1, 2, 3] });
250
+ // => [2, 4, 6]
251
+
252
+ // 多参数 lambda(reduce)
253
+ const sum = numbers.reduce(
254
+ lambda<[number, number], number>((acc, val) => expr({ acc, val })("acc + val")),
255
+ 0
256
+ );
257
+
258
+ // 捕获外部变量
259
+ const multiplier = variable<number>();
260
+ const scaled = numbers.map(lambda<[number], number>((n) => expr({ n, multiplier })("n * multiplier")));
261
+ ```
262
+
217
263
  ## 高级用法
218
264
 
219
- ### 传入对象和内置对象
265
+ ### Proxy 变量系统
266
+
267
+ `variable()` 创建的变量是 Proxy 对象,支持链式属性访问和方法调用,所有操作都会自动转换为表达式。
268
+
269
+ **属性访问:**
270
+
271
+ ```typescript
272
+ const config = variable<{
273
+ timeout: number;
274
+ retries: number;
275
+ database: {
276
+ host: string;
277
+ port: number;
278
+ };
279
+ }>();
280
+
281
+ // 链式属性访问
282
+ const timeout = config.timeout; // 自动转换为表达式
283
+ const dbHost = config.database.host; // 支持嵌套访问
284
+
285
+ const compiled = compile(timeout, { config });
286
+ const result = evaluate(compiled, {
287
+ config: { timeout: 5000, retries: 3, database: { host: "localhost", port: 5432 } },
288
+ });
289
+ // => 5000
290
+ ```
291
+
292
+ **方法调用:**
293
+
294
+ ```typescript
295
+ const calculator = variable<{
296
+ add(a: number, b: number): number;
297
+ multiply(x: number, y: number): number;
298
+ }>();
299
+
300
+ // 方法调用
301
+ const sum = calculator.add(1, 2);
302
+ const product = calculator.multiply(5, 3);
303
+
304
+ // 链式方法调用
305
+ const builder = variable<{
306
+ setName(name: string): typeof builder;
307
+ build(): { name: string };
308
+ }>();
309
+ const result = builder.setName("test").build();
310
+
311
+ // 编译并执行
312
+ const compiled = compile(sum, { calculator });
313
+ const value = evaluate(compiled, {
314
+ calculator: {
315
+ add: (a, b) => a + b,
316
+ multiply: (x, y) => x * y,
317
+ },
318
+ });
319
+ // => 3
320
+ ```
321
+
322
+ **数组方法:**
323
+
324
+ 数组变量支持所有标准数组方法,并自动处理类型推导:
325
+
326
+ ```typescript
327
+ const numbers = variable<number[]>();
328
+ const users = variable<{ id: number; name: string }[]>();
329
+
330
+ // map
331
+ const doubled = numbers.map((n) => expr({ n })("n * 2"));
332
+
333
+ // filter
334
+ const activeUsers = users.filter((u) => expr({ u })("u.active"));
220
335
 
221
- 支持在上下文中传入对象(如 Math)以在表达式中访问其属性和方法:
336
+ // reduce
337
+ const sum = numbers.reduce(
338
+ lambda<[number, number], number>((acc, val) => expr({ acc, val })("acc + val")),
339
+ 0
340
+ );
341
+
342
+ // find, some, every, sort 等
343
+ const firstMatch = users.find((u) => expr({ u })("u.id === 1"));
344
+ const hasAdmins = users.some((u) => expr({ u })("u.role === 'admin'"));
345
+ const allActive = users.every((u) => expr({ u })("u.active"));
346
+ const sorted = numbers.toSorted(lambda<[number, number], number>((a, b) => expr({ a, b })("a - b")));
347
+ ```
348
+
349
+ ### 内置全局对象
350
+
351
+ 表达式中可以直接使用以下内置对象(无需在上下文中定义):
352
+
353
+ - `Math`, `JSON`, `Date`, `RegExp`
354
+ - `Number`, `String`, `Boolean`, `Array`, `Object`
355
+ - `undefined`, `NaN`, `Infinity`
356
+ - `isNaN`, `isFinite`, `parseInt`, `parseFloat`
222
357
 
223
358
  ```typescript
224
- const x = variable(z.number());
359
+ const x = variable<number>();
225
360
 
226
- const sqrtExpr = expr({ x, Math: variable(z.any()) })("Math.sqrt(x)");
227
- const compiled = compile(sqrtExpr, { x, Math: variable(z.any()) });
228
- const result = evaluate(compiled, { x: 16, Math });
361
+ const sqrtExpr = expr({ x })("Math.sqrt(x)");
362
+ const compiled = compile(sqrtExpr, { x });
363
+ const result = evaluate(compiled, { x: 16 });
229
364
  // => 4
230
365
  ```
231
366
 
367
+ ### 支持的运算符和语法
368
+
369
+ **算术运算符:**
370
+
371
+ - `+`, `-`, `*`, `/`, `%`, `**` (幂运算)
372
+
373
+ **比较运算符:**
374
+
375
+ - `==`, `===`, `!=`, `!==`, `<`, `>`, `<=`, `>=`
376
+
377
+ **逻辑运算符:**
378
+
379
+ - `&&`, `||`, `!`, `??` (空值合并)
380
+
381
+ **位运算符:**
382
+
383
+ - `&`, `|`, `^`, `~`, `<<`, `>>`, `>>>`
384
+
385
+ **其他运算符:**
386
+
387
+ - `? :` (三元表达式)
388
+ - `in` (属性存在检查)
389
+ - `instanceof` (类型检查)
390
+ - `typeof` (类型检测)
391
+ - `?.` (可选链)
392
+ - `?.()` (可选调用)
393
+ - `?.[]` (可选元素访问)
394
+
395
+ **语法特性:**
396
+
397
+ - 对象字面量:`{ key: value, ... }`
398
+ - 数组字面量:`[element1, element2, ...]`
399
+ - 箭头函数:`(param) => expression`
400
+ - 函数调用:`func(arg1, arg2, ...)`
401
+ - 成员访问:`obj.prop`, `obj["prop"]`, `arr[0]`
402
+ - 模板字面量(通过 `t` 标签函数)
403
+ - 分组括号:`(expression)`
404
+
232
405
  ### 条件表达式
233
406
 
234
407
  ```typescript
235
- const score = variable(z.number());
408
+ const score = variable<number>();
236
409
  const gradeExpr = expr({ score })("score >= 90 ? 'A' : score >= 80 ? 'B' : score >= 70 ? 'C' : 'F'");
237
410
 
238
411
  const compiled = compile(gradeExpr, { score });
@@ -243,7 +416,7 @@ const grade = evaluate(compiled, { score: 85 });
243
416
  ### 数组和对象操作
244
417
 
245
418
  ```typescript
246
- const numbers = variable(z.array(z.number()));
419
+ const numbers = variable<number[]>();
247
420
 
248
421
  const sumExpr = expr({ numbers })("numbers.reduce((a, b) => a + b, 0)");
249
422
 
@@ -255,8 +428,8 @@ const sum = evaluate(compiled, { numbers: [1, 2, 3, 4, 5] });
255
428
  ### 链式表达式组合
256
429
 
257
430
  ```typescript
258
- const a = variable(z.number());
259
- const b = variable(z.number());
431
+ const a = variable<number>();
432
+ const b = variable<number>();
260
433
 
261
434
  const sum = expr({ a, b })("a + b");
262
435
  const product = expr({ a, b })("a * b");
@@ -269,6 +442,75 @@ const result = evaluate(compiled, { a: 2, b: 3 });
269
442
  // => (2+3) * (2*3) - (2-3) = 5 * 6 - (-1) = 30 + 1 = 31
270
443
  ```
271
444
 
445
+ ### 短路求值(控制流优化)
446
+
447
+ 编译器支持为 `&&`、`||`、`??` 和三元表达式生成短路求值代码,避免不必要的计算:
448
+
449
+ ```typescript
450
+ const a = variable<boolean>();
451
+ const b = variable<boolean>();
452
+
453
+ // 逻辑或短路
454
+ const orExpr = expr({ a, b })("a || b");
455
+ const compiled = compile(orExpr, { a, b }, { shortCircuit: true });
456
+
457
+ // 当 a 为 true 时,b 不会被求值
458
+ // 编译数据包含控制流节点:
459
+ // [["a", "b"], ["br", "$0", 1], "$1", ["phi"]]
460
+
461
+ // 空值合并
462
+ const x = variable<number | null>();
463
+ const y = variable<number>();
464
+ const coalesce = expr({ x, y })("x ?? y");
465
+
466
+ // 三元表达式
467
+ const condition = variable<boolean>();
468
+ const result = variable<number>();
469
+ const alternative = variable<number>();
470
+ const ternary = expr({ condition, result, alternative })("condition ? result : alternative");
471
+ ```
472
+
473
+ ### 自动内联优化
474
+
475
+ 编译器自动将只被引用一次的子表达式内联到使用位置,减少中间计算:
476
+
477
+ ```typescript
478
+ const x = variable<number>();
479
+ const y = variable<number>();
480
+
481
+ const sum = expr({ x, y })("x + y");
482
+ const product = expr({ x, y })("x * y");
483
+ const result = expr({ sum, product })("sum + product");
484
+
485
+ // 自动内联后,编译结果为:
486
+ // [["x", "y"], "($0+$1)+($0*$1)"]
487
+ // 而不是 [["x", "y"], "$0+$1", "$0*$1", "$2+$3"]
488
+
489
+ const compiled = compile(result, { x, y });
490
+ const value = evaluate(compiled, { x: 2, y: 3 });
491
+ // => 11
492
+ ```
493
+
494
+ ### 直接编译对象和数组
495
+
496
+ `compile` 函数支持直接编译包含 Proxy 的对象和数组:
497
+
498
+ ```typescript
499
+ const x = variable<number>();
500
+ const y = variable<number>();
501
+ const sum = expr({ x, y })("x + y");
502
+
503
+ // 编译对象
504
+ const objCompiled = compile({ result: sum, original: { x, y } }, { x, y });
505
+ const objResult = evaluate(objCompiled, { x: 10, y: 20 });
506
+ // => { result: 30, original: { x: 10, y: 20 } }
507
+
508
+ // 编译数组
509
+ const arrCompiled = compile([x, sum, 100], { x, y });
510
+ const arrResult = evaluate(arrCompiled, { x: 5, y: 3 });
511
+ // => [5, 8, 100]
512
+ ```
513
+
272
514
  ## 序列化和传输
273
515
 
274
516
  编译后的数据可以轻松进行 JSON 序列化,适合网络传输或持久化存储:
@@ -290,16 +532,200 @@ const deserialized = JSON.parse(json);
290
532
  const value = evaluate(deserialized, { x: 5, y: 3 });
291
533
  ```
292
534
 
535
+ ## 编译数据格式
536
+
537
+ ### V1 格式(基础表达式)
538
+
539
+ 基础格式为 JSON 数组:`[variableNames, ...expressions]`
540
+
541
+ ```typescript
542
+ // 输入
543
+ const sum = expr({ x, y })("x + y");
544
+ const compiled = compile(sum, { x, y });
545
+
546
+ // 输出
547
+ // [["x", "y"], "$0+$1"]
548
+ // $0 引用 x,$1 引用 y
549
+ ```
550
+
551
+ ### V2 格式(控制流节点)
552
+
553
+ 启用短路求值时,生成包含控制流节点的格式:
554
+
555
+ ```typescript
556
+ // 输入
557
+ const result = expr({ a, b })("a || b");
558
+ const compiled = compile(result, { a, b }, { shortCircuit: true });
559
+
560
+ // 输出
561
+ // [
562
+ // ["a", "b"],
563
+ // ["br", "$0", 1], // 如果 $0 为 truthy,跳过 1 条指令
564
+ // "$1", // 否则求值 $1
565
+ // ["phi"] // 取最近求值结果
566
+ // ]
567
+ ```
568
+
569
+ **控制流节点类型:**
570
+
571
+ - `["br", condition, offset]` - 条件跳转,条件为真时跳过 offset 条指令
572
+ - `["jmp", offset]` - 无条件跳转,跳过 offset 条指令
573
+ - `["phi"]` - 取最近求值结果(用于合并分支)
574
+
575
+ ## 错误处理
576
+
577
+ ### 编译时错误
578
+
579
+ 编译器会检测并报告以下错误:
580
+
581
+ ```typescript
582
+ const x = variable<number>();
583
+ const y = variable<number>();
584
+
585
+ // 错误:引用未定义的变量
586
+ const invalid = expr({ x, y })("x + y + z");
587
+ compile(invalid, { x, y });
588
+ // => Error: Undefined variable(s): z
589
+
590
+ // 错误:变量名冲突
591
+ const xy = variable<number>();
592
+ const conflict = expr({ xy, x })("xy + x");
593
+ // 正确处理:编译器能区分 xy 和 x
594
+ const compiled = compile(conflict, { xy, x });
595
+ // => [["xy", "x"], "$0+$1"]
596
+ ```
597
+
598
+ ### 运行时错误
599
+
600
+ 求值器会验证输入并报告运行时错误:
601
+
602
+ ```typescript
603
+ const x = variable<number>();
604
+ const y = variable<number>();
605
+
606
+ const sum = expr({ x, y })("x + y");
607
+ const compiled = compile(sum, { x, y });
608
+
609
+ // 错误:缺少必需变量
610
+ evaluate(compiled, { x: 2 });
611
+ // => Error: Missing required variable: y
612
+
613
+ // 错误:无效的编译数据
614
+ evaluate([], { x: 1 });
615
+ // => Error: Invalid compiled data: must have at least variable names
616
+ ```
617
+
293
618
  ## 类型安全
294
619
 
295
620
  项目充分利用 TypeScript 的类型系统进行编译时检查和类型推导:
296
621
 
297
622
  ```typescript
298
- const x = variable(z.number());
299
- const y = variable(z.string());
623
+ const x = variable<number>();
624
+ const y = variable<string>();
300
625
 
301
- // 提供完整的类型推导和自动补全
302
- const sum = expr({ x, y })("x + y");
626
+ // 类型错误会在编译时捕获
627
+ // const invalid = expr({ x, y })("z + y"); // Error: 'z' not in context
628
+ const valid = expr({ x })("-x"); // 编译器推导为 number
629
+ ```
630
+
631
+ ## 实际应用示例
632
+
633
+ ### 动态表单验证规则
634
+
635
+ ```typescript
636
+ const formData = variable<{
637
+ username: string;
638
+ password: string;
639
+ confirmPassword: string;
640
+ age: number;
641
+ }>();
642
+
643
+ // 创建验证规则表达式
644
+ const isUsernameValid = expr({ formData })("formData.username.length >= 3 && formData.username.length <= 20");
645
+
646
+ const isPasswordValid = expr({ formData })("formData.password.length >= 8 && /[A-Z]/.test(formData.password)");
647
+
648
+ const doPasswordsMatch = expr({ formData })("formData.password === formData.confirmPassword");
649
+
650
+ const isAgeValid = expr({ formData })("formData.age >= 18 && formData.age <= 120");
651
+
652
+ const isFormValid = expr({
653
+ isUsernameValid,
654
+ isPasswordValid,
655
+ doPasswordsMatch,
656
+ isAgeValid,
657
+ })("isUsernameValid && isPasswordValid && doPasswordsMatch && isAgeValid");
658
+
659
+ // 编译一次,多次执行
660
+ const compiled = compile(isFormValid, { formData });
661
+
662
+ // 在表单输入时实时验证
663
+ evaluate(compiled, {
664
+ formData: {
665
+ username: "john_doe",
666
+ password: "Secure123",
667
+ confirmPassword: "Secure123",
668
+ age: 25,
669
+ },
670
+ }); // => true
671
+ ```
672
+
673
+ ### 数据转换管道
674
+
675
+ ```typescript
676
+ const rawData = variable<any[]>();
677
+ const config = variable<{
678
+ minValue: number;
679
+ maxValue: number;
680
+ transform: (x: number) => number;
681
+ }>();
682
+
683
+ // 构建数据处理管道
684
+ const filtered = rawData.filter(
685
+ lambda<[any], boolean>((item) =>
686
+ expr({ item, config })("item.value >= config.minValue && item.value <= config.maxValue")
687
+ )
688
+ );
689
+
690
+ const transformed = filtered.map(
691
+ lambda<[any], number>((item) => expr({ item, config })("config.transform(item.value)"))
692
+ );
693
+
694
+ const sorted = transformed.toSorted(lambda<[number, number], number>((a, b) => expr({ a, b })("a - b")));
695
+
696
+ const pipeline = compile(sorted, { rawData, config });
697
+
698
+ // 执行数据处理
699
+ const result = evaluate(pipeline, {
700
+ rawData: [{ value: 10 }, { value: 5 }, { value: 20 }, { value: 15 }],
701
+ config: { minValue: 8, maxValue: 18, transform: (x: number) => x * 2 },
702
+ });
703
+ // => [10, 20, 30] (5 被过滤,10*2=20, 15*2=30, 20 被过滤)
704
+ ```
705
+
706
+ ### 规则引擎
707
+
708
+ ```typescript
709
+ // 定义规则条件
710
+ const user = variable<{
711
+ age: number;
712
+ role: string;
713
+ balance: number;
714
+ }>();
715
+
716
+ const isEligible = expr({ user })(
717
+ "(user.age >= 18 && user.age <= 65) && (user.role === 'premium' || user.balance > 10000)"
718
+ );
719
+
720
+ const discountRate = expr({ user, isEligible })("isEligible ? (user.role === 'premium' ? 0.2 : 0.1) : 0");
721
+
722
+ const rule = compile(discountRate, { user });
723
+
724
+ // 应用规则
725
+ const discount = evaluate(rule, {
726
+ user: { age: 30, role: "premium", balance: 5000 },
727
+ });
728
+ // => 0.2 (20% 折扣)
303
729
  ```
304
730
 
305
731
  ## 性能考虑
@@ -307,20 +733,45 @@ const sum = expr({ x, y })("x + y");
307
733
  - **编译时间**:编译过程涉及依赖分析和拓扑排序,通常快速完成
308
734
  - **执行时间**:表达式通过 `new Function()` 编译为原生 JavaScript,执行性能接近原生代码
309
735
  - **内存占用**:编译数据为纯 JSON,占用空间小,适合在网络上传输
736
+ - **缓存机制**:求值器缓存已编译的函数,重复执行时性能更优
737
+
738
+ ### 最佳实践
739
+
740
+ 1. **编译一次,多次执行**:对于重复使用的表达式,先编译后多次求值
741
+
742
+ ```typescript
743
+ const compiled = compile(expression, variables);
744
+ // 缓存 compiled,多次调用 evaluate
745
+ evaluate(compiled, values1);
746
+ evaluate(compiled, values2);
747
+ ```
748
+
749
+ 2. **合理使用短路求值**:对于条件表达式,启用短路求值可以避免不必要的计算
750
+
751
+ ```typescript
752
+ compile(expression, variables, { shortCircuit: true });
753
+ ```
754
+
755
+ 3. **利用自动内联**:编译器会自动内联只引用一次的子表达式,无需手动优化
756
+
757
+ 4. **优先使用 Proxy 链式调用**:对于对象属性访问,使用 `config.timeout` 比 `expr({ config })("config.timeout")` 更简洁且类型更安全
310
758
 
311
759
  ## 项目结构
312
760
 
313
761
  ```
314
762
  src/
315
- ├── index.ts # 导出入口
316
- ├── variable.ts # variable 函数实现
317
- ├── expr.ts # expr 函数实现
318
- ├── compile.ts # compile 函数实现
319
- ├── evaluate.ts # evaluate 函数实现
320
- ├── parser.ts # 表达式解析器
321
- ├── type-parser.ts # 类型解析器
322
- ├── types.ts # 类型定义
323
- └── *.test.ts # 测试文件
763
+ ├── index.ts # 导出入口
764
+ ├── variable.ts # variable<T>() 函数
765
+ ├── expr.ts # expr() 函数
766
+ ├── template.ts # t() 标签模板函数
767
+ ├── lambda.ts # lambda() 函数(数组方法支持)
768
+ ├── compile.ts # 编译器(内联优化、短路求值)
769
+ ├── evaluate.ts # 运行时求值
770
+ ├── parser.ts # 表达式 AST 解析器
771
+ ├── type-parser.ts # TypeScript 类型级表达式解析
772
+ ├── proxy-variable.ts # Proxy 变量实现
773
+ ├── proxy-metadata.ts # Proxy 元数据管理
774
+ └── types.ts # 类型定义(Variable、Expression、Lambda 等)
324
775
  ```
325
776
 
326
777
  ## 开发