@shwfed/config 2.1.2 → 2.2.1
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/config.d.vue.ts +8 -2
- package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.form/config.vue.d.ts +8 -2
- package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.form/runtime.d.vue.ts +8 -2
- package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.form/runtime.vue.d.ts +8 -2
- package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.form/schema.d.ts +8 -2
- package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/config.d.vue.ts +8 -2
- package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/config.vue.d.ts +8 -2
- package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/runtime.d.vue.ts +8 -2
- package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/runtime.vue.d.ts +8 -2
- package/dist/runtime/components/config/blocks/2026-05-06/com.shwfed.block.table/schema.d.ts +12 -3
- package/dist/runtime/components/form/config.vue +36 -5
- package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.number/config.d.vue.ts +2 -0
- package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.number/config.vue +31 -0
- package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.number/config.vue.d.ts +2 -0
- package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.number/runtime.vue +12 -2
- package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.number/schema.d.ts +1 -0
- package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.number/schema.js +4 -0
- package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.numberrange/config.d.vue.ts +2 -0
- package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.numberrange/config.vue +31 -0
- package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.numberrange/config.vue.d.ts +2 -0
- package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.numberrange/runtime.vue +16 -8
- package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.numberrange/schema.d.ts +1 -0
- package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.numberrange/schema.js +4 -0
- package/dist/runtime/components/form/fields/2026-05-12/com.shwfed.form.field.upload/config.d.vue.ts +8 -2
- package/dist/runtime/components/form/fields/2026-05-12/com.shwfed.form.field.upload/config.vue +51 -15
- package/dist/runtime/components/form/fields/2026-05-12/com.shwfed.form.field.upload/config.vue.d.ts +8 -2
- package/dist/runtime/components/form/fields/2026-05-12/com.shwfed.form.field.upload/runtime.vue +16 -5
- package/dist/runtime/components/form/fields/2026-05-12/com.shwfed.form.field.upload/schema.d.ts +9 -1
- package/dist/runtime/components/form/fields/2026-05-12/com.shwfed.form.field.upload/schema.js +25 -4
- package/dist/runtime/components/form/fields/2026-05-13/com.shwfed.form.field.combobox.single.remote/config.d.vue.ts +2 -2
- package/dist/runtime/components/form/fields/2026-05-13/com.shwfed.form.field.combobox.single.remote/config.vue.d.ts +2 -2
- package/dist/runtime/components/form/index.vue +4 -1
- package/dist/runtime/components/form/schema.d.ts +14 -4
- package/dist/runtime/components/form/schema.js +30 -10
- package/dist/runtime/components/form/utils/initial.d.ts +26 -0
- package/dist/runtime/components/form/utils/initial.js +11 -0
- package/dist/runtime/components/table/index.vue +3 -1
- package/dist/runtime/components/table/schema.d.ts +16 -4
- package/dist/runtime/plugins/i18n/index.js +8 -2
- package/dist/runtime/vendor/cel-js/CLAUDE.md +3 -1
- package/dist/runtime/vendor/cel-js/PROMPT.md +23 -7
- package/dist/runtime/vendor/cel-js/lib/http-builder.d.ts +6 -3
- package/dist/runtime/vendor/cel-js/lib/http-builder.js +24 -3
- package/dist/runtime/vendor/cel-js/lib/http-builtins.d.ts +3 -3
- package/dist/runtime/vendor/cel-js/lib/http-builtins.js +0 -4
- package/dist/runtime/vendor/cel-js/lib/operators.js +139 -11
- package/dist/runtime/vendor/cel-js/lib/parser.d.ts +2 -1
- package/dist/runtime/vendor/cel-js/lib/parser.js +20 -3
- package/dist/runtime/vendor/cel-js/lib/serialize.js +5 -1
- package/package.json +1 -1
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `HttpRequestBuilder` — the value an `http.*` CEL expression evaluates to.
|
|
3
3
|
*
|
|
4
|
-
* A local (non-upstream) extension. A CEL expression
|
|
5
|
-
* request
|
|
6
|
-
*
|
|
4
|
+
* A local (non-upstream) extension. A CEL expression only *describes* a
|
|
5
|
+
* request — it never issues one. Both terminal methods, `.json()` and
|
|
6
|
+
* `.file()`, are dispatched by the host on the returned builder, keeping
|
|
7
|
+
* expression evaluation free of IO.
|
|
7
8
|
*
|
|
8
9
|
* Endpoints are used verbatim — there is no base-URL resolution, so callers
|
|
9
10
|
* must pass absolute URLs.
|
|
@@ -12,6 +13,8 @@ import { Effect } from 'effect';
|
|
|
12
13
|
import { Fetch } from 'fx-fetch';
|
|
13
14
|
export declare class HttpRequestBuilder {
|
|
14
15
|
#private;
|
|
16
|
+
static setDefaultHeader(name: string, value: string | (() => string | null | undefined)): void;
|
|
17
|
+
static clearDefaultHeader(name: string): void;
|
|
15
18
|
constructor(url: string, method: string);
|
|
16
19
|
header(name: string, value: string): this;
|
|
17
20
|
query(key: string, value: string | number): this;
|
|
@@ -38,6 +38,20 @@ export class HttpRequestBuilder {
|
|
|
38
38
|
#headers = [];
|
|
39
39
|
#queries = [];
|
|
40
40
|
#body;
|
|
41
|
+
// Process-wide defaults applied at `#buildRequest()` time. Each entry is
|
|
42
|
+
// keyed by lowercased header name so an explicit `.header('X', …)` on the
|
|
43
|
+
// builder wins regardless of casing. A getter returning `null` / `undefined`
|
|
44
|
+
// / `''` skips the header for that request — lets the host source values
|
|
45
|
+
// from a live ref (e.g. the current i18n locale) without baking in stale
|
|
46
|
+
// snapshots.
|
|
47
|
+
static #defaultHeaders = /* @__PURE__ */ new Map();
|
|
48
|
+
static setDefaultHeader(name, value) {
|
|
49
|
+
const get = typeof value === "function" ? value : () => value;
|
|
50
|
+
HttpRequestBuilder.#defaultHeaders.set(name.toLowerCase(), { name, get });
|
|
51
|
+
}
|
|
52
|
+
static clearDefaultHeader(name) {
|
|
53
|
+
HttpRequestBuilder.#defaultHeaders.delete(name.toLowerCase());
|
|
54
|
+
}
|
|
41
55
|
constructor(url, method) {
|
|
42
56
|
this.#url = url;
|
|
43
57
|
this.#method = method;
|
|
@@ -117,9 +131,16 @@ export class HttpRequestBuilder {
|
|
|
117
131
|
url: this.#url,
|
|
118
132
|
method: this.#method
|
|
119
133
|
};
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
134
|
+
const explicit = new Set(this.#headers.map(([k]) => k.toLowerCase()));
|
|
135
|
+
const headers = {};
|
|
136
|
+
for (const [k, v] of this.#headers) headers[k] = v;
|
|
137
|
+
for (const [key, { name, get }] of HttpRequestBuilder.#defaultHeaders) {
|
|
138
|
+
if (explicit.has(key)) continue;
|
|
139
|
+
const v = get();
|
|
140
|
+
if (v == null || v === "") continue;
|
|
141
|
+
headers[name] = v;
|
|
142
|
+
}
|
|
143
|
+
if (Object.keys(headers).length > 0) {
|
|
123
144
|
parts.headers = headers;
|
|
124
145
|
}
|
|
125
146
|
if (this.#body !== void 0) {
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Registers the `http` / `HttpRequest` types, the `http` constant, and the
|
|
5
5
|
* request-builder functions on the registry. `http.get(url).header(...).body(...)`
|
|
6
|
-
* builds an `HttpRequestBuilder
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* builds an `HttpRequestBuilder` — a pure *description* of a request. CEL never
|
|
7
|
+
* issues it: both `.json()` and `.file()` are dispatched by the host on the
|
|
8
|
+
* returned builder, so expression evaluation stays free of IO.
|
|
9
9
|
*
|
|
10
10
|
* Wired into `globalRegistry` at module load (see `evaluator.ts`), so every
|
|
11
11
|
* `Environment` gets HTTP for free — both type-checking and evaluation.
|
|
@@ -74,8 +74,106 @@ function checkOptionalAccessNode(chk, ast, ctx) {
|
|
|
74
74
|
const actualType = leftType.kind === "optional" ? leftType.valueType : leftType;
|
|
75
75
|
return chk.registry.getOptionalType(chk.checkAccessOnType(ast, ctx, actualType, true));
|
|
76
76
|
}
|
|
77
|
-
function
|
|
78
|
-
return
|
|
77
|
+
function spreadInner(node) {
|
|
78
|
+
return node.args;
|
|
79
|
+
}
|
|
80
|
+
function spreadListElementType(chk, ctx, node) {
|
|
81
|
+
const t = chk.check(spreadInner(node), ctx);
|
|
82
|
+
if (t.kind === "dyn") return chk.dynType;
|
|
83
|
+
if (t.kind === "list") return t.valueType;
|
|
84
|
+
throw chk.createError(
|
|
85
|
+
"invalid_spread",
|
|
86
|
+
`Cannot spread '${chk.formatType(t)}' into a list (expected a list)`,
|
|
87
|
+
node
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
function spreadMapEntryTypes(chk, ctx, node) {
|
|
91
|
+
const t = chk.check(spreadInner(node), ctx);
|
|
92
|
+
if (t.kind === "dyn") return [chk.dynType, chk.dynType];
|
|
93
|
+
if (t.kind === "map") return [t.keyType, t.valueType];
|
|
94
|
+
if (t.kind === "message") {
|
|
95
|
+
const Base2 = chk;
|
|
96
|
+
return [Base2.stringType, chk.dynType];
|
|
97
|
+
}
|
|
98
|
+
throw chk.createError(
|
|
99
|
+
"invalid_spread",
|
|
100
|
+
`Cannot spread '${chk.formatType(t)}' into a map (expected a map)`,
|
|
101
|
+
node
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
const SPREAD_SKIP_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
105
|
+
function assignFragmentEntry(obj, k, v) {
|
|
106
|
+
const key = k;
|
|
107
|
+
if (SPREAD_SKIP_KEYS.has(key)) return;
|
|
108
|
+
obj[key] = v;
|
|
109
|
+
}
|
|
110
|
+
function mergeMapFragments(ev, frags) {
|
|
111
|
+
const obj = {};
|
|
112
|
+
for (const f of frags) {
|
|
113
|
+
if ("kv" in f) {
|
|
114
|
+
assignFragmentEntry(obj, f.kv[0], f.kv[1]);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
const src = f.spread;
|
|
118
|
+
if (src instanceof Map) {
|
|
119
|
+
for (const [k, v] of src) assignFragmentEntry(obj, k, v);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (src !== null && typeof src === "object" && !isArray(src)) {
|
|
123
|
+
for (const k in src) {
|
|
124
|
+
if (hasOwn(src, k)) assignFragmentEntry(obj, k, src[k]);
|
|
125
|
+
}
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
throw ev.createError(
|
|
129
|
+
"invalid_spread",
|
|
130
|
+
`Cannot spread a non-map value into a map`,
|
|
131
|
+
f.node
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
return obj;
|
|
135
|
+
}
|
|
136
|
+
function evaluateSpreadList(ev, ast, ctx) {
|
|
137
|
+
const arr = ast.args;
|
|
138
|
+
return Effect.all(
|
|
139
|
+
arr.map(
|
|
140
|
+
(el) => el.op === "spread" ? ev.eval(spreadInner(el), ctx).pipe(
|
|
141
|
+
Effect.flatMap(
|
|
142
|
+
(v) => isArray(v) ? Effect.succeed(v) : Effect.fail(
|
|
143
|
+
ev.createError(
|
|
144
|
+
"invalid_spread",
|
|
145
|
+
`Cannot spread a non-list value into a list`,
|
|
146
|
+
el
|
|
147
|
+
)
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
) : ev.eval(el, ctx).pipe(Effect.map((v) => [v]))
|
|
151
|
+
)
|
|
152
|
+
).pipe(Effect.map((parts) => parts.flat()));
|
|
153
|
+
}
|
|
154
|
+
function evaluateSpreadMap(ev, ast, ctx) {
|
|
155
|
+
const arr = ast.args;
|
|
156
|
+
return Effect.all(
|
|
157
|
+
arr.map((e) => {
|
|
158
|
+
if (e.length === 1 || e[0].op === "spread") {
|
|
159
|
+
const node = e[0];
|
|
160
|
+
return ev.eval(spreadInner(node), ctx).pipe(
|
|
161
|
+
Effect.map((src) => ({ spread: src, node }))
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
const pair = e;
|
|
165
|
+
return Effect.all([ev.eval(pair[0], ctx), ev.eval(pair[1], ctx)]).pipe(
|
|
166
|
+
Effect.map(([k, v]) => ({ kv: [k, v] }))
|
|
167
|
+
);
|
|
168
|
+
})
|
|
169
|
+
).pipe(
|
|
170
|
+
Effect.flatMap(
|
|
171
|
+
(frags) => Effect.try({
|
|
172
|
+
try: () => mergeMapFragments(ev, frags),
|
|
173
|
+
catch: (e) => e
|
|
174
|
+
})
|
|
175
|
+
)
|
|
176
|
+
);
|
|
79
177
|
}
|
|
80
178
|
function ternaryConditionError(ev, value, node) {
|
|
81
179
|
const type = ev.debugRuntimeType(value);
|
|
@@ -481,9 +579,19 @@ const OPERATORS_MAP = {
|
|
|
481
579
|
const arr = ast.args;
|
|
482
580
|
const arrLen = arr.length;
|
|
483
581
|
if (arrLen === 0) return ast.setMeta("evaluate", emptyList) && chk.getType("list<T>");
|
|
484
|
-
let
|
|
485
|
-
|
|
486
|
-
|
|
582
|
+
let hasSpread = false;
|
|
583
|
+
let valueType;
|
|
584
|
+
for (const el of arr) {
|
|
585
|
+
let t;
|
|
586
|
+
if (el.op === "spread") {
|
|
587
|
+
hasSpread = true;
|
|
588
|
+
t = spreadListElementType(chk, ctx, el);
|
|
589
|
+
} else {
|
|
590
|
+
t = chk.check(el, ctx);
|
|
591
|
+
}
|
|
592
|
+
valueType = valueType === void 0 ? t : valueType.unify(chk.registry, t) ?? dynType;
|
|
593
|
+
}
|
|
594
|
+
if (hasSpread) ast.setMeta("evaluate", evaluateSpreadList);
|
|
487
595
|
return chk.registry.getListType(valueType);
|
|
488
596
|
},
|
|
489
597
|
evaluate(ev, ast, ctx) {
|
|
@@ -495,13 +603,23 @@ const OPERATORS_MAP = {
|
|
|
495
603
|
const arr = ast.args;
|
|
496
604
|
const arrLen = arr.length;
|
|
497
605
|
if (arrLen === 0) return ast.setMeta("evaluate", emptyMap) && chk.getType("map<K, V>");
|
|
498
|
-
let
|
|
499
|
-
let
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
606
|
+
let hasSpread = false;
|
|
607
|
+
let keyType;
|
|
608
|
+
let valueType;
|
|
609
|
+
for (const e of arr) {
|
|
610
|
+
let k;
|
|
611
|
+
let v;
|
|
612
|
+
if (e.length === 1 || e[0].op === "spread") {
|
|
613
|
+
hasSpread = true;
|
|
614
|
+
[k, v] = spreadMapEntryTypes(chk, ctx, e[0]);
|
|
615
|
+
} else {
|
|
616
|
+
k = chk.check(e[0], ctx);
|
|
617
|
+
v = chk.check(e[1], ctx);
|
|
618
|
+
}
|
|
619
|
+
keyType = keyType === void 0 ? k : keyType.unify(chk.registry, k) ?? dynType;
|
|
620
|
+
valueType = valueType === void 0 ? v : valueType.unify(chk.registry, v) ?? dynType;
|
|
504
621
|
}
|
|
622
|
+
if (hasSpread) ast.setMeta("evaluate", evaluateSpreadMap);
|
|
505
623
|
return chk.registry.getMapType(keyType, valueType);
|
|
506
624
|
},
|
|
507
625
|
evaluate(ev, ast, ctx) {
|
|
@@ -513,6 +631,16 @@ const OPERATORS_MAP = {
|
|
|
513
631
|
).pipe(Effect.map(safeFromEntries));
|
|
514
632
|
}
|
|
515
633
|
},
|
|
634
|
+
"spread": {
|
|
635
|
+
// Reached only via direct `ast.check`/`ast.evaluate` — parents consume the
|
|
636
|
+
// node inline, so these are defensive guards.
|
|
637
|
+
check(chk, ast) {
|
|
638
|
+
throw chk.createError("misplaced_spread", `'...' is only valid inside a list or map literal`, ast);
|
|
639
|
+
},
|
|
640
|
+
evaluate(ev, ast) {
|
|
641
|
+
return Effect.fail(ev.createError("misplaced_spread", `'...' is only valid inside a list or map literal`, ast));
|
|
642
|
+
}
|
|
643
|
+
},
|
|
516
644
|
"comprehension": {
|
|
517
645
|
check(chk, ast, ctx) {
|
|
518
646
|
const args = ast.args;
|
|
@@ -76,8 +76,9 @@ export declare class Parser {
|
|
|
76
76
|
parsePostfix(): ASTNode;
|
|
77
77
|
parsePrimary(): ASTNode;
|
|
78
78
|
parseList(): ASTNode;
|
|
79
|
+
parseListElement(): ASTNode;
|
|
79
80
|
parseMap(): ASTNode;
|
|
80
|
-
parseProperty(): [ASTNode, ASTNode];
|
|
81
|
+
parseProperty(): [ASTNode, ASTNode] | [ASTNode];
|
|
81
82
|
parseArgumentList(): ASTNode[];
|
|
82
83
|
}
|
|
83
84
|
export {};
|
|
@@ -34,7 +34,8 @@ const TOKEN = {
|
|
|
34
34
|
COMMA: 28,
|
|
35
35
|
COLON: 29,
|
|
36
36
|
QUESTION: 30,
|
|
37
|
-
BYTES: 31
|
|
37
|
+
BYTES: 31,
|
|
38
|
+
ELLIPSIS: 32
|
|
38
39
|
};
|
|
39
40
|
const OP_FOR_TOKEN = {
|
|
40
41
|
[TOKEN.EQ]: OPS["=="],
|
|
@@ -208,6 +209,8 @@ class Lexer {
|
|
|
208
209
|
case "}":
|
|
209
210
|
return this.token(this.pos++, TOKEN.RBRACE);
|
|
210
211
|
case ".":
|
|
212
|
+
if (input[pos + 1] === "." && input[pos + 2] === ".")
|
|
213
|
+
return this.token((this.pos += 3) - 3, TOKEN.ELLIPSIS);
|
|
211
214
|
return this.token(this.pos++, TOKEN.DOT);
|
|
212
215
|
case ",":
|
|
213
216
|
return this.token(this.pos++, TOKEN.COMMA);
|
|
@@ -735,12 +738,12 @@ export class Parser {
|
|
|
735
738
|
const elements = [];
|
|
736
739
|
let remainingElements = this.limits.maxListElements;
|
|
737
740
|
if (!this.match(TOKEN.RBRACKET)) {
|
|
738
|
-
elements.push(this.
|
|
741
|
+
elements.push(this.parseListElement());
|
|
739
742
|
if (!remainingElements--) this.#limitExceeded("maxListElements", elements.at(-1).pos);
|
|
740
743
|
while (this.match(TOKEN.COMMA)) {
|
|
741
744
|
this.#advanceToken();
|
|
742
745
|
if (this.match(TOKEN.RBRACKET)) break;
|
|
743
|
-
elements.push(this.
|
|
746
|
+
elements.push(this.parseListElement());
|
|
744
747
|
if (!remainingElements--) this.#limitExceeded("maxListElements", elements.at(-1).pos);
|
|
745
748
|
}
|
|
746
749
|
}
|
|
@@ -748,6 +751,10 @@ export class Parser {
|
|
|
748
751
|
this.consume(TOKEN.RBRACKET);
|
|
749
752
|
return this.#node(start, closeEnd, OPS.list, elements);
|
|
750
753
|
}
|
|
754
|
+
parseListElement() {
|
|
755
|
+
if (this.match(TOKEN.ELLIPSIS)) return this.#parseSpread();
|
|
756
|
+
return this.parseExpression();
|
|
757
|
+
}
|
|
751
758
|
parseMap() {
|
|
752
759
|
const start = this.consume(TOKEN.LBRACE);
|
|
753
760
|
const props = [];
|
|
@@ -767,8 +774,18 @@ export class Parser {
|
|
|
767
774
|
return this.#node(start, closeEnd, OPS.map, props);
|
|
768
775
|
}
|
|
769
776
|
parseProperty() {
|
|
777
|
+
if (this.match(TOKEN.ELLIPSIS)) return [this.#parseSpread()];
|
|
770
778
|
return [this.parseExpression(), (this.consume(TOKEN.COLON), this.parseExpression())];
|
|
771
779
|
}
|
|
780
|
+
// `...expr` — only valid as a list element or map entry; the parent literal
|
|
781
|
+
// consumes the node and `parsePrimary` never sees ELLIPSIS, so a stray `...`
|
|
782
|
+
// surfaces as a normal "unexpected token" parse error.
|
|
783
|
+
#parseSpread() {
|
|
784
|
+
const start = this.pos;
|
|
785
|
+
this.#advanceToken();
|
|
786
|
+
const inner = this.parseExpression();
|
|
787
|
+
return this.#node(start, inner.end, OPS.spread, inner);
|
|
788
|
+
}
|
|
772
789
|
parseArgumentList() {
|
|
773
790
|
const args = [];
|
|
774
791
|
let remainingArgs = this.limits.maxCallArguments;
|
|
@@ -79,7 +79,11 @@ export function serialize(ast) {
|
|
|
79
79
|
case "list":
|
|
80
80
|
return `[${args.map(serialize).join(", ")}]`;
|
|
81
81
|
case "map":
|
|
82
|
-
return `{${args.map(
|
|
82
|
+
return `{${args.map(
|
|
83
|
+
(e) => e.length === 1 || e[0].op === "spread" ? serialize(e[0]) : `${serialize(e[0])}: ${serialize(e[1])}`
|
|
84
|
+
).join(", ")}}`;
|
|
85
|
+
case "spread":
|
|
86
|
+
return `...${serialize(args)}`;
|
|
83
87
|
case "?:": {
|
|
84
88
|
const ternArgs = args;
|
|
85
89
|
return `${wrap(ternArgs[0], op)} ? ${wrap(ternArgs[1], op)} : ${serialize(ternArgs[2])}`;
|