@barefootjs/go-template 0.17.0 → 0.18.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/adapter/expr/url-builder.d.ts.map +1 -1
- package/dist/adapter/go-template-adapter.d.ts +144 -14
- package/dist/adapter/go-template-adapter.d.ts.map +1 -1
- package/dist/adapter/index.js +449 -118
- package/dist/adapter/lib/compile-state.d.ts +27 -1
- package/dist/adapter/lib/compile-state.d.ts.map +1 -1
- package/dist/adapter/lib/go-emit.d.ts +9 -0
- package/dist/adapter/lib/go-emit.d.ts.map +1 -1
- package/dist/adapter/lib/go-naming.d.ts +23 -0
- package/dist/adapter/lib/go-naming.d.ts.map +1 -1
- package/dist/adapter/memo/memo-compute.d.ts +54 -5
- package/dist/adapter/memo/memo-compute.d.ts.map +1 -1
- package/dist/adapter/memo/memo-type.d.ts +10 -0
- package/dist/adapter/memo/memo-type.d.ts.map +1 -1
- package/dist/adapter/type/type-codegen.d.ts +5 -1
- package/dist/adapter/type/type-codegen.d.ts.map +1 -1
- package/dist/adapter/value/parsed-literal-to-go.d.ts +13 -4
- package/dist/adapter/value/parsed-literal-to-go.d.ts.map +1 -1
- package/dist/build.js +449 -118
- package/dist/conformance-pins.d.ts +12 -0
- package/dist/conformance-pins.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +468 -118
- package/package.json +3 -3
- package/src/__tests__/go-template-adapter.test.ts +652 -129
- package/src/__tests__/lowering-plugin.test.ts +56 -0
- package/src/adapter/expr/url-builder.ts +14 -3
- package/src/adapter/go-template-adapter.ts +637 -140
- package/src/adapter/lib/compile-state.ts +31 -0
- package/src/adapter/lib/go-emit.ts +20 -0
- package/src/adapter/lib/go-naming.ts +29 -0
- package/src/adapter/memo/memo-compute.ts +228 -18
- package/src/adapter/memo/memo-type.ts +19 -0
- package/src/adapter/type/type-codegen.ts +22 -3
- package/src/adapter/value/parsed-literal-to-go.ts +82 -9
- package/src/conformance-pins.ts +135 -0
- package/src/index.ts +1 -0
- package/src/test-render.ts +46 -8
package/dist/build.js
CHANGED
|
@@ -371,17 +371,18 @@ import {
|
|
|
371
371
|
isSupported,
|
|
372
372
|
exprToString,
|
|
373
373
|
identifierPath,
|
|
374
|
-
asCallbackMethodCall,
|
|
374
|
+
asCallbackMethodCall as asCallbackMethodCall3,
|
|
375
375
|
sortComparatorFromArrow,
|
|
376
376
|
emitParsedExpr,
|
|
377
377
|
emitIRNode,
|
|
378
378
|
emitAttrValue,
|
|
379
379
|
augmentInheritedPropAccesses,
|
|
380
380
|
collectContextConsumers,
|
|
381
|
-
|
|
381
|
+
isLowerableLoopDestructure,
|
|
382
382
|
collectModuleStringConsts as collectModuleStringConstsShared,
|
|
383
|
-
|
|
384
|
-
|
|
383
|
+
prepareLoweringMatchers,
|
|
384
|
+
envSignalReaderFor,
|
|
385
|
+
computeSsrSeedPlan
|
|
385
386
|
} from "@barefootjs/jsx";
|
|
386
387
|
import { findInterpolationEnd } from "@barefootjs/jsx/scanner";
|
|
387
388
|
import { BF_REGION } from "@barefootjs/shared";
|
|
@@ -462,6 +463,13 @@ function capitalizeFieldName(name) {
|
|
|
462
463
|
}
|
|
463
464
|
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
464
465
|
}
|
|
466
|
+
function goFieldNameForKey(key) {
|
|
467
|
+
const parts = key.split(/[^A-Za-z0-9_]+/).filter(Boolean);
|
|
468
|
+
if (parts.length === 0)
|
|
469
|
+
return "Field";
|
|
470
|
+
const name = parts.map(capitalizeFieldName).join("");
|
|
471
|
+
return /^[0-9]/.test(name) ? `Field${name}` : name;
|
|
472
|
+
}
|
|
465
473
|
function slotIdToFieldSuffix(slotId) {
|
|
466
474
|
const cleanId = slotId.startsWith("^") ? slotId.slice(1) : slotId;
|
|
467
475
|
const match = cleanId.match(/^s(\d+)$/);
|
|
@@ -564,6 +572,13 @@ function emitFlatMapEval(recv, body, param, emit) {
|
|
|
564
572
|
const env = emitEvalEnvArg(body, [param], emit);
|
|
565
573
|
return `bf_flat_map_eval ${wrapIfMultiToken(recv)} "${escapeGoString(json)}" "${param}" ${env}`;
|
|
566
574
|
}
|
|
575
|
+
function emitMapEval(recv, body, param, emit) {
|
|
576
|
+
const json = serializeParsedExpr(body);
|
|
577
|
+
if (json === null)
|
|
578
|
+
return null;
|
|
579
|
+
const env = emitEvalEnvArg(body, [param], emit);
|
|
580
|
+
return `bf_map_eval ${wrapIfMultiToken(recv)} "${escapeGoString(json)}" "${param}" ${env}`;
|
|
581
|
+
}
|
|
567
582
|
function stringTolerantEqOperands(l, r) {
|
|
568
583
|
const isStrLit = (x) => /^"(?:[^"\\]|\\.)*"$/.test(x);
|
|
569
584
|
if (isStrLit(l) === isStrLit(r))
|
|
@@ -677,6 +692,9 @@ class CompileState {
|
|
|
677
692
|
currentTypeDefinitions = [];
|
|
678
693
|
contextConsumers = [];
|
|
679
694
|
searchParamsLocals = new Set;
|
|
695
|
+
envSignalReadersByLocal = new Map;
|
|
696
|
+
ssrSeedPlan = { baseScope: [], steps: [] };
|
|
697
|
+
hoistedMemoLocals = new Map;
|
|
680
698
|
loweringMatchers = [];
|
|
681
699
|
nillablePropNames = new Set;
|
|
682
700
|
rootScopeNodes = new Set;
|
|
@@ -1024,9 +1042,12 @@ function forEachValueChild(n, visit) {
|
|
|
1024
1042
|
// src/adapter/expr/url-builder.ts
|
|
1025
1043
|
import {
|
|
1026
1044
|
parseExpression,
|
|
1027
|
-
stringifyParsedExpr
|
|
1045
|
+
stringifyParsedExpr,
|
|
1046
|
+
isValidHelperId
|
|
1028
1047
|
} from "@barefootjs/jsx";
|
|
1029
|
-
|
|
1048
|
+
function goHelperName(helper) {
|
|
1049
|
+
return isValidHelperId(helper) ? `bf_${helper}` : null;
|
|
1050
|
+
}
|
|
1030
1051
|
var BOOL_COMPARISON_OPS = new Set([
|
|
1031
1052
|
"==",
|
|
1032
1053
|
"===",
|
|
@@ -1069,7 +1090,7 @@ function lowerRegisteredCall(ctx, jsExpr, preParsed) {
|
|
|
1069
1090
|
return null;
|
|
1070
1091
|
}
|
|
1071
1092
|
function renderLoweringNode(ctx, node) {
|
|
1072
|
-
const helper =
|
|
1093
|
+
const helper = goHelperName(node.helper);
|
|
1073
1094
|
if (!helper)
|
|
1074
1095
|
return null;
|
|
1075
1096
|
const lowerExpr = (n) => ctx.convertExpressionToGo(stringifyParsedExpr(n), undefined, n);
|
|
@@ -1109,7 +1130,7 @@ function typeInfoToGo(ctx, typeInfo, defaultValue) {
|
|
|
1109
1130
|
case "object":
|
|
1110
1131
|
return "map[string]interface{}";
|
|
1111
1132
|
case "interface":
|
|
1112
|
-
if (typeInfo.raw && ctx.state.
|
|
1133
|
+
if (typeInfo.raw && (ctx.state.localStructFields.has(typeInfo.raw) || ctx.state.localTypeAliases.has(typeInfo.raw))) {
|
|
1113
1134
|
return typeInfo.raw;
|
|
1114
1135
|
}
|
|
1115
1136
|
if (typeInfo.raw) {
|
|
@@ -1142,7 +1163,7 @@ function tsTypeStringToGo(ctx, tsType) {
|
|
|
1142
1163
|
const arrayMatch = t.match(/^Array<(.+)>$/);
|
|
1143
1164
|
if (arrayMatch)
|
|
1144
1165
|
return `[]${tsTypeStringToGo(ctx, arrayMatch[1])}`;
|
|
1145
|
-
if (ctx.state.
|
|
1166
|
+
if (ctx.state.localStructFields.has(t) || ctx.state.localTypeAliases.has(t))
|
|
1146
1167
|
return t;
|
|
1147
1168
|
return "interface{}";
|
|
1148
1169
|
}
|
|
@@ -1164,6 +1185,24 @@ function inferTypeFromValue(value) {
|
|
|
1164
1185
|
}
|
|
1165
1186
|
|
|
1166
1187
|
// src/adapter/value/parsed-literal-to-go.ts
|
|
1188
|
+
function structPropertyType(ctx, structGoType, key) {
|
|
1189
|
+
const td = ctx.state.currentTypeDefinitions.find((t) => t.name === structGoType);
|
|
1190
|
+
return td?.properties?.find((p) => p.name === key)?.type;
|
|
1191
|
+
}
|
|
1192
|
+
function bakeInlineObjectAsGoMap(ctx, expr) {
|
|
1193
|
+
if (expr.kind !== "object-literal")
|
|
1194
|
+
return null;
|
|
1195
|
+
const entries = [];
|
|
1196
|
+
for (const prop of expr.properties) {
|
|
1197
|
+
if (prop.shorthand)
|
|
1198
|
+
return null;
|
|
1199
|
+
const go = prop.value.kind === "object-literal" ? bakeInlineObjectAsGoMap(ctx, prop.value) : parsedLiteralToGo(ctx, prop.value);
|
|
1200
|
+
if (go === null)
|
|
1201
|
+
return null;
|
|
1202
|
+
entries.push(`${JSON.stringify(goFieldNameForKey(prop.key))}: ${go}`);
|
|
1203
|
+
}
|
|
1204
|
+
return `map[string]interface{}{${entries.join(", ")}}`;
|
|
1205
|
+
}
|
|
1167
1206
|
function parsedLiteralToGo(ctx, expr, typeInfo) {
|
|
1168
1207
|
if (expr.kind === "unary" && expr.op === "-" && expr.argument.kind === "literal" && expr.argument.literalType === "number") {
|
|
1169
1208
|
return expr.argument.raw !== undefined ? `-${expr.argument.raw}` : null;
|
|
@@ -1204,9 +1243,16 @@ function parsedLiteralToGo(ctx, expr, typeInfo) {
|
|
|
1204
1243
|
const goField = structFields.get(prop.key);
|
|
1205
1244
|
if (!goField)
|
|
1206
1245
|
return null;
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1246
|
+
const propType = structPropertyType(ctx, goType, prop.key);
|
|
1247
|
+
let go;
|
|
1248
|
+
if (prop.value.kind === "array-literal") {
|
|
1249
|
+
go = parsedLiteralToGo(ctx, prop.value, propType);
|
|
1250
|
+
} else if (prop.value.kind === "object-literal") {
|
|
1251
|
+
const nestedGoType = propType ? typeInfoToGo(ctx, propType) : undefined;
|
|
1252
|
+
go = nestedGoType && ctx.state.localStructFields.has(nestedGoType) ? parsedLiteralToGo(ctx, prop.value, propType) : bakeInlineObjectAsGoMap(ctx, prop.value);
|
|
1253
|
+
} else {
|
|
1254
|
+
go = parsedLiteralToGo(ctx, prop.value);
|
|
1255
|
+
}
|
|
1210
1256
|
if (go === null)
|
|
1211
1257
|
return null;
|
|
1212
1258
|
entries.push(`${goField}: ${go}`);
|
|
@@ -1317,8 +1363,17 @@ function getSignalInitialValueAsGo(ctx, initialValue, propsParams, propFallbackV
|
|
|
1317
1363
|
}
|
|
1318
1364
|
|
|
1319
1365
|
// src/adapter/memo/memo-type.ts
|
|
1366
|
+
import { asCallbackMethodCall } from "@barefootjs/jsx";
|
|
1367
|
+
function isListFilterMemo(memo) {
|
|
1368
|
+
if (!memo.parsed)
|
|
1369
|
+
return false;
|
|
1370
|
+
const cb = asCallbackMethodCall(memo.parsed);
|
|
1371
|
+
return cb !== null && cb.method === "filter";
|
|
1372
|
+
}
|
|
1320
1373
|
function isBooleanMemo(ctx, memo, signals, propsParamMap) {
|
|
1321
1374
|
const c = memo.computation;
|
|
1375
|
+
if (isListFilterMemo(memo))
|
|
1376
|
+
return false;
|
|
1322
1377
|
if (isStringTernaryMemo(ctx, memo.parsed))
|
|
1323
1378
|
return false;
|
|
1324
1379
|
if (/(!==|===|!=(?!=)|==(?!=))/.test(c))
|
|
@@ -1609,6 +1664,14 @@ function computeObjectMemoInitialValue(ctx, memo) {
|
|
|
1609
1664
|
}`;
|
|
1610
1665
|
}
|
|
1611
1666
|
|
|
1667
|
+
// src/adapter/memo/memo-compute.ts
|
|
1668
|
+
import {
|
|
1669
|
+
asCallbackMethodCall as asCallbackMethodCall2,
|
|
1670
|
+
freeVarsInBody as freeVarsInBody2,
|
|
1671
|
+
materializeGetterCalls,
|
|
1672
|
+
serializeParsedExpr as serializeParsedExpr2
|
|
1673
|
+
} from "@barefootjs/jsx";
|
|
1674
|
+
|
|
1612
1675
|
// src/adapter/memo/template-interp.ts
|
|
1613
1676
|
import ts from "typescript";
|
|
1614
1677
|
function computeTemplateLiteralMemoInitialValue(ctx, memo, propsParams) {
|
|
@@ -1749,8 +1812,49 @@ function propsAccessNameFromParsed(ctx, node) {
|
|
|
1749
1812
|
|
|
1750
1813
|
// src/adapter/memo/memo-compute.ts
|
|
1751
1814
|
var EMPTY_PROP_FALLBACK_VARS2 = new Map;
|
|
1815
|
+
function getterCallName(e) {
|
|
1816
|
+
return e.kind === "call" && e.callee.kind === "identifier" && e.args.length === 0 ? e.callee.name : null;
|
|
1817
|
+
}
|
|
1818
|
+
function propsMemberName(e) {
|
|
1819
|
+
return e.kind === "member" && !e.computed && e.object.kind === "identifier" && e.object.name === "props" ? e.property : null;
|
|
1820
|
+
}
|
|
1821
|
+
function matchFilterArmMemo(ctx, body, signals, propsParams) {
|
|
1822
|
+
const cb = asCallbackMethodCall2(body);
|
|
1823
|
+
if (!cb || cb.method !== "filter")
|
|
1824
|
+
return null;
|
|
1825
|
+
const propName = propsMemberName(cb.object);
|
|
1826
|
+
const param = propName ? propsParams.find((p) => p.name === propName) : undefined;
|
|
1827
|
+
if (!propName || !param)
|
|
1828
|
+
return null;
|
|
1829
|
+
const knownGetterNames = new Set(ctx.state.ssrSeedPlan.steps.filter((s) => s.kind !== "env-reader").map((s) => s.name));
|
|
1830
|
+
const materialized = materializeGetterCalls(cb.arrow.body, knownGetterNames);
|
|
1831
|
+
const predJSON = serializeParsedExpr2(materialized);
|
|
1832
|
+
if (predJSON === null)
|
|
1833
|
+
return null;
|
|
1834
|
+
const paramName = cb.arrow.params[0] ?? "_";
|
|
1835
|
+
const freeVars = freeVarsInBody2(materialized, new Set(cb.arrow.params));
|
|
1836
|
+
return { propName, predJSON, paramName, freeVars };
|
|
1837
|
+
}
|
|
1838
|
+
function filterArmEarlierSiblingRefs(ctx, memo, signals, propsParams) {
|
|
1839
|
+
if (!memo.parsed)
|
|
1840
|
+
return [];
|
|
1841
|
+
const match = matchFilterArmMemo(ctx, memo.parsed, signals, propsParams);
|
|
1842
|
+
if (!match)
|
|
1843
|
+
return [];
|
|
1844
|
+
const memos = ctx.state.currentMemos ?? [];
|
|
1845
|
+
const currentIndex = memos.findIndex((m) => m.name === memo.name);
|
|
1846
|
+
if (currentIndex < 0)
|
|
1847
|
+
return [];
|
|
1848
|
+
const refs = [];
|
|
1849
|
+
for (const name of match.freeVars) {
|
|
1850
|
+
const idx = memos.findIndex((m) => m.name === name);
|
|
1851
|
+
if (idx >= 0 && idx < currentIndex)
|
|
1852
|
+
refs.push(name);
|
|
1853
|
+
}
|
|
1854
|
+
return refs;
|
|
1855
|
+
}
|
|
1752
1856
|
function computeMemoInitialValue(ctx, memo, signals, propsParams, propFallbackVars = EMPTY_PROP_FALLBACK_VARS2, goType) {
|
|
1753
|
-
const resolved = computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFallbackVars);
|
|
1857
|
+
const resolved = computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFallbackVars, new Set([memo.name]));
|
|
1754
1858
|
if (resolved !== null)
|
|
1755
1859
|
return resolved;
|
|
1756
1860
|
if (goType === "bool")
|
|
@@ -1762,15 +1866,79 @@ function computeMemoInitialValue(ctx, memo, signals, propsParams, propFallbackVa
|
|
|
1762
1866
|
}
|
|
1763
1867
|
return "0";
|
|
1764
1868
|
}
|
|
1765
|
-
function memoInitialFromParsedBody(ctx, body, signals, propsParams, propFallbackVars) {
|
|
1869
|
+
function memoInitialFromParsedBody(ctx, body, signals, propsParams, propFallbackVars, currentMemoName, resolving = new Set) {
|
|
1766
1870
|
const propRef = (propName) => {
|
|
1767
1871
|
const hoisted = propFallbackVars.get(propName);
|
|
1768
1872
|
if (hoisted)
|
|
1769
1873
|
return hoisted.varName;
|
|
1770
1874
|
return `in.${capitalizeFieldName(propName)}`;
|
|
1771
1875
|
};
|
|
1772
|
-
const
|
|
1773
|
-
|
|
1876
|
+
const envGetKey = (e) => {
|
|
1877
|
+
if (e.kind !== "call" || e.callee.kind !== "member" || e.callee.computed)
|
|
1878
|
+
return null;
|
|
1879
|
+
const recvName = getterCallName(e.callee.object);
|
|
1880
|
+
if (recvName === null)
|
|
1881
|
+
return null;
|
|
1882
|
+
const reader = ctx.state.envSignalReadersByLocal.get(recvName);
|
|
1883
|
+
if (!reader || !reader.methods.has(e.callee.property))
|
|
1884
|
+
return null;
|
|
1885
|
+
const arg = e.args[0];
|
|
1886
|
+
if (!arg || arg.kind !== "literal" || arg.literalType !== "string")
|
|
1887
|
+
return null;
|
|
1888
|
+
return { key: String(arg.value), fieldName: capitalizeFieldName(reader.canonicalName) };
|
|
1889
|
+
};
|
|
1890
|
+
{
|
|
1891
|
+
const m = envGetKey(body);
|
|
1892
|
+
if (m !== null)
|
|
1893
|
+
return `in.${m.fieldName}.Get(${JSON.stringify(m.key)})`;
|
|
1894
|
+
}
|
|
1895
|
+
if (body.kind === "logical" && (body.op === "??" || body.op === "||") && body.right.kind === "literal" && body.right.literalType === "string") {
|
|
1896
|
+
const m = envGetKey(body.left);
|
|
1897
|
+
if (m !== null) {
|
|
1898
|
+
const def = JSON.stringify(String(body.right.value));
|
|
1899
|
+
return `func() string { if v := in.${m.fieldName}.Get(${JSON.stringify(m.key)}); v != "" { return v }; return ${def} }()`;
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
{
|
|
1903
|
+
const match = matchFilterArmMemo(ctx, body, signals, propsParams);
|
|
1904
|
+
if (match) {
|
|
1905
|
+
const { propName, predJSON, paramName, freeVars } = match;
|
|
1906
|
+
const currentIndex = (ctx.state.currentMemos ?? []).findIndex((m) => m.name === currentMemoName);
|
|
1907
|
+
const envEntries = [];
|
|
1908
|
+
let unresolved = false;
|
|
1909
|
+
for (const name of freeVars) {
|
|
1910
|
+
let goExpr = null;
|
|
1911
|
+
const siblingIndex = (ctx.state.currentMemos ?? []).findIndex((m) => m.name === name);
|
|
1912
|
+
if (siblingIndex >= 0) {
|
|
1913
|
+
const siblingMemo = ctx.state.currentMemos[siblingIndex];
|
|
1914
|
+
const eligible = currentIndex >= 0 && siblingIndex < currentIndex && !resolving.has(siblingMemo.name);
|
|
1915
|
+
if (eligible) {
|
|
1916
|
+
const hoisted = ctx.state.hoistedMemoLocals.get(siblingMemo.name);
|
|
1917
|
+
goExpr = hoisted ?? computeMemoInitialValueOrNull(ctx, siblingMemo, signals, propsParams, propFallbackVars, new Set([...resolving, siblingMemo.name]));
|
|
1918
|
+
}
|
|
1919
|
+
} else {
|
|
1920
|
+
const sig = signals.find((s) => s.getter === name);
|
|
1921
|
+
if (sig) {
|
|
1922
|
+
goExpr = getSignalInitialValueAsGo(ctx, sig.initialValue, propsParams, propFallbackVars);
|
|
1923
|
+
} else {
|
|
1924
|
+
const p = propsParams.find((pp) => pp.name === name);
|
|
1925
|
+
if (p)
|
|
1926
|
+
goExpr = propRef(name);
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
if (goExpr === null) {
|
|
1930
|
+
unresolved = true;
|
|
1931
|
+
break;
|
|
1932
|
+
}
|
|
1933
|
+
envEntries.push(`${JSON.stringify(name)}: ${goExpr}`);
|
|
1934
|
+
}
|
|
1935
|
+
if (!unresolved) {
|
|
1936
|
+
const itemsField = `in.${capitalizeFieldName(propName)}`;
|
|
1937
|
+
const envMap = `map[string]any{${envEntries.join(", ")}}`;
|
|
1938
|
+
return `bf.FilterEval(${itemsField}, "${escapeGoString(predJSON)}", ${JSON.stringify(paramName)}, ${envMap})`;
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1774
1942
|
if (body.kind === "binary" && ["===", "!==", "==", "!="].includes(body.op) && body.right.kind === "literal" && body.right.literalType === "string") {
|
|
1775
1943
|
const depName = getterCallName(body.left);
|
|
1776
1944
|
if (depName) {
|
|
@@ -1809,8 +1977,8 @@ function memoInitialFromParsedBody(ctx, body, signals, propsParams, propFallback
|
|
|
1809
1977
|
condGo = getSignalInitialValueAsGo(ctx, condSignal.initialValue, propsParams, propFallbackVars);
|
|
1810
1978
|
} else {
|
|
1811
1979
|
const condMemo = (ctx.state.currentMemos ?? []).find((m) => m.name === condName);
|
|
1812
|
-
if (condMemo) {
|
|
1813
|
-
condGo = computeMemoInitialValueOrNull(ctx, condMemo, signals, propsParams, propFallbackVars);
|
|
1980
|
+
if (condMemo && !resolving.has(condMemo.name)) {
|
|
1981
|
+
condGo = computeMemoInitialValueOrNull(ctx, condMemo, signals, propsParams, propFallbackVars, new Set([...resolving, condMemo.name]));
|
|
1814
1982
|
}
|
|
1815
1983
|
}
|
|
1816
1984
|
if (condGo === "true")
|
|
@@ -1884,17 +2052,17 @@ function memoInitialFromParsedBody(ctx, body, signals, propsParams, propFallback
|
|
|
1884
2052
|
}
|
|
1885
2053
|
return null;
|
|
1886
2054
|
}
|
|
1887
|
-
function computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFallbackVars = EMPTY_PROP_FALLBACK_VARS2) {
|
|
2055
|
+
function computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFallbackVars = EMPTY_PROP_FALLBACK_VARS2, resolving = new Set) {
|
|
1888
2056
|
const computation = memo.computation;
|
|
1889
2057
|
const tmplMemo = computeTemplateLiteralMemoInitialValue(ctx, memo, propsParams);
|
|
1890
2058
|
if (tmplMemo !== null)
|
|
1891
2059
|
return tmplMemo;
|
|
1892
2060
|
if (memo.parsed) {
|
|
1893
|
-
const fromParsed = memoInitialFromParsedBody(ctx, memo.parsed, signals, propsParams, propFallbackVars);
|
|
2061
|
+
const fromParsed = memoInitialFromParsedBody(ctx, memo.parsed, signals, propsParams, propFallbackVars, memo.name, resolving);
|
|
1894
2062
|
if (fromParsed !== null)
|
|
1895
2063
|
return fromParsed;
|
|
1896
2064
|
}
|
|
1897
|
-
const cmpTernary = computeComparisonTernaryGo(ctx, memo.parsed, signals, propsParams, propFallbackVars);
|
|
2065
|
+
const cmpTernary = computeComparisonTernaryGo(ctx, memo.parsed, signals, propsParams, propFallbackVars, resolving);
|
|
1898
2066
|
if (cmpTernary !== null)
|
|
1899
2067
|
return cmpTernary;
|
|
1900
2068
|
const blockReturn = resolveBlockBodyMemoModuleConst(ctx, memo, signals);
|
|
@@ -1906,20 +2074,22 @@ function computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFall
|
|
|
1906
2074
|
return objMemo;
|
|
1907
2075
|
return null;
|
|
1908
2076
|
}
|
|
1909
|
-
function resolveGetterValueAsGo(ctx, name, signals, propsParams, propFallbackVars) {
|
|
2077
|
+
function resolveGetterValueAsGo(ctx, name, signals, propsParams, propFallbackVars, resolving = new Set) {
|
|
1910
2078
|
const signal = signals.find((s) => s.getter === name);
|
|
1911
2079
|
if (signal) {
|
|
1912
2080
|
return getSignalInitialValueAsGo(ctx, signal.initialValue, propsParams, propFallbackVars);
|
|
1913
2081
|
}
|
|
1914
2082
|
const memo = (ctx.state.currentMemos ?? []).find((m) => m.name === name);
|
|
1915
2083
|
if (memo) {
|
|
2084
|
+
if (resolving.has(memo.name))
|
|
2085
|
+
return null;
|
|
1916
2086
|
const stripped = memo.computation.replace(/^\(\)\s*=>\s*/, "");
|
|
1917
2087
|
const fb = ctx.extractPropFallback(stripped);
|
|
1918
2088
|
if (fb && capitalizeFieldName(fb.propName) === capitalizeFieldName(memo.name)) {
|
|
1919
2089
|
const field = `in.${capitalizeFieldName(fb.propName)}`;
|
|
1920
2090
|
return `func() interface{} { v := interface{}(${field}); if v == nil || v == "" { return ${fb.goFallback} }; return v }()`;
|
|
1921
2091
|
}
|
|
1922
|
-
return computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFallbackVars);
|
|
2092
|
+
return computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFallbackVars, new Set([...resolving, memo.name]));
|
|
1923
2093
|
}
|
|
1924
2094
|
const param = propsParams.find((p) => p.name === name);
|
|
1925
2095
|
if (param) {
|
|
@@ -1928,7 +2098,7 @@ function resolveGetterValueAsGo(ctx, name, signals, propsParams, propFallbackVar
|
|
|
1928
2098
|
}
|
|
1929
2099
|
return null;
|
|
1930
2100
|
}
|
|
1931
|
-
function computeComparisonTernaryGo(ctx, parsed, signals, propsParams, propFallbackVars) {
|
|
2101
|
+
function computeComparisonTernaryGo(ctx, parsed, signals, propsParams, propFallbackVars, resolving = new Set) {
|
|
1932
2102
|
if (!parsed || parsed.kind !== "conditional")
|
|
1933
2103
|
return null;
|
|
1934
2104
|
const cond = parsed.test;
|
|
@@ -1953,16 +2123,16 @@ function computeComparisonTernaryGo(ctx, parsed, signals, propsParams, propFallb
|
|
|
1953
2123
|
const f = branch(parsed.alternate);
|
|
1954
2124
|
if (t === null || f === null)
|
|
1955
2125
|
return null;
|
|
1956
|
-
const condGo = resolveComparisonOperandGo(ctx, cond.left, signals, propsParams, propFallbackVars);
|
|
2126
|
+
const condGo = resolveComparisonOperandGo(ctx, cond.left, signals, propsParams, propFallbackVars, resolving);
|
|
1957
2127
|
if (condGo === null)
|
|
1958
2128
|
return null;
|
|
1959
2129
|
const eqBranch = isEq ? t : f;
|
|
1960
2130
|
const neBranch = isEq ? f : t;
|
|
1961
2131
|
return `func() string { if ${condGo} == ${JSON.stringify(cond.right.value)} { return ${eqBranch} }; return ${neBranch} }()`;
|
|
1962
2132
|
}
|
|
1963
|
-
function resolveComparisonOperandGo(ctx, node, signals, propsParams, propFallbackVars) {
|
|
2133
|
+
function resolveComparisonOperandGo(ctx, node, signals, propsParams, propFallbackVars, resolving = new Set) {
|
|
1964
2134
|
if (node.kind === "call" && node.callee.kind === "identifier" && node.args.length === 0) {
|
|
1965
|
-
return resolveGetterValueAsGo(ctx, node.callee.name, signals, propsParams, propFallbackVars);
|
|
2135
|
+
return resolveGetterValueAsGo(ctx, node.callee.name, signals, propsParams, propFallbackVars, resolving);
|
|
1966
2136
|
}
|
|
1967
2137
|
if (node.kind === "logical" && node.op === "??" && node.right.kind === "literal" && node.right.literalType === "string") {
|
|
1968
2138
|
const propName = propsAccessNameFromParsed2(ctx, node.left);
|
|
@@ -2320,8 +2490,10 @@ class GoTemplateAdapter extends BaseAdapter {
|
|
|
2320
2490
|
inLoop = false;
|
|
2321
2491
|
loopParamStack = [];
|
|
2322
2492
|
loopScalarItemStack = [];
|
|
2493
|
+
loopWrapperStack = [];
|
|
2323
2494
|
loopVarRefCount = new Map;
|
|
2324
2495
|
loopBindingStack = [];
|
|
2496
|
+
loopRestExcludeStack = [];
|
|
2325
2497
|
childComponentShapes = new Map;
|
|
2326
2498
|
childContextConsumers = new Map;
|
|
2327
2499
|
constructor(options = {}) {
|
|
@@ -2341,7 +2513,18 @@ class GoTemplateAdapter extends BaseAdapter {
|
|
|
2341
2513
|
this.state.currentMemos = ir.metadata.memos ?? [];
|
|
2342
2514
|
this.state.currentTypeDefinitions = ir.metadata.typeDefinitions ?? [];
|
|
2343
2515
|
this.state.contextConsumers = collectContextConsumers(ir.metadata);
|
|
2344
|
-
this.state.
|
|
2516
|
+
this.state.ssrSeedPlan = ir.metadata.ssrSeedPlan ?? computeSsrSeedPlan(ir.metadata);
|
|
2517
|
+
this.state.envSignalReadersByLocal = new Map;
|
|
2518
|
+
this.state.searchParamsLocals = new Set;
|
|
2519
|
+
for (const step of this.state.ssrSeedPlan.steps) {
|
|
2520
|
+
if (step.kind !== "env-reader")
|
|
2521
|
+
continue;
|
|
2522
|
+
const reader = envSignalReaderFor(step.reader.key);
|
|
2523
|
+
if (reader)
|
|
2524
|
+
this.state.envSignalReadersByLocal.set(step.name, reader);
|
|
2525
|
+
if (step.reader.key === "search")
|
|
2526
|
+
this.state.searchParamsLocals.add(step.name);
|
|
2527
|
+
}
|
|
2345
2528
|
this.state.loweringMatchers = prepareLoweringMatchers(ir.metadata);
|
|
2346
2529
|
augmentInheritedPropAccesses(ir);
|
|
2347
2530
|
}
|
|
@@ -2503,11 +2686,22 @@ ${scriptRegistrations}${templateBody}
|
|
|
2503
2686
|
contextFieldName(c) {
|
|
2504
2687
|
return capitalizeFieldName(c.localName);
|
|
2505
2688
|
}
|
|
2689
|
+
isMapRootedContextChain(node) {
|
|
2690
|
+
if (node.kind === "identifier") {
|
|
2691
|
+
return this.state.contextConsumers.some((c) => c.localName === node.name && c.defaultKind === "object");
|
|
2692
|
+
}
|
|
2693
|
+
if (node.kind === "member" && !node.computed) {
|
|
2694
|
+
return this.isMapRootedContextChain(node.object);
|
|
2695
|
+
}
|
|
2696
|
+
return false;
|
|
2697
|
+
}
|
|
2506
2698
|
contextConsumerGoType(c) {
|
|
2507
2699
|
if (typeof c.defaultValue === "number")
|
|
2508
2700
|
return "int";
|
|
2509
2701
|
if (typeof c.defaultValue === "boolean")
|
|
2510
2702
|
return "bool";
|
|
2703
|
+
if (c.defaultKind === "object")
|
|
2704
|
+
return "map[string]interface{}";
|
|
2511
2705
|
return "string";
|
|
2512
2706
|
}
|
|
2513
2707
|
contextConsumerGoDefault(c) {
|
|
@@ -2517,6 +2711,8 @@ ${scriptRegistrations}${templateBody}
|
|
|
2517
2711
|
return String(c.defaultValue);
|
|
2518
2712
|
if (typeof c.defaultValue === "string")
|
|
2519
2713
|
return `"${escapeGoString(c.defaultValue)}"`;
|
|
2714
|
+
if (c.defaultKind === "object")
|
|
2715
|
+
return "map[string]interface{}{}";
|
|
2520
2716
|
return '""';
|
|
2521
2717
|
}
|
|
2522
2718
|
nonCollidingContextConsumers(taken) {
|
|
@@ -2563,12 +2759,15 @@ ${goFields.join(`
|
|
|
2563
2759
|
}
|
|
2564
2760
|
structFieldsFor(td) {
|
|
2565
2761
|
const fields = [];
|
|
2762
|
+
const seenGoNames = new Set;
|
|
2566
2763
|
for (const prop of td.properties ?? []) {
|
|
2567
|
-
|
|
2764
|
+
const goName = goFieldNameForKey(prop.name);
|
|
2765
|
+
if (seenGoNames.has(goName))
|
|
2568
2766
|
continue;
|
|
2767
|
+
seenGoNames.add(goName);
|
|
2569
2768
|
fields.push({
|
|
2570
2769
|
tsName: prop.name,
|
|
2571
|
-
goName
|
|
2770
|
+
goName,
|
|
2572
2771
|
goType: typeInfoToGo(this.emitCtx, prop.type)
|
|
2573
2772
|
});
|
|
2574
2773
|
}
|
|
@@ -2796,10 +2995,10 @@ ${goFields.join(`
|
|
|
2796
2995
|
}
|
|
2797
2996
|
return "interface{}";
|
|
2798
2997
|
}
|
|
2799
|
-
collectBodyChildInstances(bodyChildren) {
|
|
2998
|
+
collectBodyChildInstances(bodyChildren, propsParams = []) {
|
|
2800
2999
|
const result = [];
|
|
2801
3000
|
for (const child of bodyChildren) {
|
|
2802
|
-
this.collectStaticChildInstancesRecursive(child, result, false, new Map);
|
|
3001
|
+
this.collectStaticChildInstancesRecursive(child, result, false, new Map, propsParams);
|
|
2803
3002
|
}
|
|
2804
3003
|
return result;
|
|
2805
3004
|
}
|
|
@@ -2845,6 +3044,28 @@ ${goFields.join(`
|
|
|
2845
3044
|
if (propFallbackVars.size > 0)
|
|
2846
3045
|
lines.push("");
|
|
2847
3046
|
this.emitDynamicBodyWrappers(lines, ir, componentName, dynamicWithBody, propFallbackVars, emittedWrapperVars);
|
|
3047
|
+
const memoPropsParamMap = new Map(ir.metadata.propsParams.map((p) => [p.name, p]));
|
|
3048
|
+
this.state.hoistedMemoLocals = new Map;
|
|
3049
|
+
const hoistNames = new Set;
|
|
3050
|
+
for (const memo of ir.metadata.memos) {
|
|
3051
|
+
for (const name of filterArmEarlierSiblingRefs(this.emitCtx, memo, ir.metadata.signals, ir.metadata.propsParams)) {
|
|
3052
|
+
hoistNames.add(name);
|
|
3053
|
+
}
|
|
3054
|
+
}
|
|
3055
|
+
if (hoistNames.size > 0) {
|
|
3056
|
+
for (const memo of ir.metadata.memos) {
|
|
3057
|
+
if (!hoistNames.has(memo.name))
|
|
3058
|
+
continue;
|
|
3059
|
+
const goType = this.inferMemoType(memo, ir.metadata.signals, memoPropsParamMap);
|
|
3060
|
+
const value = computeMemoInitialValue(this.emitCtx, memo, ir.metadata.signals, ir.metadata.propsParams, propFallbackVars, goType);
|
|
3061
|
+
let localName = `memo${capitalizeFieldName(memo.name)}`;
|
|
3062
|
+
while (GO_KEYWORDS.has(localName))
|
|
3063
|
+
localName += "_";
|
|
3064
|
+
lines.push(` var ${localName} ${goType} = ${value}`);
|
|
3065
|
+
this.state.hoistedMemoLocals.set(memo.name, localName);
|
|
3066
|
+
}
|
|
3067
|
+
lines.push("");
|
|
3068
|
+
}
|
|
2848
3069
|
lines.push(` return ${propsTypeName}{`);
|
|
2849
3070
|
lines.push("\t\tScopeID: scopeID,");
|
|
2850
3071
|
lines.push("\t\tBfParent: in.BfParent,");
|
|
@@ -2918,11 +3139,15 @@ ${goFields.join(`
|
|
|
2918
3139
|
continue;
|
|
2919
3140
|
lines.push(` ${nested.name}s: ${varName},`);
|
|
2920
3141
|
}
|
|
2921
|
-
const memoPropsParamMap = new Map(ir.metadata.propsParams.map((p) => [p.name, p]));
|
|
2922
3142
|
for (const memo of ir.metadata.memos) {
|
|
2923
3143
|
const fieldName = capitalizeFieldName(memo.name);
|
|
2924
3144
|
if (propFieldNames.has(fieldName))
|
|
2925
3145
|
continue;
|
|
3146
|
+
const hoistedLocal = this.state.hoistedMemoLocals.get(memo.name);
|
|
3147
|
+
if (hoistedLocal) {
|
|
3148
|
+
lines.push(` ${fieldName}: ${hoistedLocal},`);
|
|
3149
|
+
continue;
|
|
3150
|
+
}
|
|
2926
3151
|
const goType = this.inferMemoType(memo, ir.metadata.signals, memoPropsParamMap);
|
|
2927
3152
|
const memoValue = computeMemoInitialValue(this.emitCtx, memo, ir.metadata.signals, ir.metadata.propsParams, propFallbackVars, goType);
|
|
2928
3153
|
lines.push(` ${fieldName}: ${memoValue},`);
|
|
@@ -2943,7 +3168,7 @@ ${goFields.join(`
|
|
|
2943
3168
|
for (const c of this.nonCollidingContextConsumers(takenInit)) {
|
|
2944
3169
|
const field = this.contextFieldName(c);
|
|
2945
3170
|
const def = this.contextConsumerGoDefault(c);
|
|
2946
|
-
const defaulted = c.defaultValue === null || def === '""' || def === "0" || def === "false" ? `in.${field}` : applyGoFallback(`in.${field}`, def);
|
|
3171
|
+
const defaulted = c.defaultValue === null || def === '""' || def === "0" || def === "false" || def === "map[string]interface{}{}" ? `in.${field}` : applyGoFallback(`in.${field}`, def);
|
|
2947
3172
|
lines.push(` ${field}: ${defaulted},`);
|
|
2948
3173
|
}
|
|
2949
3174
|
this.emitStaticChildInstances(lines, ir);
|
|
@@ -2952,7 +3177,7 @@ ${goFields.join(`
|
|
|
2952
3177
|
lines.push("}");
|
|
2953
3178
|
}
|
|
2954
3179
|
emitStaticChildInstances(lines, ir) {
|
|
2955
|
-
const staticChildren = this.collectStaticChildInstances(ir.root);
|
|
3180
|
+
const staticChildren = this.collectStaticChildInstances(ir.root, ir.metadata.propsParams);
|
|
2956
3181
|
for (const child of staticChildren) {
|
|
2957
3182
|
lines.push(` ${child.fieldName}: New${child.name}Props(${child.name}Input{`);
|
|
2958
3183
|
lines.push(` ScopeID: scopeID + "_${child.slotId}",`);
|
|
@@ -3084,7 +3309,7 @@ ${goFields.join(`
|
|
|
3084
3309
|
const varName = `${nested.name.charAt(0).toLowerCase()}${nested.name.slice(1)}s`;
|
|
3085
3310
|
const wrapperType = this.loopBodyWrapperName(componentName, nested);
|
|
3086
3311
|
const datumFields = this.resolveLoopDatumFields(nested.loopItemType);
|
|
3087
|
-
const bodyChildInstances = this.collectBodyChildInstances(nested.bodyChildren);
|
|
3312
|
+
const bodyChildInstances = this.collectBodyChildInstances(nested.bodyChildren, ir.metadata.propsParams);
|
|
3088
3313
|
for (const child of bodyChildInstances) {
|
|
3089
3314
|
const childVar = `child_${child.fieldName}`;
|
|
3090
3315
|
lines.push(` ${childVar} := New${child.name}Props(${child.name}Input{`);
|
|
@@ -3161,7 +3386,7 @@ ${goFields.join(`
|
|
|
3161
3386
|
const wrapperType = this.loopBodyWrapperName(componentName, nested);
|
|
3162
3387
|
const varName = `${nested.name.charAt(0).toLowerCase()}${nested.name.slice(1)}s`;
|
|
3163
3388
|
const datumFields = this.resolveLoopDatumFields(nested.loopItemType);
|
|
3164
|
-
const bodyChildInstances = this.collectBodyChildInstances(nested.bodyChildren);
|
|
3389
|
+
const bodyChildInstances = this.collectBodyChildInstances(nested.bodyChildren, ir.metadata.propsParams);
|
|
3165
3390
|
for (const child of bodyChildInstances) {
|
|
3166
3391
|
const childVar = `child_${child.fieldName}`;
|
|
3167
3392
|
lines.push(` ${childVar} := New${child.name}Props(${child.name}Input{`);
|
|
@@ -3401,7 +3626,7 @@ ${goFields.join(`
|
|
|
3401
3626
|
lines.push(` ${nested.name}s []${elemType} \`json:"${jsonTag}"\``);
|
|
3402
3627
|
}
|
|
3403
3628
|
}
|
|
3404
|
-
const staticChildren = this.collectStaticChildInstances(ir.root);
|
|
3629
|
+
const staticChildren = this.collectStaticChildInstances(ir.root, ir.metadata.propsParams);
|
|
3405
3630
|
for (const child of staticChildren) {
|
|
3406
3631
|
lines.push(` ${child.fieldName} ${child.name}Props \`json:"-"\``);
|
|
3407
3632
|
}
|
|
@@ -3413,9 +3638,9 @@ ${goFields.join(`
|
|
|
3413
3638
|
toJsonTag(name) {
|
|
3414
3639
|
return name.charAt(0).toLowerCase() + name.slice(1);
|
|
3415
3640
|
}
|
|
3416
|
-
collectStaticChildInstances(node) {
|
|
3641
|
+
collectStaticChildInstances(node, propsParams = []) {
|
|
3417
3642
|
const result = [];
|
|
3418
|
-
this.collectStaticChildInstancesRecursive(node, result, false, new Map);
|
|
3643
|
+
this.collectStaticChildInstancesRecursive(node, result, false, new Map, propsParams);
|
|
3419
3644
|
return result;
|
|
3420
3645
|
}
|
|
3421
3646
|
extractTextChildren(children) {
|
|
@@ -3460,12 +3685,12 @@ ${goFields.join(`
|
|
|
3460
3685
|
return null;
|
|
3461
3686
|
return withSentinel.split(GoTemplateAdapter.SCOPE_SENTINEL).map((seg) => JSON.stringify(seg)).join(" + scopeID + ");
|
|
3462
3687
|
}
|
|
3463
|
-
collectStaticChildInstancesRecursive(node, result, inLoop, providerCtx) {
|
|
3688
|
+
collectStaticChildInstancesRecursive(node, result, inLoop, providerCtx, propsParams = []) {
|
|
3464
3689
|
if (node.type === "component") {
|
|
3465
3690
|
const comp = node;
|
|
3466
3691
|
if (comp.dynamicTag) {
|
|
3467
3692
|
for (const child of comp.children) {
|
|
3468
|
-
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx);
|
|
3693
|
+
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx, propsParams);
|
|
3469
3694
|
}
|
|
3470
3695
|
return;
|
|
3471
3696
|
}
|
|
@@ -3483,69 +3708,111 @@ ${goFields.join(`
|
|
|
3483
3708
|
contextBindings: providerCtx.size > 0 ? providerCtx : undefined
|
|
3484
3709
|
});
|
|
3485
3710
|
for (const child of effectiveChildren) {
|
|
3486
|
-
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx);
|
|
3711
|
+
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx, propsParams);
|
|
3487
3712
|
}
|
|
3488
3713
|
}
|
|
3489
3714
|
if (comp.name === "Portal" && comp.children) {
|
|
3490
3715
|
for (const child of comp.children) {
|
|
3491
|
-
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx);
|
|
3716
|
+
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx, propsParams);
|
|
3492
3717
|
}
|
|
3493
3718
|
}
|
|
3494
3719
|
} else if (node.type === "loop") {
|
|
3495
3720
|
const loop = node;
|
|
3496
3721
|
for (const child of loop.children) {
|
|
3497
|
-
this.collectStaticChildInstancesRecursive(child, result,
|
|
3722
|
+
this.collectStaticChildInstancesRecursive(child, result, inLoop || !!loop.childComponent, providerCtx, propsParams);
|
|
3498
3723
|
}
|
|
3499
3724
|
} else if (node.type === "element") {
|
|
3500
3725
|
const element = node;
|
|
3501
3726
|
for (const child of element.children) {
|
|
3502
|
-
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx);
|
|
3727
|
+
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx, propsParams);
|
|
3503
3728
|
}
|
|
3504
3729
|
} else if (node.type === "fragment") {
|
|
3505
3730
|
const fragment = node;
|
|
3506
3731
|
for (const child of fragment.children) {
|
|
3507
|
-
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx);
|
|
3732
|
+
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx, propsParams);
|
|
3508
3733
|
}
|
|
3509
3734
|
} else if (node.type === "conditional") {
|
|
3510
3735
|
const cond = node;
|
|
3511
|
-
this.collectStaticChildInstancesRecursive(cond.whenTrue, result, inLoop, providerCtx);
|
|
3736
|
+
this.collectStaticChildInstancesRecursive(cond.whenTrue, result, inLoop, providerCtx, propsParams);
|
|
3512
3737
|
if (cond.whenFalse) {
|
|
3513
|
-
this.collectStaticChildInstancesRecursive(cond.whenFalse, result, inLoop, providerCtx);
|
|
3738
|
+
this.collectStaticChildInstancesRecursive(cond.whenFalse, result, inLoop, providerCtx, propsParams);
|
|
3514
3739
|
}
|
|
3515
3740
|
} else if (node.type === "if-statement") {
|
|
3516
3741
|
const stmt = node;
|
|
3517
|
-
this.collectStaticChildInstancesRecursive(stmt.consequent, result, inLoop, providerCtx);
|
|
3742
|
+
this.collectStaticChildInstancesRecursive(stmt.consequent, result, inLoop, providerCtx, propsParams);
|
|
3518
3743
|
if (stmt.alternate) {
|
|
3519
|
-
this.collectStaticChildInstancesRecursive(stmt.alternate, result, inLoop, providerCtx);
|
|
3744
|
+
this.collectStaticChildInstancesRecursive(stmt.alternate, result, inLoop, providerCtx, propsParams);
|
|
3520
3745
|
}
|
|
3521
3746
|
} else if (node.type === "provider") {
|
|
3522
3747
|
const p = node;
|
|
3523
|
-
const childCtx = this.extendProviderContext(providerCtx, p);
|
|
3748
|
+
const childCtx = this.extendProviderContext(providerCtx, p, propsParams);
|
|
3524
3749
|
for (const child of p.children) {
|
|
3525
|
-
this.collectStaticChildInstancesRecursive(child, result, inLoop, childCtx);
|
|
3750
|
+
this.collectStaticChildInstancesRecursive(child, result, inLoop, childCtx, propsParams);
|
|
3526
3751
|
}
|
|
3527
3752
|
} else if (node.type === "async") {
|
|
3528
3753
|
const a = node;
|
|
3529
|
-
this.collectStaticChildInstancesRecursive(a.fallback, result, inLoop, providerCtx);
|
|
3754
|
+
this.collectStaticChildInstancesRecursive(a.fallback, result, inLoop, providerCtx, propsParams);
|
|
3530
3755
|
for (const child of a.children) {
|
|
3531
|
-
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx);
|
|
3756
|
+
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx, propsParams);
|
|
3532
3757
|
}
|
|
3533
3758
|
}
|
|
3534
3759
|
}
|
|
3535
|
-
extendProviderContext(current, p) {
|
|
3760
|
+
extendProviderContext(current, p, propsParams) {
|
|
3536
3761
|
const v = p.valueProp?.value;
|
|
3537
|
-
if (!v
|
|
3762
|
+
if (!v)
|
|
3538
3763
|
return current;
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3764
|
+
if (v.kind === "literal") {
|
|
3765
|
+
let goLit = null;
|
|
3766
|
+
if (typeof v.value === "string")
|
|
3767
|
+
goLit = `"${escapeGoString(v.value)}"`;
|
|
3768
|
+
else if (typeof v.value === "number" || typeof v.value === "boolean")
|
|
3769
|
+
goLit = String(v.value);
|
|
3770
|
+
if (goLit === null)
|
|
3771
|
+
return current;
|
|
3772
|
+
const next = new Map(current);
|
|
3773
|
+
next.set(p.contextName, goLit);
|
|
3774
|
+
return next;
|
|
3775
|
+
}
|
|
3776
|
+
if (v.kind === "expression" && v.parsed) {
|
|
3777
|
+
const goMap = this.providerObjectValueToGoMap(v.parsed, propsParams);
|
|
3778
|
+
if (goMap !== null) {
|
|
3779
|
+
const next = new Map(current);
|
|
3780
|
+
next.set(p.contextName, goMap);
|
|
3781
|
+
return next;
|
|
3782
|
+
}
|
|
3783
|
+
}
|
|
3784
|
+
return current;
|
|
3785
|
+
}
|
|
3786
|
+
providerObjectValueToGoMap(parsed, propsParams) {
|
|
3787
|
+
if (parsed.kind !== "object-literal")
|
|
3788
|
+
return null;
|
|
3789
|
+
const entries = [];
|
|
3790
|
+
for (const prop of parsed.properties) {
|
|
3791
|
+
if (prop.shorthand)
|
|
3792
|
+
return null;
|
|
3793
|
+
const goVal = this.lowerProviderMapMemberValue(prop.value, propsParams);
|
|
3794
|
+
if (goVal === null)
|
|
3795
|
+
return null;
|
|
3796
|
+
entries.push(`${JSON.stringify(prop.key)}: ${goVal}`);
|
|
3797
|
+
}
|
|
3798
|
+
if (entries.length === 0)
|
|
3799
|
+
return null;
|
|
3800
|
+
return `map[string]interface{}{${entries.join(", ")}}`;
|
|
3801
|
+
}
|
|
3802
|
+
lowerProviderMapMemberValue(node, propsParams) {
|
|
3803
|
+
if (node.kind === "object-literal")
|
|
3804
|
+
return objectLiteralToGoMap(this.emitCtx, node);
|
|
3805
|
+
const literal = parsedLiteralToGo(this.emitCtx, node);
|
|
3806
|
+
if (literal !== null)
|
|
3807
|
+
return literal;
|
|
3808
|
+
if (node.kind === "logical" && node.op === "??" && node.right.kind === "object-literal" && node.right.properties.length === 0 && node.left.kind === "member" && !node.left.computed && node.left.object.kind === "identifier" && node.left.object.name === this.state.propsObjectName) {
|
|
3809
|
+
const propName = node.left.property;
|
|
3810
|
+
if (propsParams.some((param) => param.name === propName)) {
|
|
3811
|
+
const fieldRef = `in.${capitalizeFieldName(propName)}`;
|
|
3812
|
+
return `func() map[string]interface{} { ` + `if m := bf.AsMap(${fieldRef}); m != nil { return m }; ` + `return map[string]interface{}{} }()`;
|
|
3813
|
+
}
|
|
3814
|
+
}
|
|
3815
|
+
return null;
|
|
3549
3816
|
}
|
|
3550
3817
|
templatePartsToGoCode(parts, propsParams) {
|
|
3551
3818
|
const segments = [];
|
|
@@ -3611,12 +3878,14 @@ ${goFields.join(`
|
|
|
3611
3878
|
}
|
|
3612
3879
|
const memo = memos.find((m) => m.name === getterName);
|
|
3613
3880
|
if (memo) {
|
|
3614
|
-
return computeMemoInitialValueOrNull(this.emitCtx, memo, signals, propsParams);
|
|
3881
|
+
return computeMemoInitialValueOrNull(this.emitCtx, memo, signals, propsParams, undefined, new Set([memo.name]));
|
|
3615
3882
|
}
|
|
3616
3883
|
}
|
|
3617
3884
|
return null;
|
|
3618
3885
|
}
|
|
3619
3886
|
inferMemoType(memo, signals, propsParamMap) {
|
|
3887
|
+
if (isListFilterMemo(memo))
|
|
3888
|
+
return "[]any";
|
|
3620
3889
|
if (memo.bodyIsTemplateLiteral)
|
|
3621
3890
|
return "string";
|
|
3622
3891
|
if (memo.computation.includes("*") || memo.computation.includes("/") || memo.computation.includes("+") || memo.computation.includes("-")) {
|
|
@@ -4013,15 +4282,19 @@ ${goFields.join(`
|
|
|
4013
4282
|
if (objHO && (objHO.method === "find" || objHO.method === "findLast")) {
|
|
4014
4283
|
const findResult = this.renderHigherOrderExpr(objHO, emit);
|
|
4015
4284
|
if (findResult) {
|
|
4016
|
-
return `{{with ${findResult}}}{{.${
|
|
4285
|
+
return `{{with ${findResult}}}{{.${goFieldNameForKey(property)}}}{{end}}`;
|
|
4017
4286
|
}
|
|
4018
|
-
const templateBlock = this.renderFindTemplateBlock(objHO, emit,
|
|
4287
|
+
const templateBlock = this.renderFindTemplateBlock(objHO, emit, goFieldNameForKey(property));
|
|
4019
4288
|
if (templateBlock)
|
|
4020
4289
|
return templateBlock;
|
|
4021
4290
|
}
|
|
4022
4291
|
if (object.kind === "identifier" && this.state.propsObjectName && object.name === this.state.propsObjectName) {
|
|
4023
4292
|
return this.rootFieldRef(property);
|
|
4024
4293
|
}
|
|
4294
|
+
if (this.isMapRootedContextChain(object)) {
|
|
4295
|
+
const objGo = emit(object);
|
|
4296
|
+
return `bf_get ${wrapIfMultiToken(objGo)} ${JSON.stringify(property)}`;
|
|
4297
|
+
}
|
|
4025
4298
|
if (object.kind === "identifier") {
|
|
4026
4299
|
const staticValue = this.resolveStaticRecordLiteralIndex(`${object.name}.${property}`);
|
|
4027
4300
|
if (staticValue !== null)
|
|
@@ -4029,12 +4302,12 @@ ${goFields.join(`
|
|
|
4029
4302
|
}
|
|
4030
4303
|
const currentLoopParam = this.loopParamStack[this.loopParamStack.length - 1];
|
|
4031
4304
|
if (object.kind === "identifier" && currentLoopParam && object.name === currentLoopParam) {
|
|
4032
|
-
return `.${
|
|
4305
|
+
return `.${goFieldNameForKey(property)}`;
|
|
4033
4306
|
}
|
|
4034
4307
|
const obj = emit(object);
|
|
4035
4308
|
if (property === "length")
|
|
4036
4309
|
return `len ${obj}`;
|
|
4037
|
-
return `${obj}.${
|
|
4310
|
+
return `${obj}.${goFieldNameForKey(property)}`;
|
|
4038
4311
|
}
|
|
4039
4312
|
indexAccess(object, index, emit) {
|
|
4040
4313
|
return `index ${wrapIfMultiToken(emit(object))} ${wrapIfMultiToken(emit(index))}`;
|
|
@@ -4126,7 +4399,16 @@ ${goFields.join(`
|
|
|
4126
4399
|
return `bf_arr ${parts.join(" ")}`;
|
|
4127
4400
|
}
|
|
4128
4401
|
objectLiteral(_properties, raw, _emit) {
|
|
4129
|
-
|
|
4402
|
+
this.state.errors.push({
|
|
4403
|
+
code: "BF101",
|
|
4404
|
+
severity: "error",
|
|
4405
|
+
message: `Expression not supported: ${raw}`,
|
|
4406
|
+
loc: this.makeLoc(),
|
|
4407
|
+
suggestion: {
|
|
4408
|
+
message: `Go templates have no object/map literal syntax, so the \`?? {}\` fallback can't render server-side. ${GO_REMEDIATION_OPTIONS}`
|
|
4409
|
+
}
|
|
4410
|
+
});
|
|
4411
|
+
return `""`;
|
|
4130
4412
|
}
|
|
4131
4413
|
static PREDICATE_METHODS = new Set([
|
|
4132
4414
|
"filter",
|
|
@@ -4138,7 +4420,7 @@ ${goFields.join(`
|
|
|
4138
4420
|
"some"
|
|
4139
4421
|
]);
|
|
4140
4422
|
higherOrderShapeOf(node) {
|
|
4141
|
-
const cb =
|
|
4423
|
+
const cb = asCallbackMethodCall3(node);
|
|
4142
4424
|
if (!cb)
|
|
4143
4425
|
return null;
|
|
4144
4426
|
if (!GoTemplateAdapter.PREDICATE_METHODS.has(cb.method))
|
|
@@ -4213,6 +4495,12 @@ ${goFields.join(`
|
|
|
4213
4495
|
return evalForm;
|
|
4214
4496
|
return this.pushCallbackBF101(method, true);
|
|
4215
4497
|
}
|
|
4498
|
+
if (method === "map") {
|
|
4499
|
+
const evalForm = emitMapEval(recv, body, params[0] ?? "_", emit);
|
|
4500
|
+
if (evalForm !== null)
|
|
4501
|
+
return evalForm;
|
|
4502
|
+
return this.pushCallbackBF101(method, true);
|
|
4503
|
+
}
|
|
4216
4504
|
return this.pushCallbackBF101(method, true);
|
|
4217
4505
|
}
|
|
4218
4506
|
arrayMethod(method, object, args, emit) {
|
|
@@ -4333,6 +4621,9 @@ ${goFields.join(`
|
|
|
4333
4621
|
}
|
|
4334
4622
|
}
|
|
4335
4623
|
flatMethod(object, depth, emit) {
|
|
4624
|
+
if (typeof depth === "object") {
|
|
4625
|
+
return `bf_flat_dynamic ${wrapIfMultiToken(emit(object))} ${wrapIfMultiToken(emit(depth.expr))}`;
|
|
4626
|
+
}
|
|
4336
4627
|
const d = depth === "infinity" ? -1 : depth;
|
|
4337
4628
|
return `bf_flat ${wrapIfMultiToken(emit(object))} ${d}`;
|
|
4338
4629
|
}
|
|
@@ -4566,6 +4857,9 @@ ${goFields.join(`
|
|
|
4566
4857
|
if (expr.callee.kind === "identifier" && expr.args.length === 0) {
|
|
4567
4858
|
return `$.${capitalizeFieldName(expr.callee.name)}`;
|
|
4568
4859
|
}
|
|
4860
|
+
if (asCallbackMethodCall3(expr) !== null) {
|
|
4861
|
+
return this.refuseFilterExprNode(expr);
|
|
4862
|
+
}
|
|
4569
4863
|
const result = this.renderFilterExpr(expr.callee, param, localVarMap);
|
|
4570
4864
|
if (this.filterExprUnsupported)
|
|
4571
4865
|
return "false";
|
|
@@ -4630,21 +4924,23 @@ ${goFields.join(`
|
|
|
4630
4924
|
}
|
|
4631
4925
|
return `or (${left}) (${right})`;
|
|
4632
4926
|
}
|
|
4633
|
-
default:
|
|
4634
|
-
this.
|
|
4635
|
-
this.state.errors.push({
|
|
4636
|
-
code: "BF101",
|
|
4637
|
-
severity: "error",
|
|
4638
|
-
message: `Filter predicate contains an expression that cannot be lowered to a Go template action: ${exprToString(expr)}`,
|
|
4639
|
-
loc: this.makeLoc(),
|
|
4640
|
-
suggestion: {
|
|
4641
|
-
message: "Options:\n1. Use /* @client */ for client-side evaluation\n2. Rewrite the predicate to avoid nested higher-order methods (`.filter()` / `.map()` / etc. inside the predicate body)"
|
|
4642
|
-
}
|
|
4643
|
-
});
|
|
4644
|
-
return "false";
|
|
4645
|
-
}
|
|
4927
|
+
default:
|
|
4928
|
+
return this.refuseFilterExprNode(expr);
|
|
4646
4929
|
}
|
|
4647
4930
|
}
|
|
4931
|
+
refuseFilterExprNode(expr) {
|
|
4932
|
+
this.filterExprUnsupported = true;
|
|
4933
|
+
this.state.errors.push({
|
|
4934
|
+
code: "BF101",
|
|
4935
|
+
severity: "error",
|
|
4936
|
+
message: `Filter predicate contains an expression that cannot be lowered to a Go template action: ${exprToString(expr)}`,
|
|
4937
|
+
loc: this.makeLoc(),
|
|
4938
|
+
suggestion: {
|
|
4939
|
+
message: "Options:\n1. Use /* @client */ for client-side evaluation\n2. Rewrite the predicate to avoid nested higher-order methods (`.filter()` / `.map()` / etc. inside the predicate body)"
|
|
4940
|
+
}
|
|
4941
|
+
});
|
|
4942
|
+
return "false";
|
|
4943
|
+
}
|
|
4648
4944
|
isGoFunctionCall(expr) {
|
|
4649
4945
|
switch (expr.kind) {
|
|
4650
4946
|
case "binary":
|
|
@@ -4898,7 +5194,7 @@ ${goFields.join(`
|
|
|
4898
5194
|
});
|
|
4899
5195
|
return plain("false");
|
|
4900
5196
|
}
|
|
4901
|
-
if (
|
|
5197
|
+
if (asCallbackMethodCall3(expr)) {
|
|
4902
5198
|
const rendered = this.renderParsedExpr(expr);
|
|
4903
5199
|
const split = this.splitPreamble(rendered);
|
|
4904
5200
|
if (split)
|
|
@@ -5026,23 +5322,44 @@ ${goFields.join(`
|
|
|
5026
5322
|
return plain(expr.raw);
|
|
5027
5323
|
}
|
|
5028
5324
|
}
|
|
5325
|
+
buildSegmentAccessor(base, segments) {
|
|
5326
|
+
let acc = base;
|
|
5327
|
+
for (const seg of segments) {
|
|
5328
|
+
acc = seg.kind === "field" ? `${acc}.${goFieldNameForKey(seg.key)}` : `(index ${acc} ${seg.index})`;
|
|
5329
|
+
}
|
|
5330
|
+
return acc;
|
|
5331
|
+
}
|
|
5029
5332
|
buildDestructureBindingMap(loop, rangeVar) {
|
|
5030
|
-
const
|
|
5333
|
+
const bindings = new Map;
|
|
5334
|
+
const restExcludes = new Map;
|
|
5335
|
+
const base = `$${rangeVar}`;
|
|
5031
5336
|
for (const b of loop.paramBindings ?? []) {
|
|
5032
|
-
|
|
5033
|
-
|
|
5337
|
+
const parent = this.buildSegmentAccessor(base, b.segments ?? []);
|
|
5338
|
+
if (!b.rest) {
|
|
5339
|
+
bindings.set(b.name, parent);
|
|
5340
|
+
} else if (b.rest.kind === "array") {
|
|
5341
|
+
bindings.set(b.name, `(bf_slice ${parent} ${b.rest.from})`);
|
|
5034
5342
|
} else {
|
|
5035
|
-
|
|
5343
|
+
bindings.set(b.name, parent);
|
|
5344
|
+
restExcludes.set(b.name, { parent, excludeKeys: b.rest.exclude.map((k) => k.key) });
|
|
5036
5345
|
}
|
|
5037
5346
|
}
|
|
5038
|
-
return
|
|
5347
|
+
return { bindings, restExcludes };
|
|
5348
|
+
}
|
|
5349
|
+
lookupRestExclude(name) {
|
|
5350
|
+
for (let i = this.loopRestExcludeStack.length - 1;i >= 0; i--) {
|
|
5351
|
+
const info = this.loopRestExcludeStack[i].get(name);
|
|
5352
|
+
if (info)
|
|
5353
|
+
return info;
|
|
5354
|
+
}
|
|
5355
|
+
return;
|
|
5039
5356
|
}
|
|
5040
5357
|
renderLoop(loop) {
|
|
5041
5358
|
if (loop.clientOnly) {
|
|
5042
5359
|
return `{{bfComment "loop:${loop.markerId}"}}{{bfComment "/loop:${loop.markerId}"}}`;
|
|
5043
5360
|
}
|
|
5044
5361
|
const destructure = !!(loop.paramBindings && loop.paramBindings.length > 0);
|
|
5045
|
-
const supportableDestructure = destructure &&
|
|
5362
|
+
const supportableDestructure = destructure && isLowerableLoopDestructure(loop);
|
|
5046
5363
|
if (destructure && !supportableDestructure) {
|
|
5047
5364
|
this.state.errors.push({
|
|
5048
5365
|
code: "BF104",
|
|
@@ -5057,6 +5374,21 @@ ${goFields.join(`
|
|
|
5057
5374
|
}
|
|
5058
5375
|
});
|
|
5059
5376
|
}
|
|
5377
|
+
const arrayName = loop.array.trim();
|
|
5378
|
+
if (/^[A-Za-z_$][\w$]*$/.test(arrayName)) {
|
|
5379
|
+
const arrayConst = this.state.localConstants.find((c) => c.name === arrayName);
|
|
5380
|
+
if (arrayConst && !arrayConst.isModule && arrayConst.parsed && !this.isStringExpr(arrayConst.parsed, new Set)) {
|
|
5381
|
+
this.state.errors.push({
|
|
5382
|
+
code: "BF101",
|
|
5383
|
+
severity: "error",
|
|
5384
|
+
message: `Loop array \`${arrayName}\` is a local computed value (\`${arrayConst.value}\`) that the Go template adapter cannot bind as a template variable — only a string-derived local resolves to a generated struct field.`,
|
|
5385
|
+
loc: loop.loc ?? this.makeLoc(),
|
|
5386
|
+
suggestion: {
|
|
5387
|
+
message: "Pre-compute the array server-side and pass it as a prop, or mark the loop position as @client-only so it runs in JS on the client."
|
|
5388
|
+
}
|
|
5389
|
+
});
|
|
5390
|
+
}
|
|
5391
|
+
}
|
|
5060
5392
|
let goArray = this.convertExpressionToGo(loop.array);
|
|
5061
5393
|
const param = loop.param;
|
|
5062
5394
|
let index = loop.index || "_";
|
|
@@ -5066,15 +5398,16 @@ ${goFields.join(`
|
|
|
5066
5398
|
rangeIndex = param;
|
|
5067
5399
|
rangeValue = "_";
|
|
5068
5400
|
}
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
goArray = `.${childComponent.name}s`;
|
|
5401
|
+
if (loop.childComponent) {
|
|
5402
|
+
goArray = `.${loop.childComponent.name}s`;
|
|
5072
5403
|
}
|
|
5073
5404
|
this.inLoop = true;
|
|
5074
5405
|
const addedLoopVars = [];
|
|
5075
5406
|
let pushedBindingMap = false;
|
|
5076
5407
|
if (supportableDestructure) {
|
|
5077
|
-
this.
|
|
5408
|
+
const built = this.buildDestructureBindingMap(loop, rangeValue);
|
|
5409
|
+
this.loopBindingStack.push(built.bindings);
|
|
5410
|
+
this.loopRestExcludeStack.push(built.restExcludes);
|
|
5078
5411
|
pushedBindingMap = true;
|
|
5079
5412
|
this.loopParamStack.push("");
|
|
5080
5413
|
if (rangeIndex !== "_") {
|
|
@@ -5093,7 +5426,9 @@ ${goFields.join(`
|
|
|
5093
5426
|
}
|
|
5094
5427
|
}
|
|
5095
5428
|
this.loopScalarItemStack.push(this.scalarLiteralLoopGoType(loop.arrayParsed, loop.itemType) !== null);
|
|
5429
|
+
this.loopWrapperStack.push(!!loop.childComponent);
|
|
5096
5430
|
const children = this.renderChildren(loop.children);
|
|
5431
|
+
this.loopWrapperStack.pop();
|
|
5097
5432
|
this.loopScalarItemStack.pop();
|
|
5098
5433
|
const itemMarker = this.loopItemMarker(loop);
|
|
5099
5434
|
for (const v of addedLoopVars) {
|
|
@@ -5104,8 +5439,10 @@ ${goFields.join(`
|
|
|
5104
5439
|
this.loopVarRefCount.set(v, rc);
|
|
5105
5440
|
}
|
|
5106
5441
|
this.loopParamStack.pop();
|
|
5107
|
-
if (pushedBindingMap)
|
|
5442
|
+
if (pushedBindingMap) {
|
|
5108
5443
|
this.loopBindingStack.pop();
|
|
5444
|
+
this.loopRestExcludeStack.pop();
|
|
5445
|
+
}
|
|
5109
5446
|
this.inLoop = false;
|
|
5110
5447
|
if (loop.sortComparator) {
|
|
5111
5448
|
const sortEmit = (e) => this.renderParsedExpr(e);
|
|
@@ -5134,24 +5471,6 @@ ${goFields.join(`
|
|
|
5134
5471
|
}
|
|
5135
5472
|
return "";
|
|
5136
5473
|
}
|
|
5137
|
-
findChildComponent(nodes) {
|
|
5138
|
-
for (const node of nodes) {
|
|
5139
|
-
if (node.type === "component") {
|
|
5140
|
-
return node;
|
|
5141
|
-
}
|
|
5142
|
-
if (node.type === "element" && node.children) {
|
|
5143
|
-
const found = this.findChildComponent(node.children);
|
|
5144
|
-
if (found)
|
|
5145
|
-
return found;
|
|
5146
|
-
}
|
|
5147
|
-
if (node.type === "fragment" && node.children) {
|
|
5148
|
-
const found = this.findChildComponent(node.children);
|
|
5149
|
-
if (found)
|
|
5150
|
-
return found;
|
|
5151
|
-
}
|
|
5152
|
-
}
|
|
5153
|
-
return null;
|
|
5154
|
-
}
|
|
5155
5474
|
queueDynamicChildrenDefine(comp) {
|
|
5156
5475
|
const effectiveChildren = comp.children.length > 0 ? comp.children : this.jsxChildrenPropNodes(comp.props);
|
|
5157
5476
|
if (effectiveChildren.length === 0)
|
|
@@ -5199,7 +5518,7 @@ ${goFields.join(`
|
|
|
5199
5518
|
return this.renderChildren(comp.children);
|
|
5200
5519
|
}
|
|
5201
5520
|
let templateCall;
|
|
5202
|
-
if (this.inLoop) {
|
|
5521
|
+
if (this.inLoop && (this.loopWrapperStack[this.loopWrapperStack.length - 1] ?? false)) {
|
|
5203
5522
|
const loopBodyDefine = this.queueLoopBodyChildrenDefine(comp);
|
|
5204
5523
|
if (loopBodyDefine) {
|
|
5205
5524
|
const bodyData = this.loopScalarItemStack[this.loopScalarItemStack.length - 1] ? ".BfLoopItem" : ".";
|
|
@@ -5207,6 +5526,12 @@ ${goFields.join(`
|
|
|
5207
5526
|
} else {
|
|
5208
5527
|
templateCall = `{{template "${comp.name}" .}}`;
|
|
5209
5528
|
}
|
|
5529
|
+
} else if (this.inLoop && comp.slotId) {
|
|
5530
|
+
const suffix = slotIdToFieldSuffix(comp.slotId);
|
|
5531
|
+
const loopBodyDefine = this.queueLoopBodyChildrenDefine(comp);
|
|
5532
|
+
templateCall = loopBodyDefine ? `{{template "${comp.name}" (bf_with_children $.${comp.name}${suffix} (bf_tmpl "${loopBodyDefine}" .))}}` : `{{template "${comp.name}" $.${comp.name}${suffix}}}`;
|
|
5533
|
+
} else if (this.inLoop) {
|
|
5534
|
+
templateCall = `{{template "${comp.name}" .}}`;
|
|
5210
5535
|
} else if (comp.slotId) {
|
|
5211
5536
|
const suffix = slotIdToFieldSuffix(comp.slotId);
|
|
5212
5537
|
const childrenDefine = this.queueDynamicChildrenDefine(comp);
|
|
@@ -5302,6 +5627,12 @@ ${children}`;
|
|
|
5302
5627
|
if (currentLoopParam && trimmed === currentLoopParam) {
|
|
5303
5628
|
return `{{bf_spread_attrs .}}`;
|
|
5304
5629
|
}
|
|
5630
|
+
const restInfo = this.lookupRestExclude(trimmed);
|
|
5631
|
+
if (restInfo) {
|
|
5632
|
+
const excludeArgs = restInfo.excludeKeys.map((k) => JSON.stringify(k)).join(" ");
|
|
5633
|
+
const omitArgs = excludeArgs ? `${restInfo.parent} ${excludeArgs}` : restInfo.parent;
|
|
5634
|
+
return `{{bf_spread_attrs (bf_omit ${omitArgs})}}`;
|
|
5635
|
+
}
|
|
5305
5636
|
const goExpr = this.convertExpressionToGo(value.expr);
|
|
5306
5637
|
return `{{bf_spread_attrs ${goExpr}}}`;
|
|
5307
5638
|
}
|