@jxsuite/compiler 1.4.0 → 2.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/dist/cli.js +564 -230
- package/dist/compiler.js +334 -133
- package/package.json +11 -9
- package/src/compiler.ts +1 -1
- package/src/shadow.ts +65 -0
- package/src/shared.ts +461 -51
- package/src/site/bundler.ts +149 -18
- package/src/site/client-runtime.ts +374 -0
- package/src/site/context-injection.ts +45 -2
- package/src/site/csp.ts +224 -0
- package/src/site/head-merger.ts +57 -13
- package/src/site/headers-emitter.ts +232 -0
- package/src/site/i18n.ts +365 -0
- package/src/site/image-optimizer.ts +7 -0
- package/src/site/image-transform.ts +269 -118
- package/src/site/img-loading.ts +55 -0
- package/src/site/link-relations.ts +251 -0
- package/src/site/locale-negotiation.ts +258 -0
- package/src/site/pages-discovery.ts +149 -0
- package/src/site/preview-server.ts +9 -1
- package/src/site/schema-command.ts +138 -87
- package/src/site/service-worker.ts +294 -0
- package/src/site/site-build.ts +956 -109
- package/src/site/site-loader.ts +1 -0
- package/src/site/validate-command.ts +134 -38
- package/src/site/well-known.ts +221 -0
- package/src/targets/compile-client.ts +144 -81
- package/src/targets/compile-element.ts +620 -58
- package/src/targets/compile-server.ts +19 -2
- package/src/targets/compile-static.ts +12 -3
- package/src/types.ts +2 -0
|
@@ -16,21 +16,26 @@ import {
|
|
|
16
16
|
DEFAULT_LIT_HTML_SRC,
|
|
17
17
|
DEFAULT_REACTIVITY_SRC,
|
|
18
18
|
buildAttrs,
|
|
19
|
+
childSeparator,
|
|
19
20
|
colorSchemePrePaintScript,
|
|
20
21
|
compileExpression,
|
|
21
22
|
compileStatements,
|
|
22
23
|
compileStyles,
|
|
23
24
|
createCompileContext,
|
|
24
25
|
emitFormulaFn,
|
|
26
|
+
emitRequestFetch,
|
|
25
27
|
escapeHtml,
|
|
26
28
|
isMutating,
|
|
27
29
|
isRefObject,
|
|
28
30
|
isSchemaOnly,
|
|
29
31
|
isTemplateString,
|
|
32
|
+
PREFORMATTED_TAGS,
|
|
30
33
|
pureSchemeOf,
|
|
31
34
|
resolveStaticValue,
|
|
35
|
+
srcImportBinding,
|
|
32
36
|
} from "../shared.ts";
|
|
33
37
|
import {
|
|
38
|
+
bodyReturnsValue,
|
|
34
39
|
hasStructuredBody,
|
|
35
40
|
isExpandedSignal,
|
|
36
41
|
isExpressionDef,
|
|
@@ -38,16 +43,24 @@ import {
|
|
|
38
43
|
isMappedArray,
|
|
39
44
|
isNamedFormulaDef,
|
|
40
45
|
isPrototypeDef,
|
|
46
|
+
isTagExpression,
|
|
41
47
|
paramNames,
|
|
48
|
+
tagNameCandidates,
|
|
42
49
|
} from "@jxsuite/schema/guards";
|
|
43
50
|
import type { CompileContext, ExpressionNode } from "../shared.ts";
|
|
51
|
+
import {
|
|
52
|
+
escapeToken,
|
|
53
|
+
objectKey,
|
|
54
|
+
refAccessor,
|
|
55
|
+
refBindingKey,
|
|
56
|
+
refSegments,
|
|
57
|
+
} from "@jxsuite/runtime/pointer";
|
|
44
58
|
import type {
|
|
45
59
|
JsonObject,
|
|
46
60
|
JsonValue,
|
|
47
61
|
JxDocument,
|
|
48
62
|
JxMappedArray,
|
|
49
63
|
JxMutableNode,
|
|
50
|
-
JxPrototypeDef,
|
|
51
64
|
JxStyle,
|
|
52
65
|
} from "@jxsuite/schema/types";
|
|
53
66
|
|
|
@@ -161,11 +174,11 @@ export function compileClient(
|
|
|
161
174
|
if (!srcImportMap.has(def.$src)) {
|
|
162
175
|
srcImportMap.set(def.$src, new Set());
|
|
163
176
|
}
|
|
164
|
-
(srcImportMap.get(def.$src) as Set<string>).add(key);
|
|
177
|
+
(srcImportMap.get(def.$src) as Set<string>).add(srcImportBinding(key, def));
|
|
165
178
|
|
|
166
179
|
// $src functions always produce computed entries (they return values)
|
|
167
180
|
computedEntries.push([key, `() => { return ${key}(state); }`]);
|
|
168
|
-
} else if (typeof def.body === "string" && def.body
|
|
181
|
+
} else if (typeof def.body === "string" && bodyReturnsValue(def.body)) {
|
|
169
182
|
// Body contains return → computed
|
|
170
183
|
computedEntries.push([key, `() => { ${def.body} }`]);
|
|
171
184
|
} else {
|
|
@@ -200,7 +213,7 @@ export function compileClient(
|
|
|
200
213
|
// $prototype: "Request"
|
|
201
214
|
if (def.$prototype === "Request") {
|
|
202
215
|
stateEntries.push([key, null]);
|
|
203
|
-
initBlocks.push(
|
|
216
|
+
initBlocks.push(emitRequestFetch(key, def));
|
|
204
217
|
continue;
|
|
205
218
|
}
|
|
206
219
|
|
|
@@ -334,7 +347,22 @@ function buildClientNode(
|
|
|
334
347
|
raw?.$media ?? context.media,
|
|
335
348
|
);
|
|
336
349
|
|
|
350
|
+
/* REFUSED, LOUDLY. A chosen tag has no implementation in this target: the element's identity is
|
|
351
|
+
fixed in the prerendered markup, so there is nothing here to re-choose at hydration the way the
|
|
352
|
+
`$switch` binding below re-chooses a subtree. Emitting a silently wrong element would be an
|
|
353
|
+
instance of the class the tagName pattern was added to end, so a dynamic page that needs a
|
|
354
|
+
chosen tag is told to put the element in a component (which compiles through `compile-element`,
|
|
355
|
+
where the construct is implemented) rather than shipping markup with the wrong tag. */
|
|
356
|
+
if (isTagExpression(def.tagName)) {
|
|
357
|
+
throw new Error(
|
|
358
|
+
"A tag chosen at creation is not supported on a dynamic page yet (candidates: " +
|
|
359
|
+
`${tagNameCandidates(def.tagName).join(", ")}). Move the element into a component, or ` +
|
|
360
|
+
"give it a literal tagName.",
|
|
361
|
+
);
|
|
362
|
+
}
|
|
337
363
|
const tag = def.tagName ?? "div";
|
|
364
|
+
// `white-space` inherits, so once inside a <pre> the whole subtree stays whitespace-significant.
|
|
365
|
+
nextContext.preformatted = context.preformatted === true || PREFORMATTED_TAGS.has(tag);
|
|
338
366
|
const bindAttrs = [];
|
|
339
367
|
let needsBind = false;
|
|
340
368
|
|
|
@@ -478,6 +506,33 @@ function buildClientNode(
|
|
|
478
506
|
// Inner content
|
|
479
507
|
let inner = "";
|
|
480
508
|
const source = raw ?? def;
|
|
509
|
+
if (source.$switch) {
|
|
510
|
+
// ─── $switch → lit-html render binding ───
|
|
511
|
+
// Without this branch the node fell through to the generic element path, which emitted a
|
|
512
|
+
// Container and then looked for `children` to recurse into — `cases` is not `children`, so the
|
|
513
|
+
// Subtree was never visited and the page shipped with the content missing, no error (#127).
|
|
514
|
+
// The container is emitted empty for the same reason the mapped-array branch below is: lit's
|
|
515
|
+
// `render` appends into the container rather than replacing its existing children, so any
|
|
516
|
+
// Prerendered branch would survive alongside the rendered one.
|
|
517
|
+
counter.needsLit = true;
|
|
518
|
+
const swKey = `_sw${counter.sw}`;
|
|
519
|
+
counter.sw += 1;
|
|
520
|
+
const discriminant = isRefObject(source.$switch)
|
|
521
|
+
? `state.${refToBindingKey((source.$switch as { $ref: string }).$ref)}`
|
|
522
|
+
: `\`${String(source.$switch)}\``;
|
|
523
|
+
const cases = (source.cases ?? {}) as Record<string, JxMutableNode>;
|
|
524
|
+
const caseEntries = Object.entries(cases)
|
|
525
|
+
// An external `$ref` case cannot be fetched at compile time, exactly as in the static target.
|
|
526
|
+
.filter(([, caseDef]) => caseDef && !isRefObject(caseDef))
|
|
527
|
+
.map(
|
|
528
|
+
([key, caseDef]) =>
|
|
529
|
+
`${JSON.stringify(key)}: html\`${emitChildLit(caseDef, nextContext.preformatted)}\``,
|
|
530
|
+
);
|
|
531
|
+
bindings.set(swKey, `() => ({${caseEntries.join(", ")}})[String(${discriminant})] ?? html\`\``);
|
|
532
|
+
bindAttrs.push(`:render="${swKey}"`);
|
|
533
|
+
const bindAttrStrSwitch = ` ${bindAttrs.join(" ")}`;
|
|
534
|
+
return `<${tag}${staticAttrs} data-bind${bindAttrStrSwitch}></${tag}>`;
|
|
535
|
+
}
|
|
481
536
|
if (source.textContent !== undefined && !needsBind) {
|
|
482
537
|
const value = resolveStaticValue(source.textContent, nextContext.scope);
|
|
483
538
|
inner = value == null ? "" : escapeHtml(String(value));
|
|
@@ -530,9 +585,14 @@ function buildClientNode(
|
|
|
530
585
|
const listKey = `_children${counter.l}`;
|
|
531
586
|
counter.l += 1;
|
|
532
587
|
const childrenTpl = source.children
|
|
533
|
-
.map((c) => emitChildLit(c as JxMutableNode))
|
|
534
|
-
.join("
|
|
535
|
-
bindings.set(
|
|
588
|
+
.map((c) => emitChildLit(c as JxMutableNode, nextContext.preformatted))
|
|
589
|
+
.join(childSeparator(nextContext.preformatted, " "));
|
|
590
|
+
bindings.set(
|
|
591
|
+
listKey,
|
|
592
|
+
nextContext.preformatted
|
|
593
|
+
? `() => html\`${childrenTpl}\``
|
|
594
|
+
: `() => html\`\n ${childrenTpl}\n \``,
|
|
595
|
+
);
|
|
536
596
|
bindAttrs.push(`:render="${listKey}"`);
|
|
537
597
|
needsBind = true;
|
|
538
598
|
const bindAttrStr2 = ` ${bindAttrs.join(" ")}`;
|
|
@@ -551,7 +611,7 @@ function buildClientNode(
|
|
|
551
611
|
counter,
|
|
552
612
|
);
|
|
553
613
|
})
|
|
554
|
-
.join(
|
|
614
|
+
.join(childSeparator(nextContext.preformatted));
|
|
555
615
|
}
|
|
556
616
|
|
|
557
617
|
// Self-closing tags
|
|
@@ -570,13 +630,25 @@ function buildClientNode(
|
|
|
570
630
|
* index.
|
|
571
631
|
*
|
|
572
632
|
* @param {JxMutableNode} def
|
|
633
|
+
* @param {boolean} [preformatted]
|
|
573
634
|
* @returns {string}
|
|
574
635
|
*/
|
|
575
|
-
function emitLitMapTemplate(def: JxMutableNode | undefined) {
|
|
636
|
+
function emitLitMapTemplate(def: JxMutableNode | undefined, preformatted = false) {
|
|
576
637
|
if (!def) {
|
|
577
638
|
return "";
|
|
578
639
|
}
|
|
640
|
+
// Same refusal as `buildClientNode` above, for the repeater's item template — this target has no
|
|
641
|
+
// Branch construct, and a silently wrong element is what the tagName pattern exists to prevent.
|
|
642
|
+
if (isTagExpression(def.tagName)) {
|
|
643
|
+
throw new Error(
|
|
644
|
+
"A tag chosen at creation is not supported inside a dynamic page's repeater yet " +
|
|
645
|
+
`(candidates: ${tagNameCandidates(def.tagName).join(", ")}). Move the item into a ` +
|
|
646
|
+
"component, or give it a literal tagName.",
|
|
647
|
+
);
|
|
648
|
+
}
|
|
579
649
|
const tag = def.tagName ?? "div";
|
|
650
|
+
// `white-space` inherits, so once inside a <pre> the whole subtree stays whitespace-significant.
|
|
651
|
+
const inPre = preformatted || PREFORMATTED_TAGS.has(tag);
|
|
580
652
|
let attrs = "";
|
|
581
653
|
|
|
582
654
|
if (def.id) {
|
|
@@ -586,6 +658,20 @@ function emitLitMapTemplate(def: JxMutableNode | undefined) {
|
|
|
586
658
|
attrs += ` class="${mapRefsToLit(def.className)}"`;
|
|
587
659
|
}
|
|
588
660
|
|
|
661
|
+
// $props → lit property bindings. The element target emits these; the client target emitted
|
|
662
|
+
// Nothing, so a component in a list silently received none of its per-item props.
|
|
663
|
+
if (def.$props && typeof def.$props === "object") {
|
|
664
|
+
for (const [k, v] of Object.entries(def.$props)) {
|
|
665
|
+
if (isRefObject(v)) {
|
|
666
|
+
attrs += ` .${k}="\${${mapRefToClientExpr((v as { $ref: string }).$ref)}}"`;
|
|
667
|
+
} else if (typeof v === "string" && isTemplateString(v)) {
|
|
668
|
+
attrs += ` .${k}="${mapRefsToLit(v)}"`;
|
|
669
|
+
} else {
|
|
670
|
+
attrs += ` .${k}="\${${JSON.stringify(v)}}"`;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
589
675
|
// Attributes object
|
|
590
676
|
if (def.attributes && typeof def.attributes === "object") {
|
|
591
677
|
for (const [k, v] of Object.entries(def.attributes)) {
|
|
@@ -674,7 +760,8 @@ function emitLitMapTemplate(def: JxMutableNode | undefined) {
|
|
|
674
760
|
// Legacy whole-children repeater nested inside a map template.
|
|
675
761
|
inner = `\n ${emitArrayHole(def.children)}\n `;
|
|
676
762
|
} else if (Array.isArray(def.children)) {
|
|
677
|
-
|
|
763
|
+
const rendered = def.children.map((c) => emitChildLit(c, inPre));
|
|
764
|
+
inner = inPre ? rendered.join("") : `\n ${rendered.join("\n ")}\n `;
|
|
678
765
|
}
|
|
679
766
|
|
|
680
767
|
const voidTags = new Set(["input", "br", "hr", "img", "meta", "link"]);
|
|
@@ -689,9 +776,10 @@ function emitLitMapTemplate(def: JxMutableNode | undefined) {
|
|
|
689
776
|
* via a `.map()` hole), or a nested element.
|
|
690
777
|
*
|
|
691
778
|
* @param {JxMutableNode | string} c
|
|
779
|
+
* @param {boolean} [preformatted]
|
|
692
780
|
* @returns {string}
|
|
693
781
|
*/
|
|
694
|
-
function emitChildLit(c: JxMutableNode | string): string {
|
|
782
|
+
function emitChildLit(c: JxMutableNode | string, preformatted = false): string {
|
|
695
783
|
if (typeof c === "string") {
|
|
696
784
|
return isTemplateString(c) ? mapRefsToLit(c) : escapeHtml(c);
|
|
697
785
|
}
|
|
@@ -701,7 +789,7 @@ function emitChildLit(c: JxMutableNode | string): string {
|
|
|
701
789
|
if (isMappedArray(c)) {
|
|
702
790
|
return emitArrayHole(c);
|
|
703
791
|
}
|
|
704
|
-
return emitLitMapTemplate(c);
|
|
792
|
+
return emitLitMapTemplate(c, preformatted);
|
|
705
793
|
}
|
|
706
794
|
|
|
707
795
|
/**
|
|
@@ -798,7 +886,11 @@ function emitClientModule(
|
|
|
798
886
|
// State — reactive state
|
|
799
887
|
lines.push("", "const state = reactive({");
|
|
800
888
|
for (const [key, val] of stateEntries) {
|
|
801
|
-
|
|
889
|
+
/*
|
|
890
|
+
* State keys come from the document, so `{"user.name": 1}` is legal input. Pasting one raw as
|
|
891
|
+
* an identifier emitted `user.name: 1,` — a SyntaxError the build reported as a success.
|
|
892
|
+
*/
|
|
893
|
+
lines.push(` ${objectKey(key)}: ${JSON.stringify(val)},`);
|
|
802
894
|
}
|
|
803
895
|
lines.push("});", "");
|
|
804
896
|
|
|
@@ -813,7 +905,7 @@ function emitClientModule(
|
|
|
813
905
|
// Computed signals on state
|
|
814
906
|
if (computedEntries.length > 0) {
|
|
815
907
|
for (const [key, expr] of computedEntries) {
|
|
816
|
-
lines.push(
|
|
908
|
+
lines.push(`${refAccessor("state", escapeToken(key))} = computed(${expr});`);
|
|
817
909
|
}
|
|
818
910
|
lines.push("");
|
|
819
911
|
}
|
|
@@ -822,7 +914,7 @@ function emitClientModule(
|
|
|
822
914
|
if (bindEntries.length > 0) {
|
|
823
915
|
lines.push("const bind = {");
|
|
824
916
|
for (const [key, expr] of bindEntries) {
|
|
825
|
-
lines.push(` ${key}: ${expr},`);
|
|
917
|
+
lines.push(` ${objectKey(key)}: ${expr},`);
|
|
826
918
|
}
|
|
827
919
|
lines.push("};");
|
|
828
920
|
} else {
|
|
@@ -837,7 +929,7 @@ function emitClientModule(
|
|
|
837
929
|
const argNames = def.args ?? ["state"];
|
|
838
930
|
const callArgs = argNames.map((a: string) => (a === "state" ? "state" : "e")).join(", ");
|
|
839
931
|
lines.push(
|
|
840
|
-
` ${key}: (e) => { const fn = (${argNames.join(", ")}) => { ${def.body} }; fn(${
|
|
932
|
+
` ${objectKey(key)}: (e) => { const fn = (${argNames.join(", ")}) => { ${def.body} }; fn(${
|
|
841
933
|
callArgs
|
|
842
934
|
}); },`,
|
|
843
935
|
);
|
|
@@ -888,61 +980,8 @@ function emitClientModule(
|
|
|
888
980
|
}
|
|
889
981
|
|
|
890
982
|
// ─── Prototype init emitters ─────────────────────────────────────────────────
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
* @param {string} key
|
|
894
|
-
* @param {JxMutableNode} def
|
|
895
|
-
* @returns {string}
|
|
896
|
-
*/
|
|
897
|
-
function emitRequestInit(key: string, def: JxPrototypeDef) {
|
|
898
|
-
const { url } = def;
|
|
899
|
-
const method = def.method ?? "GET";
|
|
900
|
-
const isTemplateUrl = isTemplateString(url);
|
|
901
|
-
|
|
902
|
-
if (def.manual) {
|
|
903
|
-
return `// ${key}: manual Request — fetch triggered by user action`;
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
const lines: string[] = [
|
|
907
|
-
`// ${key}: auto-fetch from ${isTemplateUrl ? "(dynamic URL)" : url}`,
|
|
908
|
-
"effect(() => {",
|
|
909
|
-
];
|
|
910
|
-
|
|
911
|
-
if (isTemplateUrl) {
|
|
912
|
-
lines.push(
|
|
913
|
-
` const url = \`${url}\`;`,
|
|
914
|
-
' if (!url || url === "undefined" || url.includes("undefined")) return;',
|
|
915
|
-
);
|
|
916
|
-
} else {
|
|
917
|
-
lines.push(` const url = ${JSON.stringify(url)};`);
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
const fetchOpts: string[] = [];
|
|
921
|
-
if (method !== "GET") {
|
|
922
|
-
fetchOpts.push(`method: ${JSON.stringify(method)}`);
|
|
923
|
-
}
|
|
924
|
-
if (def.headers) {
|
|
925
|
-
fetchOpts.push(`headers: ${JSON.stringify(def.headers)}`);
|
|
926
|
-
}
|
|
927
|
-
if (def.body) {
|
|
928
|
-
const bodyStr =
|
|
929
|
-
typeof def.body === "object"
|
|
930
|
-
? JSON.stringify(JSON.stringify(def.body))
|
|
931
|
-
: JSON.stringify(def.body);
|
|
932
|
-
fetchOpts.push(`body: ${bodyStr}`);
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
const optsStr = fetchOpts.length > 0 ? `, { ${fetchOpts.join(", ")} }` : "";
|
|
936
|
-
lines.push(
|
|
937
|
-
` fetch(url${optsStr})`,
|
|
938
|
-
" .then(r => r.ok ? r.json() : Promise.reject(r.statusText))",
|
|
939
|
-
` .then(d => { state.${key} = d; })`,
|
|
940
|
-
` .catch(e => { state.${key} = { error: String(e) }; });`,
|
|
941
|
-
"});",
|
|
942
|
-
);
|
|
943
|
-
|
|
944
|
-
return lines.join("\n");
|
|
945
|
-
}
|
|
983
|
+
// Request auto-fetch lives in shared.ts (`emitRequestFetch`) so the element target emits the same
|
|
984
|
+
// Effect against `this.state`.
|
|
946
985
|
|
|
947
986
|
/**
|
|
948
987
|
* @param {string} key
|
|
@@ -995,11 +1034,38 @@ function emitCookieInit(key: string, cookieName: string, defaultVal: unknown) {
|
|
|
995
1034
|
* @param {string} ref
|
|
996
1035
|
* @returns {string}
|
|
997
1036
|
*/
|
|
998
|
-
|
|
1037
|
+
/**
|
|
1038
|
+
* Lower a `$ref` to the JS expression that reads it inside a map callback — the mirror of the
|
|
1039
|
+
* element target's `refToExpr`/`mapRefToExpr`. Distinct from `refToBindingKey` below, which
|
|
1040
|
+
* flattens `/` to `_` to name a binding and would produce nonsense (`state.$map_item`) as an
|
|
1041
|
+
* expression.
|
|
1042
|
+
*
|
|
1043
|
+
* @param {string} ref
|
|
1044
|
+
* @returns {string}
|
|
1045
|
+
*/
|
|
1046
|
+
function mapRefToClientExpr(ref: string) {
|
|
1047
|
+
if (ref.startsWith("$map/")) {
|
|
1048
|
+
// The loop variable is an emitted identifier, so its first segment is the base, not a member.
|
|
1049
|
+
const [head, ...rest] = refSegments(ref.slice("$map/".length));
|
|
1050
|
+
return refAccessor(head ?? "", rest.map((seg) => escapeToken(seg)).join("/"));
|
|
1051
|
+
}
|
|
999
1052
|
if (ref.startsWith("#/state/")) {
|
|
1000
|
-
return ref.slice("#/state/".length)
|
|
1053
|
+
return refAccessor("state", ref.slice("#/state/".length));
|
|
1001
1054
|
}
|
|
1002
|
-
return
|
|
1055
|
+
return refAccessor("state", ref);
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
/**
|
|
1059
|
+
* The `bind`/`on` map key for a ref. It is emitted both as an object-literal key and as a
|
|
1060
|
+
* `data-bind` attribute value, so it has to survive being a JavaScript identifier and an HTML
|
|
1061
|
+
* attribute at once. Stripping the `#/state/` prefix first keeps every pure-slash ref on the key it
|
|
1062
|
+
* already had — `#/state/user/name` is still `user_name` — so this fix changes no shipped output.
|
|
1063
|
+
*
|
|
1064
|
+
* @param {string} ref
|
|
1065
|
+
* @returns {string}
|
|
1066
|
+
*/
|
|
1067
|
+
function refToBindingKey(ref: string) {
|
|
1068
|
+
return refBindingKey(ref.startsWith("#/state/") ? ref.slice("#/state/".length) : ref);
|
|
1003
1069
|
}
|
|
1004
1070
|
|
|
1005
1071
|
/**
|
|
@@ -1011,11 +1077,8 @@ function addRefBinding(bindings: Map<string, string>, key: string, ref: string)
|
|
|
1011
1077
|
if (bindings.has(key)) {
|
|
1012
1078
|
return;
|
|
1013
1079
|
}
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
} else {
|
|
1019
|
-
bindings.set(key, `() => state.${ref}`);
|
|
1020
|
-
}
|
|
1080
|
+
bindings.set(
|
|
1081
|
+
key,
|
|
1082
|
+
`() => ${refAccessor("state", ref.startsWith("#/state/") ? ref.slice("#/state/".length) : ref)}`,
|
|
1083
|
+
);
|
|
1021
1084
|
}
|