@codehz/json-expr 0.0.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/LICENSE +21 -0
- package/README.md +325 -0
- package/dist/index.d.mts +365 -0
- package/dist/index.mjs +981 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +61 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CodeHz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
# @codehz/json-expr
|
|
2
|
+
|
|
3
|
+
一个可序列化为 JSON 的表达式 DSL 库,提供类型安全的表达式构建、编译和求值。
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@codehz/json-expr)
|
|
6
|
+
|
|
7
|
+
## 特性
|
|
8
|
+
|
|
9
|
+
- 🎯 **类型安全** - 使用 TypeScript 和 Zod 进行完整的类型推导和验证
|
|
10
|
+
- 📦 **可序列化** - 编译后的表达式为纯 JSON 格式,易于传输和存储
|
|
11
|
+
- 🔧 **灵活的表达式** - 支持任意 JavaScript 表达式,包括函数调用和对象属性访问
|
|
12
|
+
- ⚡ **高性能** - 使用 `new Function()` 进行优化执行
|
|
13
|
+
- 🧩 **可组合** - 表达式可以相互组合,形成复杂的计算树
|
|
14
|
+
- 🔐 **类型验证** - 运行时通过 Zod schema 进行数据验证
|
|
15
|
+
|
|
16
|
+
## 快速开始
|
|
17
|
+
|
|
18
|
+
### 安装
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
bun install @codehz/json-expr
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 基本用法
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { z } from "zod";
|
|
28
|
+
import { variable, expr, compile, evaluate } from "@codehz/json-expr";
|
|
29
|
+
|
|
30
|
+
// 定义类型化变量
|
|
31
|
+
const x = variable(z.number());
|
|
32
|
+
const y = variable(z.number());
|
|
33
|
+
|
|
34
|
+
// 构建表达式
|
|
35
|
+
const sum = expr({ x, y })("x + y");
|
|
36
|
+
const product = expr({ x, y })("x * y");
|
|
37
|
+
const result = expr({ sum, product })("sum + product");
|
|
38
|
+
|
|
39
|
+
// 编译表达式(可序列化为 JSON)
|
|
40
|
+
const compiled = compile(result, { x, y });
|
|
41
|
+
// => [["x", "y"], "$0+$1", "$0*$1", "$2+$3"]
|
|
42
|
+
|
|
43
|
+
// 执行编译后的表达式
|
|
44
|
+
const value = evaluate(compiled, { x: 2, y: 3 });
|
|
45
|
+
// => 11 (2+3 + 2*3 = 5 + 6 = 11)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 核心概念
|
|
49
|
+
|
|
50
|
+
### Variable(变量)
|
|
51
|
+
|
|
52
|
+
变量是表达式中的占位符,通过 Zod schema 定义其类型和验证规则。
|
|
53
|
+
|
|
54
|
+
```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
|
+
);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Expression(表达式)
|
|
66
|
+
|
|
67
|
+
表达式对变量或其他表达式进行运算,使用字符串形式描述。
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
const x = variable(z.number());
|
|
71
|
+
const y = variable(z.number());
|
|
72
|
+
|
|
73
|
+
// 简单表达式
|
|
74
|
+
const sum = expr({ x, y })("x + y");
|
|
75
|
+
|
|
76
|
+
// 复杂表达式(可以使用 JS 语言特性)
|
|
77
|
+
const abs = expr({ x })("Math.abs(x)");
|
|
78
|
+
const conditional = expr({ x, y })("x > y ? x : y");
|
|
79
|
+
const array = expr({ x, y })("[x, y].filter(v => v > 0)");
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### CompiledData(编译数据)
|
|
83
|
+
|
|
84
|
+
编译后的表达式为 JSON 数组格式:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
// 格式: [variableNames, expression1, expression2, ...]
|
|
88
|
+
// 其中 $N 用于引用之前的变量或表达式
|
|
89
|
+
|
|
90
|
+
const compiled = compile(result, { x, y });
|
|
91
|
+
// [["x", "y"], "$0+$1", "$0*$1", "$2+$3"]
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## API 参考
|
|
95
|
+
|
|
96
|
+
### `variable<T>(schema: T): Variable<T>`
|
|
97
|
+
|
|
98
|
+
创建一个类型化变量。
|
|
99
|
+
|
|
100
|
+
**参数:**
|
|
101
|
+
|
|
102
|
+
- `schema` - Zod schema,定义变量的类型和验证规则
|
|
103
|
+
|
|
104
|
+
**返回值:** Variable 对象
|
|
105
|
+
|
|
106
|
+
**示例:**
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
const num = variable(z.number());
|
|
110
|
+
const str = variable(z.string());
|
|
111
|
+
const date = variable(z.date());
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### `expr<TContext>(context: TContext): (source: string) => Expression<TContext, TResult>`
|
|
115
|
+
|
|
116
|
+
创建表达式,采用柯里化设计以支持完整的类型推导。
|
|
117
|
+
|
|
118
|
+
**参数:**
|
|
119
|
+
|
|
120
|
+
- `context` - 上下文对象,包含变量和/或其他表达式的映射
|
|
121
|
+
|
|
122
|
+
**返回值:** 函数,接收表达式源码字符串并返回 Expression 对象
|
|
123
|
+
|
|
124
|
+
**示例:**
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
const x = variable(z.number());
|
|
128
|
+
const y = variable(z.number());
|
|
129
|
+
|
|
130
|
+
const sum = expr({ x, y })("x + y");
|
|
131
|
+
const result = expr({ sum, x })("sum * x");
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### `compile<TResult>(expression: Expression<any, TResult>, variables: Record<string, Variable<any>>, options?: CompileOptions): CompiledData`
|
|
135
|
+
|
|
136
|
+
将表达式树编译为可序列化的 JSON 结构。
|
|
137
|
+
|
|
138
|
+
**参数:**
|
|
139
|
+
|
|
140
|
+
- `expression` - 要编译的表达式
|
|
141
|
+
- `variables` - 表达式中使用的所有变量映射
|
|
142
|
+
- `options` - 编译选项(可选)
|
|
143
|
+
- `optimize?: boolean` - 是否进行优化(默认:false)
|
|
144
|
+
|
|
145
|
+
**返回值:** CompiledData 数组
|
|
146
|
+
|
|
147
|
+
**示例:**
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
const x = variable(z.number());
|
|
151
|
+
const y = variable(z.number());
|
|
152
|
+
const sum = expr({ x, y })("x + y");
|
|
153
|
+
const product = expr({ x, y })("x * y");
|
|
154
|
+
const result = expr({ sum, product })("sum + product");
|
|
155
|
+
|
|
156
|
+
const compiled = compile(result, { x, y });
|
|
157
|
+
// [["x", "y"], "$0+$1", "$0*$1", "$2+$3"]
|
|
158
|
+
|
|
159
|
+
// 使用优化选项
|
|
160
|
+
const optimized = compile(result, { x, y }, { optimize: true });
|
|
161
|
+
// [["x", "y"], "($0+$1)+($0*$1)"]
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### `evaluate<TResult>(data: CompiledData, values: Record<string, unknown>): TResult`
|
|
165
|
+
|
|
166
|
+
执行编译后的表达式。
|
|
167
|
+
|
|
168
|
+
**参数:**
|
|
169
|
+
|
|
170
|
+
- `data` - 编译后的表达式数据
|
|
171
|
+
- `values` - 变量值映射,对应编译数据中的变量名顺序
|
|
172
|
+
|
|
173
|
+
**返回值:** 表达式计算结果
|
|
174
|
+
|
|
175
|
+
**示例:**
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
const compiled = compile(result, { x, y });
|
|
179
|
+
const value = evaluate(compiled, { x: 5, y: 3 });
|
|
180
|
+
// => 23 ((5+3) + (5*3) = 8 + 15 = 23)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## 高级用法
|
|
184
|
+
|
|
185
|
+
### 传入对象和内置对象
|
|
186
|
+
|
|
187
|
+
支持在上下文中传入对象(如 Math)以在表达式中访问其属性和方法:
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
const x = variable(z.number());
|
|
191
|
+
|
|
192
|
+
const sqrtExpr = expr({ x, Math: variable(z.any()) })("Math.sqrt(x)");
|
|
193
|
+
const compiled = compile(sqrtExpr, { x, Math: variable(z.any()) });
|
|
194
|
+
const result = evaluate(compiled, { x: 16, Math });
|
|
195
|
+
// => 4
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### 条件表达式
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
const score = variable(z.number());
|
|
202
|
+
const gradeExpr = expr({ score })("score >= 90 ? 'A' : score >= 80 ? 'B' : score >= 70 ? 'C' : 'F'");
|
|
203
|
+
|
|
204
|
+
const compiled = compile(gradeExpr, { score });
|
|
205
|
+
const grade = evaluate(compiled, { score: 85 });
|
|
206
|
+
// => "B"
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### 数组和对象操作
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
const numbers = variable(z.array(z.number()));
|
|
213
|
+
|
|
214
|
+
const sumExpr = expr({ numbers })("numbers.reduce((a, b) => a + b, 0)");
|
|
215
|
+
|
|
216
|
+
const compiled = compile(sumExpr, { numbers });
|
|
217
|
+
const sum = evaluate(compiled, { numbers: [1, 2, 3, 4, 5] });
|
|
218
|
+
// => 15
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### 链式表达式组合
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
const a = variable(z.number());
|
|
225
|
+
const b = variable(z.number());
|
|
226
|
+
|
|
227
|
+
const sum = expr({ a, b })("a + b");
|
|
228
|
+
const product = expr({ a, b })("a * b");
|
|
229
|
+
const difference = expr({ a, b })("a - b");
|
|
230
|
+
|
|
231
|
+
const complex = expr({ sum, product, difference })("sum * product - difference");
|
|
232
|
+
|
|
233
|
+
const compiled = compile(complex, { a, b });
|
|
234
|
+
const result = evaluate(compiled, { a: 2, b: 3 });
|
|
235
|
+
// => (2+3) * (2*3) - (2-3) = 5 * 6 - (-1) = 30 + 1 = 31
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## 序列化和传输
|
|
239
|
+
|
|
240
|
+
编译后的数据可以轻松进行 JSON 序列化,适合网络传输或持久化存储:
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
// 编译表达式
|
|
244
|
+
const compiled = compile(result, { x, y });
|
|
245
|
+
|
|
246
|
+
// 序列化
|
|
247
|
+
const json = JSON.stringify(compiled);
|
|
248
|
+
// "[["x","y"],"$0+$1","$0*$1","$2+$3"]"
|
|
249
|
+
|
|
250
|
+
// 存储或传输...
|
|
251
|
+
|
|
252
|
+
// 反序列化
|
|
253
|
+
const deserialized = JSON.parse(json);
|
|
254
|
+
|
|
255
|
+
// 执行
|
|
256
|
+
const value = evaluate(deserialized, { x: 5, y: 3 });
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## 类型安全
|
|
260
|
+
|
|
261
|
+
项目充分利用 TypeScript 的类型系统进行编译时检查和类型推导:
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
const x = variable(z.number());
|
|
265
|
+
const y = variable(z.string());
|
|
266
|
+
|
|
267
|
+
// 提供完整的类型推导和自动补全
|
|
268
|
+
const sum = expr({ x, y })("x + y");
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## 性能考虑
|
|
272
|
+
|
|
273
|
+
- **编译时间**:编译过程涉及依赖分析和拓扑排序,通常快速完成
|
|
274
|
+
- **执行时间**:表达式通过 `new Function()` 编译为原生 JavaScript,执行性能接近原生代码
|
|
275
|
+
- **内存占用**:编译数据为纯 JSON,占用空间小,适合在网络上传输
|
|
276
|
+
|
|
277
|
+
## 项目结构
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
src/
|
|
281
|
+
├── index.ts # 导出入口
|
|
282
|
+
├── variable.ts # variable 函数实现
|
|
283
|
+
├── expr.ts # expr 函数实现
|
|
284
|
+
├── compile.ts # compile 函数实现
|
|
285
|
+
├── evaluate.ts # evaluate 函数实现
|
|
286
|
+
├── parser.ts # 表达式解析器
|
|
287
|
+
├── type-parser.ts # 类型解析器
|
|
288
|
+
├── types.ts # 类型定义
|
|
289
|
+
└── *.test.ts # 测试文件
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
## 开发
|
|
293
|
+
|
|
294
|
+
### 安装依赖
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
bun install
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### 运行测试
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
bun test
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### 代码检查
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
bun run lint
|
|
310
|
+
bun run type-check
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### 代码格式化
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
bun run format
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
## 许可证
|
|
320
|
+
|
|
321
|
+
MIT
|
|
322
|
+
|
|
323
|
+
## 贡献
|
|
324
|
+
|
|
325
|
+
欢迎提交 Issue 和 Pull Request!
|