@codehz/json-expr 0.5.0 → 0.5.2

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
@@ -28,7 +28,7 @@ bun install @codehz/json-expr
28
28
  ### 基本用法
29
29
 
30
30
  ```typescript
31
- import { variable, expr, compile, evaluate, t, lambda } from "@codehz/json-expr";
31
+ import { variable, expr, compile, evaluate, t, lambda, wrap } from "@codehz/json-expr";
32
32
 
33
33
  // 定义类型化变量(使用 TypeScript 泛型)
34
34
  const x = variable<number>();
@@ -54,6 +54,11 @@ const greeting = t`Hello, ${name}!`;
54
54
  // 使用 lambda 表达式
55
55
  const numbers = variable<number[]>();
56
56
  const doubled = numbers.map(lambda<[number], number>((n) => expr({ n })("n * 2")));
57
+
58
+ // 使用 wrap 包装静态值
59
+ const pattern = wrap(/^[a-z]+$/i);
60
+ const input = variable<string>();
61
+ const isValid = pattern.test(input);
57
62
  ```
58
63
 
59
64
  ## 核心概念
@@ -260,8 +265,152 @@ const multiplier = variable<number>();
260
265
  const scaled = numbers.map(lambda<[number], number>((n) => expr({ n, multiplier })("n * multiplier")));
261
266
  ```
262
267
 
268
+ ### `wrap<T>(value: T): Proxify<T>`
269
+
270
+ 将静态值包装为 Proxy Expression,使其可以像 Variable 一样调用方法和访问属性。
271
+
272
+ **参数:**
273
+
274
+ - `value` - 要包装的静态值(支持原始值、对象、数组、Date、RegExp、BigInt、URL、Map、Set、TypedArray 等)
275
+
276
+ **返回值:** Proxy Expression,可以继续链式调用
277
+
278
+ **示例:**
279
+
280
+ ```typescript
281
+ // 包装 RegExp
282
+ const pattern = wrap(/^[a-z]+$/i);
283
+ const input = variable<string>();
284
+ const isValid = pattern.test(input);
285
+
286
+ const compiled = compile(isValid, { input });
287
+ evaluate(compiled, { input: "hello" }); // => true
288
+ evaluate(compiled, { input: "hello123" }); // => false
289
+
290
+ // 包装 Date
291
+ const now = wrap(new Date("2024-01-01"));
292
+ const year = now.getFullYear();
293
+
294
+ // 包装数组
295
+ const staticNumbers = wrap([1, 2, 3, 4, 5]);
296
+ const x = variable<number>();
297
+ const doubled = staticNumbers.map(lambda((n: number) => expr({ n, x })("n * x")));
298
+
299
+ // 包装对象
300
+ const config = wrap({ port: 8080, host: "localhost" });
301
+ const port = config.port; // 直接访问属性
302
+
303
+ // 包装 Map
304
+ const map = wrap(
305
+ new Map([
306
+ ["a", 1],
307
+ ["b", 2],
308
+ ])
309
+ );
310
+ const key = variable<string>();
311
+ const value = map.get(key);
312
+
313
+ // 链式调用
314
+ const text = wrap(" hello world ");
315
+ const result = text.trim().toUpperCase().replace("HELLO", "HI");
316
+ // => "HI WORLD"
317
+ ```
318
+
263
319
  ## 高级用法
264
320
 
321
+ ### 包装静态值(wrap)
322
+
323
+ `wrap()` 函数可以将任意静态值转换为 Proxy Expression,使其可以像 Variable 一样调用方法和访问属性。这在需要对常量值执行操作时非常有用。
324
+
325
+ **基本用法:**
326
+
327
+ ```typescript
328
+ // 不使用 wrap(传统方式)
329
+ interface Validator {
330
+ match(text: string, pattern: RegExp): boolean;
331
+ }
332
+ const validator = variable<Validator>();
333
+ const result = validator.match("hello", /^[a-z]+$/i);
334
+
335
+ // 使用 wrap(推荐方式)
336
+ const pattern = wrap(/^[a-z]+$/i);
337
+ const input = variable<string>();
338
+ const result = pattern.test(input);
339
+ ```
340
+
341
+ **支持的类型:**
342
+
343
+ ```typescript
344
+ // 原始值
345
+ const num = wrap(42);
346
+ const str = wrap("hello");
347
+ const bool = wrap(true);
348
+
349
+ // Date 和 RegExp
350
+ const date = wrap(new Date("2024-01-01"));
351
+ const year = date.getFullYear();
352
+
353
+ const regex = wrap(/\d+/g);
354
+ const text = variable<string>();
355
+ const matches = text.match(regex);
356
+
357
+ // BigInt
358
+ const bigNum = wrap(123456789n);
359
+ const x = variable<bigint>();
360
+ const sum = expr({ bigNum, x })("bigNum + x");
361
+
362
+ // URL
363
+ const url = wrap(new URL("https://example.com/path"));
364
+ const host = url.hostname;
365
+ const port = url.port;
366
+
367
+ // Map 和 Set
368
+ const map = wrap(
369
+ new Map([
370
+ ["key1", 100],
371
+ ["key2", 200],
372
+ ])
373
+ );
374
+ const key = variable<string>();
375
+ const value = map.get(key);
376
+
377
+ const set = wrap(new Set([1, 2, 3]));
378
+ const num = variable<number>();
379
+ const has = set.has(num);
380
+
381
+ // TypedArray
382
+ const arr = wrap(new Uint8Array([10, 20, 30]));
383
+ const index = variable<number>();
384
+ const value = expr({ arr, index })("arr[index]");
385
+
386
+ // 数组和对象
387
+ const numbers = wrap([1, 2, 3, 4, 5]);
388
+ const multiplier = variable<number>();
389
+ const scaled = numbers.map(lambda((n: number) => expr({ n, multiplier })("n * multiplier")));
390
+
391
+ const config = wrap({ port: 8080, host: "localhost" });
392
+ const port = config.port;
393
+ ```
394
+
395
+ **链式调用:**
396
+
397
+ ```typescript
398
+ const text = wrap(" Hello, World! ");
399
+ const result = text.trim().toLowerCase().replace("world", "universe");
400
+ // => "hello, universe!"
401
+ ```
402
+
403
+ **与 variable 结合:**
404
+
405
+ ```typescript
406
+ const staticData = wrap({ users: ["alice", "bob", "charlie"] });
407
+ const index = variable<number>();
408
+ const username = expr({ staticData, index })("staticData.users[index]");
409
+
410
+ const compiled = compile(username, { index });
411
+ evaluate(compiled, { index: 1 }); // => "bob"
412
+ ```
413
+
265
414
  ### Proxy 变量系统
266
415
 
267
416
  `variable()` 创建的变量是 Proxy 对象,支持链式属性访问和方法调用,所有操作都会自动转换为表达式。
package/dist/index.d.mts CHANGED
@@ -15,6 +15,45 @@ type ProxifyArgs<T extends unknown[]> = { [K in keyof T]: T[K] | Proxify<T[K]> }
15
15
  * 需要特殊处理的数组方法名(有泛型参数,需要显式定义以保留类型推导)
16
16
  */
17
17
  type ProxifiedArrayMethods = "map" | "flatMap" | "filter" | "reduce" | "reduceRight" | "find" | "findIndex" | "findLast" | "findLastIndex" | "every" | "some" | "forEach" | "toSorted" | "sort";
18
+ /**
19
+ * 字符串类型的 Proxify 版本
20
+ * 将所有字符串方法返回值包装为 Proxify
21
+ * 参数允许为 Proxy 或原始值
22
+ */
23
+ type ProxifiedString = {
24
+ charAt(pos: number | Proxify<number>): Proxify<string>;
25
+ charCodeAt(index: number | Proxify<number>): Proxify<number>;
26
+ concat(...strings: (string | Proxify<string>)[]): Proxify<string>;
27
+ indexOf(searchString: string | Proxify<string>, position?: number | Proxify<number>): Proxify<number>;
28
+ lastIndexOf(searchString: string | Proxify<string>, position?: number | Proxify<number>): Proxify<number>;
29
+ localeCompare(that: string | Proxify<string>): Proxify<number>;
30
+ match(regexp: string | RegExp | Proxify<string> | Proxify<RegExp>): Proxify<RegExpMatchArray | null>;
31
+ replace(searchValue: string | RegExp | Proxify<string> | Proxify<RegExp>, replaceValue: string | Proxify<string> | Proxify<(substring: string, ...args: unknown[]) => string>): Proxify<string>;
32
+ replaceAll(searchValue: string | RegExp | Proxify<string> | Proxify<RegExp>, replaceValue: string | Proxify<string> | Proxify<(substring: string, ...args: unknown[]) => string>): Proxify<string>;
33
+ search(regexp: string | RegExp | Proxify<string> | Proxify<RegExp>): Proxify<number>;
34
+ slice(start?: number | Proxify<number>, end?: number | Proxify<number>): Proxify<string>;
35
+ split(separator: string | RegExp | Proxify<string> | Proxify<RegExp>, limit?: number | Proxify<number>): Proxify<string[]>;
36
+ substring(start: number | Proxify<number>, end?: number | Proxify<number>): Proxify<string>;
37
+ toLowerCase(): Proxify<string>;
38
+ toLocaleLowerCase(): Proxify<string>;
39
+ toUpperCase(): Proxify<string>;
40
+ toLocaleUpperCase(): Proxify<string>;
41
+ trim(): Proxify<string>;
42
+ trimStart(): Proxify<string>;
43
+ trimEnd(): Proxify<string>;
44
+ padStart(maxLength: number | Proxify<number>, fillString?: string | Proxify<string>): Proxify<string>;
45
+ padEnd(maxLength: number | Proxify<number>, fillString?: string | Proxify<string>): Proxify<string>;
46
+ repeat(count: number | Proxify<number>): Proxify<string>;
47
+ startsWith(searchString: string | Proxify<string>, position?: number | Proxify<number>): Proxify<boolean>;
48
+ endsWith(searchString: string | Proxify<string>, endPosition?: number | Proxify<number>): Proxify<boolean>;
49
+ includes(searchString: string | Proxify<string>, position?: number | Proxify<number>): Proxify<boolean>;
50
+ at(index: number | Proxify<number>): Proxify<string | undefined>;
51
+ codePointAt(pos: number | Proxify<number>): Proxify<number | undefined>;
52
+ normalize(form?: string | Proxify<string>): Proxify<string>;
53
+ matchAll(regexp: RegExp | Proxify<RegExp>): Proxify<IterableIterator<RegExpMatchArray>>;
54
+ readonly length: Proxify<number>;
55
+ [key: string]: unknown;
56
+ };
18
57
  /**
19
58
  * 数组类型的 Proxify 版本
20
59
  * 特殊处理泛型方法(map, filter 等),确保返回值类型正确
@@ -45,11 +84,12 @@ type ProxifiedArray<T> = {
45
84
  * 将类型 T 转换为 Proxy 包装类型
46
85
  * - 始终包含 ProxyExpression<T> 标记,用于 compile 函数类型检查
47
86
  * - 函数类型:保持函数签名,但参数允许 Proxy 或原始值,返回值递归应用 Proxify
87
+ * - 字符串类型:使用 ProxifiedString 特殊处理字符串方法
48
88
  * - 数组类型:使用 ProxifiedArray 特殊处理泛型方法
49
89
  * - 对象类型:映射所有属性为 Proxify
50
90
  * - 原始类型:保持不变(返回 ProxyExpression 包装)
51
91
  */
52
- type Proxify<T> = ProxyExpression<T> & (T extends ((...args: infer Args) => infer R) ? (...args: ProxifyArgs<Args>) => Proxify<R> : T extends readonly (infer E)[] ? ProxifiedArray<E> : T extends object ? { [K in keyof T]: Proxify<T[K]> } : unknown);
92
+ type Proxify<T> = ProxyExpression<T> & (T extends string ? ProxifiedString : T extends ((...args: infer Args) => infer R) ? (...args: ProxifyArgs<Args>) => Proxify<R> : T extends readonly (infer E)[] ? ProxifiedArray<E> : T extends object ? { [K in keyof T]: Proxify<T[K]> } : unknown);
53
93
  /**
54
94
  * Variable 类型定义
55
95
  * 总是返回 Proxy 包装后的类型
@@ -234,7 +274,7 @@ declare function compile<TResult>(expression: LambdaBodyResult<TResult>, variabl
234
274
  * // => 6 (3 * 2)
235
275
  * ```
236
276
  */
237
- declare function evaluate<TResult>(data: CompiledData, values: Record<string, unknown>): TResult;
277
+ declare function evaluate<TResult = unknown>(data: CompiledData, values: Record<string, unknown>): TResult;
238
278
  //#endregion
239
279
  //#region src/type-parser.d.ts
240
280
  /** 去除字符串两端空白 */
@@ -510,5 +550,32 @@ declare function variable<T>(): Variable<T>;
510
550
  */
511
551
  declare function getVariableId(variable: unknown): symbol | undefined;
512
552
  //#endregion
513
- export { type BranchNode, type CompileContext, type CompileOptions, type CompiledData, type CompiledExpression, type ContextTypeMap, type ControlFlowNode, type ExprNode, type Expression, type ExpressionType, type ExtractType, type FilterCallback, type FindCallback, type InferContextType, type InferExpressionResult, type InferExpressionType, type InferLambdaArgs, type InferLambdaReturn, type InferVariableType, type JumpNode, type Lambda, type LambdaBuilder, type LambdaParam, type MapCallback, type ParseExpression, type PhiNode, type Proxify, type ProxyExpression, type ReduceCallback, type SortCallback, type ValidateExpression, type Variable, compile, evaluate, expr, getVariableId, isProxy, isProxyExpression, isProxyVariable, lambda, t, variable };
553
+ //#region src/wrap.d.ts
554
+ /**
555
+ * 将静态值包装为 Proxy Expression
556
+ * 返回的 Proxy 可以像 Variable 一样调用方法和访问属性
557
+ *
558
+ * @template T - 值的类型
559
+ * @param value - 要包装的静态值(支持原始值、对象、数组、Date、RegExp 等)
560
+ * @returns Proxy Expression,可以继续链式调用
561
+ *
562
+ * @example
563
+ * ```ts
564
+ * // 包装 RegExp
565
+ * const pattern = wrap(/^[a-z]+$/i);
566
+ * const input = variable<string>();
567
+ * const result = pattern.match(input);
568
+ *
569
+ * // 包装 Date
570
+ * const now = wrap(new Date());
571
+ * const year = now.getFullYear();
572
+ *
573
+ * // 包装数组
574
+ * const numbers = wrap([1, 2, 3, 4, 5]);
575
+ * const doubled = numbers.map((x) => x * 2);
576
+ * ```
577
+ */
578
+ declare function wrap<T>(value: T): Proxify<T>;
579
+ //#endregion
580
+ export { type BranchNode, type CompileContext, type CompileOptions, type CompiledData, type CompiledExpression, type ContextTypeMap, type ControlFlowNode, type ExprNode, type Expression, type ExpressionType, type ExtractType, type FilterCallback, type FindCallback, type InferContextType, type InferExpressionResult, type InferExpressionType, type InferLambdaArgs, type InferLambdaReturn, type InferVariableType, type JumpNode, type Lambda, type LambdaBuilder, type LambdaParam, type MapCallback, type ParseExpression, type PhiNode, type Proxify, type ProxyExpression, type ReduceCallback, type SortCallback, type ValidateExpression, type Variable, compile, evaluate, expr, getVariableId, isProxy, isProxyExpression, isProxyVariable, lambda, t, variable, wrap };
514
581
  //# sourceMappingURL=index.d.mts.map