@shwfed/config 2.2.2 → 2.2.4
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/dist/module.json +1 -1
- package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.form/schema.d.ts +5 -2
- package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/schema.d.ts +5 -2
- package/dist/runtime/components/form/schema.d.ts +5 -2
- package/dist/runtime/components/form/schema.js +30 -20
- package/dist/runtime/components/table/schema.d.ts +5 -2
- package/dist/runtime/components/ui/date-picker/DatePicker.vue +0 -1
- package/dist/runtime/vendor/cel-js/CLAUDE.md +3 -0
- package/dist/runtime/vendor/cel-js/PROMPT.md +14 -0
- package/dist/runtime/vendor/cel-js/lib/evaluator.js +2 -0
- package/dist/runtime/vendor/cel-js/lib/json-builtins.d.ts +2 -0
- package/dist/runtime/vendor/cel-js/lib/json-builtins.js +51 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -80,10 +80,13 @@ export declare function schema(configure: (env: Environment) => void, _blockRef:
|
|
|
80
80
|
}>;
|
|
81
81
|
}>>>;
|
|
82
82
|
kind: Schema.tag<"shwfed.component.form">;
|
|
83
|
-
initial: Schema.optional<Schema.Struct<{
|
|
83
|
+
initial: Schema.optional<Schema.transform<Schema.Union<[Schema.Schema<string, string, never>, Schema.Struct<{
|
|
84
84
|
request: Schema.optional<Schema.Schema<string, string, never>>;
|
|
85
85
|
data: Schema.Schema<string, string, never>;
|
|
86
|
-
}
|
|
86
|
+
}>]>, Schema.Struct<{
|
|
87
|
+
request: Schema.optional<Schema.Schema<string, string, never>>;
|
|
88
|
+
data: Schema.Schema<string, string, never>;
|
|
89
|
+
}>>>;
|
|
87
90
|
readonly: Schema.optional<Schema.Schema<string, string, never>>;
|
|
88
91
|
}>>;
|
|
89
92
|
}>;
|
|
@@ -347,10 +347,13 @@ export declare function schema(configure: (env: Environment) => void, _blockRef:
|
|
|
347
347
|
}>;
|
|
348
348
|
}>>>;
|
|
349
349
|
kind: Schema.tag<"shwfed.component.form">;
|
|
350
|
-
initial: Schema.optional<Schema.Struct<{
|
|
350
|
+
initial: Schema.optional<Schema.transform<Schema.Union<[Schema.Schema<string, string, never>, Schema.Struct<{
|
|
351
351
|
request: Schema.optional<Schema.Schema<string, string, never>>;
|
|
352
352
|
data: Schema.Schema<string, string, never>;
|
|
353
|
-
}
|
|
353
|
+
}>]>, Schema.Struct<{
|
|
354
|
+
request: Schema.optional<Schema.Schema<string, string, never>>;
|
|
355
|
+
data: Schema.Schema<string, string, never>;
|
|
356
|
+
}>>>;
|
|
354
357
|
readonly: Schema.optional<Schema.Schema<string, string, never>>;
|
|
355
358
|
}>>>;
|
|
356
359
|
cellStyle: Schema.optional<Schema.Schema<string, string, never>>;
|
|
@@ -138,10 +138,13 @@ export declare function FormConfig(configure: (env: Environment) => void): Schem
|
|
|
138
138
|
}>;
|
|
139
139
|
}>>>;
|
|
140
140
|
kind: Schema.tag<"shwfed.component.form">;
|
|
141
|
-
initial: Schema.optional<Schema.Struct<{
|
|
141
|
+
initial: Schema.optional<Schema.transform<Schema.Union<[Schema.Schema<string, string, never>, Schema.Struct<{
|
|
142
142
|
request: Schema.optional<Schema.Schema<string, string, never>>;
|
|
143
143
|
data: Schema.Schema<string, string, never>;
|
|
144
|
-
}
|
|
144
|
+
}>]>, Schema.Struct<{
|
|
145
|
+
request: Schema.optional<Schema.Schema<string, string, never>>;
|
|
146
|
+
data: Schema.Schema<string, string, never>;
|
|
147
|
+
}>>>;
|
|
145
148
|
readonly: Schema.optional<Schema.Schema<string, string, never>>;
|
|
146
149
|
}>>;
|
|
147
150
|
export declare function createFormConfig(body: Omit<Schema.Schema.Type<ReturnType<typeof FormConfig>>, 'kind'>): {
|
|
@@ -58,30 +58,40 @@ export function FormConfig(configure) {
|
|
|
58
58
|
resultType: "dyn"
|
|
59
59
|
});
|
|
60
60
|
const CelFormReadonly = Expression({ configure: formConfigure, resultType: "bool" });
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
description: md`
|
|
67
|
-
可选的 HTTP 请求表达式:返回 \`HttpRequest\`,运行时由宿主发起,并把响应体作为 \`json\` 传给「数据」表达式。
|
|
61
|
+
const InitialStruct = Schema.Struct({
|
|
62
|
+
request: Schema.optional(CelInitialRequest.annotations({
|
|
63
|
+
title: "\u8BF7\u6C42",
|
|
64
|
+
description: md`
|
|
65
|
+
可选的 HTTP 请求表达式:返回 \`HttpRequest\`,运行时由宿主发起,并把响应体作为 \`json\` 传给「数据」表达式。
|
|
68
66
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
67
|
+
留空时「数据」直接对 CEL 上下文求值(静态默认值,或引用 \`form\` 的表达式)。
|
|
68
|
+
`
|
|
69
|
+
})),
|
|
70
|
+
data: CelInitialData.annotations({
|
|
71
|
+
title: "\u6570\u636E",
|
|
72
|
+
description: md`
|
|
73
|
+
返回整个表单初始值的 CEL 表达式(应为一个对象):
|
|
76
74
|
|
|
77
|
-
|
|
75
|
+
- 可以互相依赖,但应避免循环引用。考虑一个含「用户名」与「用户角色」的表单:可默认填入当前登入人的用户名,再以此为依据填入其默认角色。
|
|
78
76
|
|
|
79
|
-
|
|
77
|
+
- 配置了「请求」时,可通过 \`json\` 引用响应体,例如 \`json.?data\`。
|
|
80
78
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
- 如果配置了初始值,重置这个表单将**重置为其初始值,而非空**。
|
|
80
|
+
`
|
|
81
|
+
})
|
|
82
|
+
});
|
|
83
|
+
const Initial = Schema.transform(
|
|
84
|
+
Schema.Union(CelInitialData, InitialStruct),
|
|
85
|
+
InitialStruct,
|
|
86
|
+
{
|
|
87
|
+
strict: true,
|
|
88
|
+
decode: (input) => typeof input === "string" ? { data: input } : input,
|
|
89
|
+
encode: (output) => output
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
return Schema.Struct({
|
|
93
|
+
kind: Schema.tag(KIND),
|
|
94
|
+
initial: Schema.optional(Initial.annotations({
|
|
85
95
|
title: "\u521D\u59CB\u503C",
|
|
86
96
|
description: "\u8868\u5355\u521D\u59CB\u503C\u7684\u6765\u6E90\uFF1A\u53EF\u9009\u7684 HTTP \u8BF7\u6C42\uFF0C\u52A0\u4E00\u4E2A\u8FD4\u56DE\u521D\u59CB\u503C\u5BF9\u8C61\u7684 CEL \u8868\u8FBE\u5F0F"
|
|
87
97
|
})),
|
|
@@ -432,10 +432,13 @@ export declare function TableConfig(configure: (env: Environment) => void): Sche
|
|
|
432
432
|
}>;
|
|
433
433
|
}>>>;
|
|
434
434
|
kind: Schema.tag<"shwfed.component.form">;
|
|
435
|
-
initial: Schema.optional<Schema.Struct<{
|
|
435
|
+
initial: Schema.optional<Schema.transform<Schema.Union<[Schema.Schema<string, string, never>, Schema.Struct<{
|
|
436
436
|
request: Schema.optional<Schema.Schema<string, string, never>>;
|
|
437
437
|
data: Schema.Schema<string, string, never>;
|
|
438
|
-
}
|
|
438
|
+
}>]>, Schema.Struct<{
|
|
439
|
+
request: Schema.optional<Schema.Schema<string, string, never>>;
|
|
440
|
+
data: Schema.Schema<string, string, never>;
|
|
441
|
+
}>>>;
|
|
439
442
|
readonly: Schema.optional<Schema.Schema<string, string, never>>;
|
|
440
443
|
}>>>;
|
|
441
444
|
cellStyle: Schema.optional<Schema.Schema<string, string, never>>;
|
|
@@ -214,7 +214,6 @@ function applyShortcut(index) {
|
|
|
214
214
|
<PopoverContent
|
|
215
215
|
align="start"
|
|
216
216
|
:class="cn('w-auto p-0', props.popoverClass)"
|
|
217
|
-
:style="{ minWidth: 'var(--reka-popover-trigger-width)' }"
|
|
218
217
|
@open-auto-focus="(event) => event.preventDefault()"
|
|
219
218
|
@interact-outside="onInteractOutside"
|
|
220
219
|
>
|
|
@@ -22,6 +22,8 @@ The custom `Optional` class has been replaced with Effect's `Option` type (`impo
|
|
|
22
22
|
|
|
23
23
|
An `http` built-in has been added (`http-builtins.ts`, `http-builder.ts`) — not from upstream. It registers the `http` constant and the `http` / `HttpRequest` types on `globalRegistry`, so `http.get(url).header(...).body(...)` expressions type-check and evaluate in every `Environment`. A CEL expression only builds an `HttpRequestBuilder` — a pure description of a request; it never issues one. Both terminal methods, `.json()` and `.file()`, are dispatched by the host on the returned builder (neither is a CEL method), so expression evaluation stays free of IO. Endpoints must be absolute URLs — there is no base-URL resolution. Depends on `fx-fetch`. The host can register process-wide default headers via `HttpRequestBuilder.setDefaultHeader(name, valueOrGetter)` / `clearDefaultHeader(name)`; they are merged in at `#buildRequest()` time, with case-insensitive precedence to an explicit `.header(...)` on the builder. A getter that returns `null` / `undefined` / `''` skips the header for that request, so the host can source values from live refs (e.g. the active i18n locale for `Accept-Language`) without baking in stale snapshots.
|
|
24
24
|
|
|
25
|
+
A `JSON` built-in namespace has been added (`json-builtins.ts`) — not from upstream. It registers a `JSON` brand class and a same-named constant on `globalRegistry`, so `JSON.parse(string): dyn` and `JSON.stringify(dyn): string` resolve in every `Environment`. The CEL-side surface mirrors the JS globals deliberately. `JSON.parse` is a thin wrapper over `globalThis.JSON.parse` — numbers come back as plain JS `number` (the evaluator coerces via `Decimal.from` at use time). `JSON.stringify` pre-walks the value via `normalizeForJSON` before handing it to `globalThis.JSON.stringify`: `Decimal` → JS number (via `.toNumber()` — loses precision past safe-integer range, deliberate trade-off for idiomatic JSON output), `Option.Some(x)` → `x`, `Option.None` → `null`, `Map` → plain object, `Date`/`TZDate` passes through so its built-in `toJSON` emits ISO 8601. The pre-walk is required because Effect's `Option` defines its own `toJSON()` that runs before any replacer would see it.
|
|
26
|
+
|
|
25
27
|
Spread syntax (`...expr`) inside list and map literals — not from upstream. A new `ELLIPSIS` token (3-char lookahead in the lexer) and a `spread` AST op let `[1, ...a, 4]` and `{...a, "x": 1, ...b}` desugar inside the parent literal. The spread node's own `check`/`evaluate` are defensive stubs — `parsePrimary` never produces one, so `...` outside a list/map is an "unexpected token" parse error. List `args` shape is unchanged (`IASTNode[]`, with spread elements detected via `op === 'spread'`); map `args` becomes `([IASTNode, IASTNode] | [IASTNode])[]` — a length-1 tuple represents a spread entry, preserving positional ordering for override semantics (later writes win). The fast path is preserved: the `list`/`map` `check` swaps `evaluate` meta to `evaluateSpreadList`/`evaluateSpreadMap` only when a spread child is present; literals without spreads run the original `resolveAstArray`/`safeFromEntries` paths byte-for-byte. Spread map sources may be plain objects, `Map` instances, or registered message types (typed as `map<string, dyn>`); the `__proto__`/`constructor`/`prototype` skip from `safeFromEntries` is applied to spread sources too. Runtime errors fire on non-list/non-map sources (including `null`). `maxListElements` / `maxMapEntries` count a spread as one entry — runtime expansion bypasses those caps (deliberate trade-off). Call-argument spread (`f(...args)`) is **not** supported.
|
|
26
28
|
|
|
27
29
|
## Architecture
|
|
@@ -39,6 +41,7 @@ lib/
|
|
|
39
41
|
├── macros.ts — map, filter, all, exists, exists_one, find, has, cel.bind
|
|
40
42
|
├── http-builtins.ts — `http` constant + http/HttpRequest types (local addition)
|
|
41
43
|
├── http-builder.ts — `HttpRequestBuilder` — what an http.* expression returns
|
|
44
|
+
├── json-builtins.ts — `JSON` constant + `JSON.parse` / `JSON.stringify` (local addition)
|
|
42
45
|
├── decimal.ts — Decimal class (arbitrary precision)
|
|
43
46
|
├── optional.ts — Optional type support (uses Effect Option)
|
|
44
47
|
├── serialize.ts — AST back to CEL string
|
|
@@ -160,6 +160,20 @@ b"hello".at(0) // 104
|
|
|
160
160
|
size(b"hello") // 5
|
|
161
161
|
```
|
|
162
162
|
|
|
163
|
+
### JSON
|
|
164
|
+
```cel
|
|
165
|
+
JSON.parse('{"a":1,"b":[2,3]}') // dyn value: {"a": 1, "b": [2, 3]}
|
|
166
|
+
JSON.parse("42") // 42
|
|
167
|
+
JSON.stringify({"a": 1, "b": [2,3]}) // '{"a":1,"b":[2,3]}'
|
|
168
|
+
JSON.stringify(1 + 2) // "3"
|
|
169
|
+
```
|
|
170
|
+
`JSON` is a built-in namespace — you don't import it, it's always available.
|
|
171
|
+
`JSON.parse` accepts any JSON string and returns a `dyn` value.
|
|
172
|
+
`JSON.stringify` takes any value and serializes it; CEL-internal shapes are
|
|
173
|
+
unwrapped first so the output is plain JSON — numbers (CEL's `Decimal`) become
|
|
174
|
+
JS numbers, optionals become their value (or `null` when empty), and `Date`
|
|
175
|
+
values become ISO 8601 strings.
|
|
176
|
+
|
|
163
177
|
### Dates
|
|
164
178
|
```cel
|
|
165
179
|
date("2023-06-15") // create a Date
|
|
@@ -3,6 +3,7 @@ import { createRegistry, RootContext } from "./registry.js";
|
|
|
3
3
|
import { evaluationError } from "./errors.js";
|
|
4
4
|
import { registerFunctions } from "./functions.js";
|
|
5
5
|
import { registerHttpBuiltins } from "./http-builtins.js";
|
|
6
|
+
import { registerJSONBuiltins } from "./json-builtins.js";
|
|
6
7
|
import { registerMacros } from "./macros.js";
|
|
7
8
|
import { registerOverloads } from "./overloads.js";
|
|
8
9
|
import { TypeChecker } from "./type-checker.js";
|
|
@@ -14,6 +15,7 @@ registerFunctions(globalRegistry);
|
|
|
14
15
|
registerOverloads(globalRegistry);
|
|
15
16
|
registerMacros(globalRegistry);
|
|
16
17
|
registerHttpBuiltins(globalRegistry);
|
|
18
|
+
registerJSONBuiltins(globalRegistry);
|
|
17
19
|
class Environment {
|
|
18
20
|
#registry;
|
|
19
21
|
#evaluator;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Option } from "effect";
|
|
2
|
+
import { evaluationError } from "./errors.js";
|
|
3
|
+
import { Decimal } from "./decimal.js";
|
|
4
|
+
class JSONNamespace {
|
|
5
|
+
brand = "JSON";
|
|
6
|
+
}
|
|
7
|
+
const JSON_INSTANCE = new JSONNamespace();
|
|
8
|
+
function normalizeForJSON(value) {
|
|
9
|
+
if (value === null || value === void 0) return value;
|
|
10
|
+
if (value instanceof Decimal) return value.toNumber();
|
|
11
|
+
if (Option.isOption(value)) {
|
|
12
|
+
return Option.isSome(value) ? normalizeForJSON(value.value) : null;
|
|
13
|
+
}
|
|
14
|
+
if (value instanceof Date) return value;
|
|
15
|
+
if (value instanceof Map) {
|
|
16
|
+
const out = {};
|
|
17
|
+
for (const [k, v] of value) out[String(k)] = normalizeForJSON(v);
|
|
18
|
+
return out;
|
|
19
|
+
}
|
|
20
|
+
if (Array.isArray(value)) return value.map(normalizeForJSON);
|
|
21
|
+
if (typeof value === "object") {
|
|
22
|
+
const proto = Object.getPrototypeOf(value);
|
|
23
|
+
if (proto !== Object.prototype && proto !== null) return value;
|
|
24
|
+
const out = {};
|
|
25
|
+
for (const key of Object.keys(value)) {
|
|
26
|
+
out[key] = normalizeForJSON(value[key]);
|
|
27
|
+
}
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
export function registerJSONBuiltins(registry) {
|
|
33
|
+
registry.registerType("JSON", JSONNamespace);
|
|
34
|
+
registry.registerVariable({
|
|
35
|
+
name: "JSON",
|
|
36
|
+
type: "JSON",
|
|
37
|
+
value: JSON_INSTANCE,
|
|
38
|
+
description: "JSON \u7F16\u89E3\u7801"
|
|
39
|
+
});
|
|
40
|
+
registry.registerFunctionOverload("JSON.parse(string): dyn", (_r, s) => {
|
|
41
|
+
try {
|
|
42
|
+
return globalThis.JSON.parse(s);
|
|
43
|
+
} catch (e) {
|
|
44
|
+
throw evaluationError("invalid_json", `JSON.parse(): ${e.message}`);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
registry.registerFunctionOverload(
|
|
48
|
+
"JSON.stringify(dyn): string",
|
|
49
|
+
(_r, v) => globalThis.JSON.stringify(normalizeForJSON(v))
|
|
50
|
+
);
|
|
51
|
+
}
|