@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/index.js
CHANGED
|
@@ -31,17 +31,18 @@ import {
|
|
|
31
31
|
isSupported,
|
|
32
32
|
exprToString,
|
|
33
33
|
identifierPath,
|
|
34
|
-
asCallbackMethodCall,
|
|
34
|
+
asCallbackMethodCall as asCallbackMethodCall3,
|
|
35
35
|
sortComparatorFromArrow,
|
|
36
36
|
emitParsedExpr,
|
|
37
37
|
emitIRNode,
|
|
38
38
|
emitAttrValue,
|
|
39
39
|
augmentInheritedPropAccesses,
|
|
40
40
|
collectContextConsumers,
|
|
41
|
-
|
|
41
|
+
isLowerableLoopDestructure,
|
|
42
42
|
collectModuleStringConsts as collectModuleStringConstsShared,
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
prepareLoweringMatchers,
|
|
44
|
+
envSignalReaderFor,
|
|
45
|
+
computeSsrSeedPlan
|
|
45
46
|
} from "@barefootjs/jsx";
|
|
46
47
|
import { findInterpolationEnd } from "@barefootjs/jsx/scanner";
|
|
47
48
|
import { BF_REGION } from "@barefootjs/shared";
|
|
@@ -122,6 +123,13 @@ function capitalizeFieldName(name) {
|
|
|
122
123
|
}
|
|
123
124
|
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
124
125
|
}
|
|
126
|
+
function goFieldNameForKey(key) {
|
|
127
|
+
const parts = key.split(/[^A-Za-z0-9_]+/).filter(Boolean);
|
|
128
|
+
if (parts.length === 0)
|
|
129
|
+
return "Field";
|
|
130
|
+
const name = parts.map(capitalizeFieldName).join("");
|
|
131
|
+
return /^[0-9]/.test(name) ? `Field${name}` : name;
|
|
132
|
+
}
|
|
125
133
|
function slotIdToFieldSuffix(slotId) {
|
|
126
134
|
const cleanId = slotId.startsWith("^") ? slotId.slice(1) : slotId;
|
|
127
135
|
const match = cleanId.match(/^s(\d+)$/);
|
|
@@ -224,6 +232,13 @@ function emitFlatMapEval(recv, body, param, emit) {
|
|
|
224
232
|
const env = emitEvalEnvArg(body, [param], emit);
|
|
225
233
|
return `bf_flat_map_eval ${wrapIfMultiToken(recv)} "${escapeGoString(json)}" "${param}" ${env}`;
|
|
226
234
|
}
|
|
235
|
+
function emitMapEval(recv, body, param, emit) {
|
|
236
|
+
const json = serializeParsedExpr(body);
|
|
237
|
+
if (json === null)
|
|
238
|
+
return null;
|
|
239
|
+
const env = emitEvalEnvArg(body, [param], emit);
|
|
240
|
+
return `bf_map_eval ${wrapIfMultiToken(recv)} "${escapeGoString(json)}" "${param}" ${env}`;
|
|
241
|
+
}
|
|
227
242
|
function stringTolerantEqOperands(l, r) {
|
|
228
243
|
const isStrLit = (x) => /^"(?:[^"\\]|\\.)*"$/.test(x);
|
|
229
244
|
if (isStrLit(l) === isStrLit(r))
|
|
@@ -337,6 +352,9 @@ class CompileState {
|
|
|
337
352
|
currentTypeDefinitions = [];
|
|
338
353
|
contextConsumers = [];
|
|
339
354
|
searchParamsLocals = new Set;
|
|
355
|
+
envSignalReadersByLocal = new Map;
|
|
356
|
+
ssrSeedPlan = { baseScope: [], steps: [] };
|
|
357
|
+
hoistedMemoLocals = new Map;
|
|
340
358
|
loweringMatchers = [];
|
|
341
359
|
nillablePropNames = new Set;
|
|
342
360
|
rootScopeNodes = new Set;
|
|
@@ -684,9 +702,12 @@ function forEachValueChild(n, visit) {
|
|
|
684
702
|
// src/adapter/expr/url-builder.ts
|
|
685
703
|
import {
|
|
686
704
|
parseExpression,
|
|
687
|
-
stringifyParsedExpr
|
|
705
|
+
stringifyParsedExpr,
|
|
706
|
+
isValidHelperId
|
|
688
707
|
} from "@barefootjs/jsx";
|
|
689
|
-
|
|
708
|
+
function goHelperName(helper) {
|
|
709
|
+
return isValidHelperId(helper) ? `bf_${helper}` : null;
|
|
710
|
+
}
|
|
690
711
|
var BOOL_COMPARISON_OPS = new Set([
|
|
691
712
|
"==",
|
|
692
713
|
"===",
|
|
@@ -729,7 +750,7 @@ function lowerRegisteredCall(ctx, jsExpr, preParsed) {
|
|
|
729
750
|
return null;
|
|
730
751
|
}
|
|
731
752
|
function renderLoweringNode(ctx, node) {
|
|
732
|
-
const helper =
|
|
753
|
+
const helper = goHelperName(node.helper);
|
|
733
754
|
if (!helper)
|
|
734
755
|
return null;
|
|
735
756
|
const lowerExpr = (n) => ctx.convertExpressionToGo(stringifyParsedExpr(n), undefined, n);
|
|
@@ -769,7 +790,7 @@ function typeInfoToGo(ctx, typeInfo, defaultValue) {
|
|
|
769
790
|
case "object":
|
|
770
791
|
return "map[string]interface{}";
|
|
771
792
|
case "interface":
|
|
772
|
-
if (typeInfo.raw && ctx.state.
|
|
793
|
+
if (typeInfo.raw && (ctx.state.localStructFields.has(typeInfo.raw) || ctx.state.localTypeAliases.has(typeInfo.raw))) {
|
|
773
794
|
return typeInfo.raw;
|
|
774
795
|
}
|
|
775
796
|
if (typeInfo.raw) {
|
|
@@ -802,7 +823,7 @@ function tsTypeStringToGo(ctx, tsType) {
|
|
|
802
823
|
const arrayMatch = t.match(/^Array<(.+)>$/);
|
|
803
824
|
if (arrayMatch)
|
|
804
825
|
return `[]${tsTypeStringToGo(ctx, arrayMatch[1])}`;
|
|
805
|
-
if (ctx.state.
|
|
826
|
+
if (ctx.state.localStructFields.has(t) || ctx.state.localTypeAliases.has(t))
|
|
806
827
|
return t;
|
|
807
828
|
return "interface{}";
|
|
808
829
|
}
|
|
@@ -824,6 +845,24 @@ function inferTypeFromValue(value) {
|
|
|
824
845
|
}
|
|
825
846
|
|
|
826
847
|
// src/adapter/value/parsed-literal-to-go.ts
|
|
848
|
+
function structPropertyType(ctx, structGoType, key) {
|
|
849
|
+
const td = ctx.state.currentTypeDefinitions.find((t) => t.name === structGoType);
|
|
850
|
+
return td?.properties?.find((p) => p.name === key)?.type;
|
|
851
|
+
}
|
|
852
|
+
function bakeInlineObjectAsGoMap(ctx, expr) {
|
|
853
|
+
if (expr.kind !== "object-literal")
|
|
854
|
+
return null;
|
|
855
|
+
const entries = [];
|
|
856
|
+
for (const prop of expr.properties) {
|
|
857
|
+
if (prop.shorthand)
|
|
858
|
+
return null;
|
|
859
|
+
const go = prop.value.kind === "object-literal" ? bakeInlineObjectAsGoMap(ctx, prop.value) : parsedLiteralToGo(ctx, prop.value);
|
|
860
|
+
if (go === null)
|
|
861
|
+
return null;
|
|
862
|
+
entries.push(`${JSON.stringify(goFieldNameForKey(prop.key))}: ${go}`);
|
|
863
|
+
}
|
|
864
|
+
return `map[string]interface{}{${entries.join(", ")}}`;
|
|
865
|
+
}
|
|
827
866
|
function parsedLiteralToGo(ctx, expr, typeInfo) {
|
|
828
867
|
if (expr.kind === "unary" && expr.op === "-" && expr.argument.kind === "literal" && expr.argument.literalType === "number") {
|
|
829
868
|
return expr.argument.raw !== undefined ? `-${expr.argument.raw}` : null;
|
|
@@ -864,9 +903,16 @@ function parsedLiteralToGo(ctx, expr, typeInfo) {
|
|
|
864
903
|
const goField = structFields.get(prop.key);
|
|
865
904
|
if (!goField)
|
|
866
905
|
return null;
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
906
|
+
const propType = structPropertyType(ctx, goType, prop.key);
|
|
907
|
+
let go;
|
|
908
|
+
if (prop.value.kind === "array-literal") {
|
|
909
|
+
go = parsedLiteralToGo(ctx, prop.value, propType);
|
|
910
|
+
} else if (prop.value.kind === "object-literal") {
|
|
911
|
+
const nestedGoType = propType ? typeInfoToGo(ctx, propType) : undefined;
|
|
912
|
+
go = nestedGoType && ctx.state.localStructFields.has(nestedGoType) ? parsedLiteralToGo(ctx, prop.value, propType) : bakeInlineObjectAsGoMap(ctx, prop.value);
|
|
913
|
+
} else {
|
|
914
|
+
go = parsedLiteralToGo(ctx, prop.value);
|
|
915
|
+
}
|
|
870
916
|
if (go === null)
|
|
871
917
|
return null;
|
|
872
918
|
entries.push(`${goField}: ${go}`);
|
|
@@ -977,8 +1023,17 @@ function getSignalInitialValueAsGo(ctx, initialValue, propsParams, propFallbackV
|
|
|
977
1023
|
}
|
|
978
1024
|
|
|
979
1025
|
// src/adapter/memo/memo-type.ts
|
|
1026
|
+
import { asCallbackMethodCall } from "@barefootjs/jsx";
|
|
1027
|
+
function isListFilterMemo(memo) {
|
|
1028
|
+
if (!memo.parsed)
|
|
1029
|
+
return false;
|
|
1030
|
+
const cb = asCallbackMethodCall(memo.parsed);
|
|
1031
|
+
return cb !== null && cb.method === "filter";
|
|
1032
|
+
}
|
|
980
1033
|
function isBooleanMemo(ctx, memo, signals, propsParamMap) {
|
|
981
1034
|
const c = memo.computation;
|
|
1035
|
+
if (isListFilterMemo(memo))
|
|
1036
|
+
return false;
|
|
982
1037
|
if (isStringTernaryMemo(ctx, memo.parsed))
|
|
983
1038
|
return false;
|
|
984
1039
|
if (/(!==|===|!=(?!=)|==(?!=))/.test(c))
|
|
@@ -1269,6 +1324,14 @@ function computeObjectMemoInitialValue(ctx, memo) {
|
|
|
1269
1324
|
}`;
|
|
1270
1325
|
}
|
|
1271
1326
|
|
|
1327
|
+
// src/adapter/memo/memo-compute.ts
|
|
1328
|
+
import {
|
|
1329
|
+
asCallbackMethodCall as asCallbackMethodCall2,
|
|
1330
|
+
freeVarsInBody as freeVarsInBody2,
|
|
1331
|
+
materializeGetterCalls,
|
|
1332
|
+
serializeParsedExpr as serializeParsedExpr2
|
|
1333
|
+
} from "@barefootjs/jsx";
|
|
1334
|
+
|
|
1272
1335
|
// src/adapter/memo/template-interp.ts
|
|
1273
1336
|
import ts from "typescript";
|
|
1274
1337
|
function computeTemplateLiteralMemoInitialValue(ctx, memo, propsParams) {
|
|
@@ -1409,8 +1472,49 @@ function propsAccessNameFromParsed(ctx, node) {
|
|
|
1409
1472
|
|
|
1410
1473
|
// src/adapter/memo/memo-compute.ts
|
|
1411
1474
|
var EMPTY_PROP_FALLBACK_VARS2 = new Map;
|
|
1475
|
+
function getterCallName(e) {
|
|
1476
|
+
return e.kind === "call" && e.callee.kind === "identifier" && e.args.length === 0 ? e.callee.name : null;
|
|
1477
|
+
}
|
|
1478
|
+
function propsMemberName(e) {
|
|
1479
|
+
return e.kind === "member" && !e.computed && e.object.kind === "identifier" && e.object.name === "props" ? e.property : null;
|
|
1480
|
+
}
|
|
1481
|
+
function matchFilterArmMemo(ctx, body, signals, propsParams) {
|
|
1482
|
+
const cb = asCallbackMethodCall2(body);
|
|
1483
|
+
if (!cb || cb.method !== "filter")
|
|
1484
|
+
return null;
|
|
1485
|
+
const propName = propsMemberName(cb.object);
|
|
1486
|
+
const param = propName ? propsParams.find((p) => p.name === propName) : undefined;
|
|
1487
|
+
if (!propName || !param)
|
|
1488
|
+
return null;
|
|
1489
|
+
const knownGetterNames = new Set(ctx.state.ssrSeedPlan.steps.filter((s) => s.kind !== "env-reader").map((s) => s.name));
|
|
1490
|
+
const materialized = materializeGetterCalls(cb.arrow.body, knownGetterNames);
|
|
1491
|
+
const predJSON = serializeParsedExpr2(materialized);
|
|
1492
|
+
if (predJSON === null)
|
|
1493
|
+
return null;
|
|
1494
|
+
const paramName = cb.arrow.params[0] ?? "_";
|
|
1495
|
+
const freeVars = freeVarsInBody2(materialized, new Set(cb.arrow.params));
|
|
1496
|
+
return { propName, predJSON, paramName, freeVars };
|
|
1497
|
+
}
|
|
1498
|
+
function filterArmEarlierSiblingRefs(ctx, memo, signals, propsParams) {
|
|
1499
|
+
if (!memo.parsed)
|
|
1500
|
+
return [];
|
|
1501
|
+
const match = matchFilterArmMemo(ctx, memo.parsed, signals, propsParams);
|
|
1502
|
+
if (!match)
|
|
1503
|
+
return [];
|
|
1504
|
+
const memos = ctx.state.currentMemos ?? [];
|
|
1505
|
+
const currentIndex = memos.findIndex((m) => m.name === memo.name);
|
|
1506
|
+
if (currentIndex < 0)
|
|
1507
|
+
return [];
|
|
1508
|
+
const refs = [];
|
|
1509
|
+
for (const name of match.freeVars) {
|
|
1510
|
+
const idx = memos.findIndex((m) => m.name === name);
|
|
1511
|
+
if (idx >= 0 && idx < currentIndex)
|
|
1512
|
+
refs.push(name);
|
|
1513
|
+
}
|
|
1514
|
+
return refs;
|
|
1515
|
+
}
|
|
1412
1516
|
function computeMemoInitialValue(ctx, memo, signals, propsParams, propFallbackVars = EMPTY_PROP_FALLBACK_VARS2, goType) {
|
|
1413
|
-
const resolved = computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFallbackVars);
|
|
1517
|
+
const resolved = computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFallbackVars, new Set([memo.name]));
|
|
1414
1518
|
if (resolved !== null)
|
|
1415
1519
|
return resolved;
|
|
1416
1520
|
if (goType === "bool")
|
|
@@ -1422,15 +1526,79 @@ function computeMemoInitialValue(ctx, memo, signals, propsParams, propFallbackVa
|
|
|
1422
1526
|
}
|
|
1423
1527
|
return "0";
|
|
1424
1528
|
}
|
|
1425
|
-
function memoInitialFromParsedBody(ctx, body, signals, propsParams, propFallbackVars) {
|
|
1529
|
+
function memoInitialFromParsedBody(ctx, body, signals, propsParams, propFallbackVars, currentMemoName, resolving = new Set) {
|
|
1426
1530
|
const propRef = (propName) => {
|
|
1427
1531
|
const hoisted = propFallbackVars.get(propName);
|
|
1428
1532
|
if (hoisted)
|
|
1429
1533
|
return hoisted.varName;
|
|
1430
1534
|
return `in.${capitalizeFieldName(propName)}`;
|
|
1431
1535
|
};
|
|
1432
|
-
const
|
|
1433
|
-
|
|
1536
|
+
const envGetKey = (e) => {
|
|
1537
|
+
if (e.kind !== "call" || e.callee.kind !== "member" || e.callee.computed)
|
|
1538
|
+
return null;
|
|
1539
|
+
const recvName = getterCallName(e.callee.object);
|
|
1540
|
+
if (recvName === null)
|
|
1541
|
+
return null;
|
|
1542
|
+
const reader = ctx.state.envSignalReadersByLocal.get(recvName);
|
|
1543
|
+
if (!reader || !reader.methods.has(e.callee.property))
|
|
1544
|
+
return null;
|
|
1545
|
+
const arg = e.args[0];
|
|
1546
|
+
if (!arg || arg.kind !== "literal" || arg.literalType !== "string")
|
|
1547
|
+
return null;
|
|
1548
|
+
return { key: String(arg.value), fieldName: capitalizeFieldName(reader.canonicalName) };
|
|
1549
|
+
};
|
|
1550
|
+
{
|
|
1551
|
+
const m = envGetKey(body);
|
|
1552
|
+
if (m !== null)
|
|
1553
|
+
return `in.${m.fieldName}.Get(${JSON.stringify(m.key)})`;
|
|
1554
|
+
}
|
|
1555
|
+
if (body.kind === "logical" && (body.op === "??" || body.op === "||") && body.right.kind === "literal" && body.right.literalType === "string") {
|
|
1556
|
+
const m = envGetKey(body.left);
|
|
1557
|
+
if (m !== null) {
|
|
1558
|
+
const def = JSON.stringify(String(body.right.value));
|
|
1559
|
+
return `func() string { if v := in.${m.fieldName}.Get(${JSON.stringify(m.key)}); v != "" { return v }; return ${def} }()`;
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
{
|
|
1563
|
+
const match = matchFilterArmMemo(ctx, body, signals, propsParams);
|
|
1564
|
+
if (match) {
|
|
1565
|
+
const { propName, predJSON, paramName, freeVars } = match;
|
|
1566
|
+
const currentIndex = (ctx.state.currentMemos ?? []).findIndex((m) => m.name === currentMemoName);
|
|
1567
|
+
const envEntries = [];
|
|
1568
|
+
let unresolved = false;
|
|
1569
|
+
for (const name of freeVars) {
|
|
1570
|
+
let goExpr = null;
|
|
1571
|
+
const siblingIndex = (ctx.state.currentMemos ?? []).findIndex((m) => m.name === name);
|
|
1572
|
+
if (siblingIndex >= 0) {
|
|
1573
|
+
const siblingMemo = ctx.state.currentMemos[siblingIndex];
|
|
1574
|
+
const eligible = currentIndex >= 0 && siblingIndex < currentIndex && !resolving.has(siblingMemo.name);
|
|
1575
|
+
if (eligible) {
|
|
1576
|
+
const hoisted = ctx.state.hoistedMemoLocals.get(siblingMemo.name);
|
|
1577
|
+
goExpr = hoisted ?? computeMemoInitialValueOrNull(ctx, siblingMemo, signals, propsParams, propFallbackVars, new Set([...resolving, siblingMemo.name]));
|
|
1578
|
+
}
|
|
1579
|
+
} else {
|
|
1580
|
+
const sig = signals.find((s) => s.getter === name);
|
|
1581
|
+
if (sig) {
|
|
1582
|
+
goExpr = getSignalInitialValueAsGo(ctx, sig.initialValue, propsParams, propFallbackVars);
|
|
1583
|
+
} else {
|
|
1584
|
+
const p = propsParams.find((pp) => pp.name === name);
|
|
1585
|
+
if (p)
|
|
1586
|
+
goExpr = propRef(name);
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
if (goExpr === null) {
|
|
1590
|
+
unresolved = true;
|
|
1591
|
+
break;
|
|
1592
|
+
}
|
|
1593
|
+
envEntries.push(`${JSON.stringify(name)}: ${goExpr}`);
|
|
1594
|
+
}
|
|
1595
|
+
if (!unresolved) {
|
|
1596
|
+
const itemsField = `in.${capitalizeFieldName(propName)}`;
|
|
1597
|
+
const envMap = `map[string]any{${envEntries.join(", ")}}`;
|
|
1598
|
+
return `bf.FilterEval(${itemsField}, "${escapeGoString(predJSON)}", ${JSON.stringify(paramName)}, ${envMap})`;
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1434
1602
|
if (body.kind === "binary" && ["===", "!==", "==", "!="].includes(body.op) && body.right.kind === "literal" && body.right.literalType === "string") {
|
|
1435
1603
|
const depName = getterCallName(body.left);
|
|
1436
1604
|
if (depName) {
|
|
@@ -1469,8 +1637,8 @@ function memoInitialFromParsedBody(ctx, body, signals, propsParams, propFallback
|
|
|
1469
1637
|
condGo = getSignalInitialValueAsGo(ctx, condSignal.initialValue, propsParams, propFallbackVars);
|
|
1470
1638
|
} else {
|
|
1471
1639
|
const condMemo = (ctx.state.currentMemos ?? []).find((m) => m.name === condName);
|
|
1472
|
-
if (condMemo) {
|
|
1473
|
-
condGo = computeMemoInitialValueOrNull(ctx, condMemo, signals, propsParams, propFallbackVars);
|
|
1640
|
+
if (condMemo && !resolving.has(condMemo.name)) {
|
|
1641
|
+
condGo = computeMemoInitialValueOrNull(ctx, condMemo, signals, propsParams, propFallbackVars, new Set([...resolving, condMemo.name]));
|
|
1474
1642
|
}
|
|
1475
1643
|
}
|
|
1476
1644
|
if (condGo === "true")
|
|
@@ -1544,17 +1712,17 @@ function memoInitialFromParsedBody(ctx, body, signals, propsParams, propFallback
|
|
|
1544
1712
|
}
|
|
1545
1713
|
return null;
|
|
1546
1714
|
}
|
|
1547
|
-
function computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFallbackVars = EMPTY_PROP_FALLBACK_VARS2) {
|
|
1715
|
+
function computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFallbackVars = EMPTY_PROP_FALLBACK_VARS2, resolving = new Set) {
|
|
1548
1716
|
const computation = memo.computation;
|
|
1549
1717
|
const tmplMemo = computeTemplateLiteralMemoInitialValue(ctx, memo, propsParams);
|
|
1550
1718
|
if (tmplMemo !== null)
|
|
1551
1719
|
return tmplMemo;
|
|
1552
1720
|
if (memo.parsed) {
|
|
1553
|
-
const fromParsed = memoInitialFromParsedBody(ctx, memo.parsed, signals, propsParams, propFallbackVars);
|
|
1721
|
+
const fromParsed = memoInitialFromParsedBody(ctx, memo.parsed, signals, propsParams, propFallbackVars, memo.name, resolving);
|
|
1554
1722
|
if (fromParsed !== null)
|
|
1555
1723
|
return fromParsed;
|
|
1556
1724
|
}
|
|
1557
|
-
const cmpTernary = computeComparisonTernaryGo(ctx, memo.parsed, signals, propsParams, propFallbackVars);
|
|
1725
|
+
const cmpTernary = computeComparisonTernaryGo(ctx, memo.parsed, signals, propsParams, propFallbackVars, resolving);
|
|
1558
1726
|
if (cmpTernary !== null)
|
|
1559
1727
|
return cmpTernary;
|
|
1560
1728
|
const blockReturn = resolveBlockBodyMemoModuleConst(ctx, memo, signals);
|
|
@@ -1566,20 +1734,22 @@ function computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFall
|
|
|
1566
1734
|
return objMemo;
|
|
1567
1735
|
return null;
|
|
1568
1736
|
}
|
|
1569
|
-
function resolveGetterValueAsGo(ctx, name, signals, propsParams, propFallbackVars) {
|
|
1737
|
+
function resolveGetterValueAsGo(ctx, name, signals, propsParams, propFallbackVars, resolving = new Set) {
|
|
1570
1738
|
const signal = signals.find((s) => s.getter === name);
|
|
1571
1739
|
if (signal) {
|
|
1572
1740
|
return getSignalInitialValueAsGo(ctx, signal.initialValue, propsParams, propFallbackVars);
|
|
1573
1741
|
}
|
|
1574
1742
|
const memo = (ctx.state.currentMemos ?? []).find((m) => m.name === name);
|
|
1575
1743
|
if (memo) {
|
|
1744
|
+
if (resolving.has(memo.name))
|
|
1745
|
+
return null;
|
|
1576
1746
|
const stripped = memo.computation.replace(/^\(\)\s*=>\s*/, "");
|
|
1577
1747
|
const fb = ctx.extractPropFallback(stripped);
|
|
1578
1748
|
if (fb && capitalizeFieldName(fb.propName) === capitalizeFieldName(memo.name)) {
|
|
1579
1749
|
const field = `in.${capitalizeFieldName(fb.propName)}`;
|
|
1580
1750
|
return `func() interface{} { v := interface{}(${field}); if v == nil || v == "" { return ${fb.goFallback} }; return v }()`;
|
|
1581
1751
|
}
|
|
1582
|
-
return computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFallbackVars);
|
|
1752
|
+
return computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFallbackVars, new Set([...resolving, memo.name]));
|
|
1583
1753
|
}
|
|
1584
1754
|
const param = propsParams.find((p) => p.name === name);
|
|
1585
1755
|
if (param) {
|
|
@@ -1588,7 +1758,7 @@ function resolveGetterValueAsGo(ctx, name, signals, propsParams, propFallbackVar
|
|
|
1588
1758
|
}
|
|
1589
1759
|
return null;
|
|
1590
1760
|
}
|
|
1591
|
-
function computeComparisonTernaryGo(ctx, parsed, signals, propsParams, propFallbackVars) {
|
|
1761
|
+
function computeComparisonTernaryGo(ctx, parsed, signals, propsParams, propFallbackVars, resolving = new Set) {
|
|
1592
1762
|
if (!parsed || parsed.kind !== "conditional")
|
|
1593
1763
|
return null;
|
|
1594
1764
|
const cond = parsed.test;
|
|
@@ -1613,16 +1783,16 @@ function computeComparisonTernaryGo(ctx, parsed, signals, propsParams, propFallb
|
|
|
1613
1783
|
const f = branch(parsed.alternate);
|
|
1614
1784
|
if (t === null || f === null)
|
|
1615
1785
|
return null;
|
|
1616
|
-
const condGo = resolveComparisonOperandGo(ctx, cond.left, signals, propsParams, propFallbackVars);
|
|
1786
|
+
const condGo = resolveComparisonOperandGo(ctx, cond.left, signals, propsParams, propFallbackVars, resolving);
|
|
1617
1787
|
if (condGo === null)
|
|
1618
1788
|
return null;
|
|
1619
1789
|
const eqBranch = isEq ? t : f;
|
|
1620
1790
|
const neBranch = isEq ? f : t;
|
|
1621
1791
|
return `func() string { if ${condGo} == ${JSON.stringify(cond.right.value)} { return ${eqBranch} }; return ${neBranch} }()`;
|
|
1622
1792
|
}
|
|
1623
|
-
function resolveComparisonOperandGo(ctx, node, signals, propsParams, propFallbackVars) {
|
|
1793
|
+
function resolveComparisonOperandGo(ctx, node, signals, propsParams, propFallbackVars, resolving = new Set) {
|
|
1624
1794
|
if (node.kind === "call" && node.callee.kind === "identifier" && node.args.length === 0) {
|
|
1625
|
-
return resolveGetterValueAsGo(ctx, node.callee.name, signals, propsParams, propFallbackVars);
|
|
1795
|
+
return resolveGetterValueAsGo(ctx, node.callee.name, signals, propsParams, propFallbackVars, resolving);
|
|
1626
1796
|
}
|
|
1627
1797
|
if (node.kind === "logical" && node.op === "??" && node.right.kind === "literal" && node.right.literalType === "string") {
|
|
1628
1798
|
const propName = propsAccessNameFromParsed2(ctx, node.left);
|
|
@@ -1980,8 +2150,10 @@ class GoTemplateAdapter extends BaseAdapter {
|
|
|
1980
2150
|
inLoop = false;
|
|
1981
2151
|
loopParamStack = [];
|
|
1982
2152
|
loopScalarItemStack = [];
|
|
2153
|
+
loopWrapperStack = [];
|
|
1983
2154
|
loopVarRefCount = new Map;
|
|
1984
2155
|
loopBindingStack = [];
|
|
2156
|
+
loopRestExcludeStack = [];
|
|
1985
2157
|
childComponentShapes = new Map;
|
|
1986
2158
|
childContextConsumers = new Map;
|
|
1987
2159
|
constructor(options = {}) {
|
|
@@ -2001,7 +2173,18 @@ class GoTemplateAdapter extends BaseAdapter {
|
|
|
2001
2173
|
this.state.currentMemos = ir.metadata.memos ?? [];
|
|
2002
2174
|
this.state.currentTypeDefinitions = ir.metadata.typeDefinitions ?? [];
|
|
2003
2175
|
this.state.contextConsumers = collectContextConsumers(ir.metadata);
|
|
2004
|
-
this.state.
|
|
2176
|
+
this.state.ssrSeedPlan = ir.metadata.ssrSeedPlan ?? computeSsrSeedPlan(ir.metadata);
|
|
2177
|
+
this.state.envSignalReadersByLocal = new Map;
|
|
2178
|
+
this.state.searchParamsLocals = new Set;
|
|
2179
|
+
for (const step of this.state.ssrSeedPlan.steps) {
|
|
2180
|
+
if (step.kind !== "env-reader")
|
|
2181
|
+
continue;
|
|
2182
|
+
const reader = envSignalReaderFor(step.reader.key);
|
|
2183
|
+
if (reader)
|
|
2184
|
+
this.state.envSignalReadersByLocal.set(step.name, reader);
|
|
2185
|
+
if (step.reader.key === "search")
|
|
2186
|
+
this.state.searchParamsLocals.add(step.name);
|
|
2187
|
+
}
|
|
2005
2188
|
this.state.loweringMatchers = prepareLoweringMatchers(ir.metadata);
|
|
2006
2189
|
augmentInheritedPropAccesses(ir);
|
|
2007
2190
|
}
|
|
@@ -2163,11 +2346,22 @@ ${scriptRegistrations}${templateBody}
|
|
|
2163
2346
|
contextFieldName(c) {
|
|
2164
2347
|
return capitalizeFieldName(c.localName);
|
|
2165
2348
|
}
|
|
2349
|
+
isMapRootedContextChain(node) {
|
|
2350
|
+
if (node.kind === "identifier") {
|
|
2351
|
+
return this.state.contextConsumers.some((c) => c.localName === node.name && c.defaultKind === "object");
|
|
2352
|
+
}
|
|
2353
|
+
if (node.kind === "member" && !node.computed) {
|
|
2354
|
+
return this.isMapRootedContextChain(node.object);
|
|
2355
|
+
}
|
|
2356
|
+
return false;
|
|
2357
|
+
}
|
|
2166
2358
|
contextConsumerGoType(c) {
|
|
2167
2359
|
if (typeof c.defaultValue === "number")
|
|
2168
2360
|
return "int";
|
|
2169
2361
|
if (typeof c.defaultValue === "boolean")
|
|
2170
2362
|
return "bool";
|
|
2363
|
+
if (c.defaultKind === "object")
|
|
2364
|
+
return "map[string]interface{}";
|
|
2171
2365
|
return "string";
|
|
2172
2366
|
}
|
|
2173
2367
|
contextConsumerGoDefault(c) {
|
|
@@ -2177,6 +2371,8 @@ ${scriptRegistrations}${templateBody}
|
|
|
2177
2371
|
return String(c.defaultValue);
|
|
2178
2372
|
if (typeof c.defaultValue === "string")
|
|
2179
2373
|
return `"${escapeGoString(c.defaultValue)}"`;
|
|
2374
|
+
if (c.defaultKind === "object")
|
|
2375
|
+
return "map[string]interface{}{}";
|
|
2180
2376
|
return '""';
|
|
2181
2377
|
}
|
|
2182
2378
|
nonCollidingContextConsumers(taken) {
|
|
@@ -2223,12 +2419,15 @@ ${goFields.join(`
|
|
|
2223
2419
|
}
|
|
2224
2420
|
structFieldsFor(td) {
|
|
2225
2421
|
const fields = [];
|
|
2422
|
+
const seenGoNames = new Set;
|
|
2226
2423
|
for (const prop of td.properties ?? []) {
|
|
2227
|
-
|
|
2424
|
+
const goName = goFieldNameForKey(prop.name);
|
|
2425
|
+
if (seenGoNames.has(goName))
|
|
2228
2426
|
continue;
|
|
2427
|
+
seenGoNames.add(goName);
|
|
2229
2428
|
fields.push({
|
|
2230
2429
|
tsName: prop.name,
|
|
2231
|
-
goName
|
|
2430
|
+
goName,
|
|
2232
2431
|
goType: typeInfoToGo(this.emitCtx, prop.type)
|
|
2233
2432
|
});
|
|
2234
2433
|
}
|
|
@@ -2456,10 +2655,10 @@ ${goFields.join(`
|
|
|
2456
2655
|
}
|
|
2457
2656
|
return "interface{}";
|
|
2458
2657
|
}
|
|
2459
|
-
collectBodyChildInstances(bodyChildren) {
|
|
2658
|
+
collectBodyChildInstances(bodyChildren, propsParams = []) {
|
|
2460
2659
|
const result = [];
|
|
2461
2660
|
for (const child of bodyChildren) {
|
|
2462
|
-
this.collectStaticChildInstancesRecursive(child, result, false, new Map);
|
|
2661
|
+
this.collectStaticChildInstancesRecursive(child, result, false, new Map, propsParams);
|
|
2463
2662
|
}
|
|
2464
2663
|
return result;
|
|
2465
2664
|
}
|
|
@@ -2505,6 +2704,28 @@ ${goFields.join(`
|
|
|
2505
2704
|
if (propFallbackVars.size > 0)
|
|
2506
2705
|
lines.push("");
|
|
2507
2706
|
this.emitDynamicBodyWrappers(lines, ir, componentName, dynamicWithBody, propFallbackVars, emittedWrapperVars);
|
|
2707
|
+
const memoPropsParamMap = new Map(ir.metadata.propsParams.map((p) => [p.name, p]));
|
|
2708
|
+
this.state.hoistedMemoLocals = new Map;
|
|
2709
|
+
const hoistNames = new Set;
|
|
2710
|
+
for (const memo of ir.metadata.memos) {
|
|
2711
|
+
for (const name of filterArmEarlierSiblingRefs(this.emitCtx, memo, ir.metadata.signals, ir.metadata.propsParams)) {
|
|
2712
|
+
hoistNames.add(name);
|
|
2713
|
+
}
|
|
2714
|
+
}
|
|
2715
|
+
if (hoistNames.size > 0) {
|
|
2716
|
+
for (const memo of ir.metadata.memos) {
|
|
2717
|
+
if (!hoistNames.has(memo.name))
|
|
2718
|
+
continue;
|
|
2719
|
+
const goType = this.inferMemoType(memo, ir.metadata.signals, memoPropsParamMap);
|
|
2720
|
+
const value = computeMemoInitialValue(this.emitCtx, memo, ir.metadata.signals, ir.metadata.propsParams, propFallbackVars, goType);
|
|
2721
|
+
let localName = `memo${capitalizeFieldName(memo.name)}`;
|
|
2722
|
+
while (GO_KEYWORDS.has(localName))
|
|
2723
|
+
localName += "_";
|
|
2724
|
+
lines.push(` var ${localName} ${goType} = ${value}`);
|
|
2725
|
+
this.state.hoistedMemoLocals.set(memo.name, localName);
|
|
2726
|
+
}
|
|
2727
|
+
lines.push("");
|
|
2728
|
+
}
|
|
2508
2729
|
lines.push(` return ${propsTypeName}{`);
|
|
2509
2730
|
lines.push("\t\tScopeID: scopeID,");
|
|
2510
2731
|
lines.push("\t\tBfParent: in.BfParent,");
|
|
@@ -2578,11 +2799,15 @@ ${goFields.join(`
|
|
|
2578
2799
|
continue;
|
|
2579
2800
|
lines.push(` ${nested.name}s: ${varName},`);
|
|
2580
2801
|
}
|
|
2581
|
-
const memoPropsParamMap = new Map(ir.metadata.propsParams.map((p) => [p.name, p]));
|
|
2582
2802
|
for (const memo of ir.metadata.memos) {
|
|
2583
2803
|
const fieldName = capitalizeFieldName(memo.name);
|
|
2584
2804
|
if (propFieldNames.has(fieldName))
|
|
2585
2805
|
continue;
|
|
2806
|
+
const hoistedLocal = this.state.hoistedMemoLocals.get(memo.name);
|
|
2807
|
+
if (hoistedLocal) {
|
|
2808
|
+
lines.push(` ${fieldName}: ${hoistedLocal},`);
|
|
2809
|
+
continue;
|
|
2810
|
+
}
|
|
2586
2811
|
const goType = this.inferMemoType(memo, ir.metadata.signals, memoPropsParamMap);
|
|
2587
2812
|
const memoValue = computeMemoInitialValue(this.emitCtx, memo, ir.metadata.signals, ir.metadata.propsParams, propFallbackVars, goType);
|
|
2588
2813
|
lines.push(` ${fieldName}: ${memoValue},`);
|
|
@@ -2603,7 +2828,7 @@ ${goFields.join(`
|
|
|
2603
2828
|
for (const c of this.nonCollidingContextConsumers(takenInit)) {
|
|
2604
2829
|
const field = this.contextFieldName(c);
|
|
2605
2830
|
const def = this.contextConsumerGoDefault(c);
|
|
2606
|
-
const defaulted = c.defaultValue === null || def === '""' || def === "0" || def === "false" ? `in.${field}` : applyGoFallback(`in.${field}`, def);
|
|
2831
|
+
const defaulted = c.defaultValue === null || def === '""' || def === "0" || def === "false" || def === "map[string]interface{}{}" ? `in.${field}` : applyGoFallback(`in.${field}`, def);
|
|
2607
2832
|
lines.push(` ${field}: ${defaulted},`);
|
|
2608
2833
|
}
|
|
2609
2834
|
this.emitStaticChildInstances(lines, ir);
|
|
@@ -2612,7 +2837,7 @@ ${goFields.join(`
|
|
|
2612
2837
|
lines.push("}");
|
|
2613
2838
|
}
|
|
2614
2839
|
emitStaticChildInstances(lines, ir) {
|
|
2615
|
-
const staticChildren = this.collectStaticChildInstances(ir.root);
|
|
2840
|
+
const staticChildren = this.collectStaticChildInstances(ir.root, ir.metadata.propsParams);
|
|
2616
2841
|
for (const child of staticChildren) {
|
|
2617
2842
|
lines.push(` ${child.fieldName}: New${child.name}Props(${child.name}Input{`);
|
|
2618
2843
|
lines.push(` ScopeID: scopeID + "_${child.slotId}",`);
|
|
@@ -2744,7 +2969,7 @@ ${goFields.join(`
|
|
|
2744
2969
|
const varName = `${nested.name.charAt(0).toLowerCase()}${nested.name.slice(1)}s`;
|
|
2745
2970
|
const wrapperType = this.loopBodyWrapperName(componentName, nested);
|
|
2746
2971
|
const datumFields = this.resolveLoopDatumFields(nested.loopItemType);
|
|
2747
|
-
const bodyChildInstances = this.collectBodyChildInstances(nested.bodyChildren);
|
|
2972
|
+
const bodyChildInstances = this.collectBodyChildInstances(nested.bodyChildren, ir.metadata.propsParams);
|
|
2748
2973
|
for (const child of bodyChildInstances) {
|
|
2749
2974
|
const childVar = `child_${child.fieldName}`;
|
|
2750
2975
|
lines.push(` ${childVar} := New${child.name}Props(${child.name}Input{`);
|
|
@@ -2821,7 +3046,7 @@ ${goFields.join(`
|
|
|
2821
3046
|
const wrapperType = this.loopBodyWrapperName(componentName, nested);
|
|
2822
3047
|
const varName = `${nested.name.charAt(0).toLowerCase()}${nested.name.slice(1)}s`;
|
|
2823
3048
|
const datumFields = this.resolveLoopDatumFields(nested.loopItemType);
|
|
2824
|
-
const bodyChildInstances = this.collectBodyChildInstances(nested.bodyChildren);
|
|
3049
|
+
const bodyChildInstances = this.collectBodyChildInstances(nested.bodyChildren, ir.metadata.propsParams);
|
|
2825
3050
|
for (const child of bodyChildInstances) {
|
|
2826
3051
|
const childVar = `child_${child.fieldName}`;
|
|
2827
3052
|
lines.push(` ${childVar} := New${child.name}Props(${child.name}Input{`);
|
|
@@ -3061,7 +3286,7 @@ ${goFields.join(`
|
|
|
3061
3286
|
lines.push(` ${nested.name}s []${elemType} \`json:"${jsonTag}"\``);
|
|
3062
3287
|
}
|
|
3063
3288
|
}
|
|
3064
|
-
const staticChildren = this.collectStaticChildInstances(ir.root);
|
|
3289
|
+
const staticChildren = this.collectStaticChildInstances(ir.root, ir.metadata.propsParams);
|
|
3065
3290
|
for (const child of staticChildren) {
|
|
3066
3291
|
lines.push(` ${child.fieldName} ${child.name}Props \`json:"-"\``);
|
|
3067
3292
|
}
|
|
@@ -3073,9 +3298,9 @@ ${goFields.join(`
|
|
|
3073
3298
|
toJsonTag(name) {
|
|
3074
3299
|
return name.charAt(0).toLowerCase() + name.slice(1);
|
|
3075
3300
|
}
|
|
3076
|
-
collectStaticChildInstances(node) {
|
|
3301
|
+
collectStaticChildInstances(node, propsParams = []) {
|
|
3077
3302
|
const result = [];
|
|
3078
|
-
this.collectStaticChildInstancesRecursive(node, result, false, new Map);
|
|
3303
|
+
this.collectStaticChildInstancesRecursive(node, result, false, new Map, propsParams);
|
|
3079
3304
|
return result;
|
|
3080
3305
|
}
|
|
3081
3306
|
extractTextChildren(children) {
|
|
@@ -3120,12 +3345,12 @@ ${goFields.join(`
|
|
|
3120
3345
|
return null;
|
|
3121
3346
|
return withSentinel.split(GoTemplateAdapter.SCOPE_SENTINEL).map((seg) => JSON.stringify(seg)).join(" + scopeID + ");
|
|
3122
3347
|
}
|
|
3123
|
-
collectStaticChildInstancesRecursive(node, result, inLoop, providerCtx) {
|
|
3348
|
+
collectStaticChildInstancesRecursive(node, result, inLoop, providerCtx, propsParams = []) {
|
|
3124
3349
|
if (node.type === "component") {
|
|
3125
3350
|
const comp = node;
|
|
3126
3351
|
if (comp.dynamicTag) {
|
|
3127
3352
|
for (const child of comp.children) {
|
|
3128
|
-
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx);
|
|
3353
|
+
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx, propsParams);
|
|
3129
3354
|
}
|
|
3130
3355
|
return;
|
|
3131
3356
|
}
|
|
@@ -3143,69 +3368,111 @@ ${goFields.join(`
|
|
|
3143
3368
|
contextBindings: providerCtx.size > 0 ? providerCtx : undefined
|
|
3144
3369
|
});
|
|
3145
3370
|
for (const child of effectiveChildren) {
|
|
3146
|
-
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx);
|
|
3371
|
+
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx, propsParams);
|
|
3147
3372
|
}
|
|
3148
3373
|
}
|
|
3149
3374
|
if (comp.name === "Portal" && comp.children) {
|
|
3150
3375
|
for (const child of comp.children) {
|
|
3151
|
-
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx);
|
|
3376
|
+
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx, propsParams);
|
|
3152
3377
|
}
|
|
3153
3378
|
}
|
|
3154
3379
|
} else if (node.type === "loop") {
|
|
3155
3380
|
const loop = node;
|
|
3156
3381
|
for (const child of loop.children) {
|
|
3157
|
-
this.collectStaticChildInstancesRecursive(child, result,
|
|
3382
|
+
this.collectStaticChildInstancesRecursive(child, result, inLoop || !!loop.childComponent, providerCtx, propsParams);
|
|
3158
3383
|
}
|
|
3159
3384
|
} else if (node.type === "element") {
|
|
3160
3385
|
const element = node;
|
|
3161
3386
|
for (const child of element.children) {
|
|
3162
|
-
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx);
|
|
3387
|
+
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx, propsParams);
|
|
3163
3388
|
}
|
|
3164
3389
|
} else if (node.type === "fragment") {
|
|
3165
3390
|
const fragment = node;
|
|
3166
3391
|
for (const child of fragment.children) {
|
|
3167
|
-
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx);
|
|
3392
|
+
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx, propsParams);
|
|
3168
3393
|
}
|
|
3169
3394
|
} else if (node.type === "conditional") {
|
|
3170
3395
|
const cond = node;
|
|
3171
|
-
this.collectStaticChildInstancesRecursive(cond.whenTrue, result, inLoop, providerCtx);
|
|
3396
|
+
this.collectStaticChildInstancesRecursive(cond.whenTrue, result, inLoop, providerCtx, propsParams);
|
|
3172
3397
|
if (cond.whenFalse) {
|
|
3173
|
-
this.collectStaticChildInstancesRecursive(cond.whenFalse, result, inLoop, providerCtx);
|
|
3398
|
+
this.collectStaticChildInstancesRecursive(cond.whenFalse, result, inLoop, providerCtx, propsParams);
|
|
3174
3399
|
}
|
|
3175
3400
|
} else if (node.type === "if-statement") {
|
|
3176
3401
|
const stmt = node;
|
|
3177
|
-
this.collectStaticChildInstancesRecursive(stmt.consequent, result, inLoop, providerCtx);
|
|
3402
|
+
this.collectStaticChildInstancesRecursive(stmt.consequent, result, inLoop, providerCtx, propsParams);
|
|
3178
3403
|
if (stmt.alternate) {
|
|
3179
|
-
this.collectStaticChildInstancesRecursive(stmt.alternate, result, inLoop, providerCtx);
|
|
3404
|
+
this.collectStaticChildInstancesRecursive(stmt.alternate, result, inLoop, providerCtx, propsParams);
|
|
3180
3405
|
}
|
|
3181
3406
|
} else if (node.type === "provider") {
|
|
3182
3407
|
const p = node;
|
|
3183
|
-
const childCtx = this.extendProviderContext(providerCtx, p);
|
|
3408
|
+
const childCtx = this.extendProviderContext(providerCtx, p, propsParams);
|
|
3184
3409
|
for (const child of p.children) {
|
|
3185
|
-
this.collectStaticChildInstancesRecursive(child, result, inLoop, childCtx);
|
|
3410
|
+
this.collectStaticChildInstancesRecursive(child, result, inLoop, childCtx, propsParams);
|
|
3186
3411
|
}
|
|
3187
3412
|
} else if (node.type === "async") {
|
|
3188
3413
|
const a = node;
|
|
3189
|
-
this.collectStaticChildInstancesRecursive(a.fallback, result, inLoop, providerCtx);
|
|
3414
|
+
this.collectStaticChildInstancesRecursive(a.fallback, result, inLoop, providerCtx, propsParams);
|
|
3190
3415
|
for (const child of a.children) {
|
|
3191
|
-
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx);
|
|
3416
|
+
this.collectStaticChildInstancesRecursive(child, result, inLoop, providerCtx, propsParams);
|
|
3192
3417
|
}
|
|
3193
3418
|
}
|
|
3194
3419
|
}
|
|
3195
|
-
extendProviderContext(current, p) {
|
|
3420
|
+
extendProviderContext(current, p, propsParams) {
|
|
3196
3421
|
const v = p.valueProp?.value;
|
|
3197
|
-
if (!v
|
|
3422
|
+
if (!v)
|
|
3198
3423
|
return current;
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3424
|
+
if (v.kind === "literal") {
|
|
3425
|
+
let goLit = null;
|
|
3426
|
+
if (typeof v.value === "string")
|
|
3427
|
+
goLit = `"${escapeGoString(v.value)}"`;
|
|
3428
|
+
else if (typeof v.value === "number" || typeof v.value === "boolean")
|
|
3429
|
+
goLit = String(v.value);
|
|
3430
|
+
if (goLit === null)
|
|
3431
|
+
return current;
|
|
3432
|
+
const next = new Map(current);
|
|
3433
|
+
next.set(p.contextName, goLit);
|
|
3434
|
+
return next;
|
|
3435
|
+
}
|
|
3436
|
+
if (v.kind === "expression" && v.parsed) {
|
|
3437
|
+
const goMap = this.providerObjectValueToGoMap(v.parsed, propsParams);
|
|
3438
|
+
if (goMap !== null) {
|
|
3439
|
+
const next = new Map(current);
|
|
3440
|
+
next.set(p.contextName, goMap);
|
|
3441
|
+
return next;
|
|
3442
|
+
}
|
|
3443
|
+
}
|
|
3444
|
+
return current;
|
|
3445
|
+
}
|
|
3446
|
+
providerObjectValueToGoMap(parsed, propsParams) {
|
|
3447
|
+
if (parsed.kind !== "object-literal")
|
|
3448
|
+
return null;
|
|
3449
|
+
const entries = [];
|
|
3450
|
+
for (const prop of parsed.properties) {
|
|
3451
|
+
if (prop.shorthand)
|
|
3452
|
+
return null;
|
|
3453
|
+
const goVal = this.lowerProviderMapMemberValue(prop.value, propsParams);
|
|
3454
|
+
if (goVal === null)
|
|
3455
|
+
return null;
|
|
3456
|
+
entries.push(`${JSON.stringify(prop.key)}: ${goVal}`);
|
|
3457
|
+
}
|
|
3458
|
+
if (entries.length === 0)
|
|
3459
|
+
return null;
|
|
3460
|
+
return `map[string]interface{}{${entries.join(", ")}}`;
|
|
3461
|
+
}
|
|
3462
|
+
lowerProviderMapMemberValue(node, propsParams) {
|
|
3463
|
+
if (node.kind === "object-literal")
|
|
3464
|
+
return objectLiteralToGoMap(this.emitCtx, node);
|
|
3465
|
+
const literal = parsedLiteralToGo(this.emitCtx, node);
|
|
3466
|
+
if (literal !== null)
|
|
3467
|
+
return literal;
|
|
3468
|
+
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) {
|
|
3469
|
+
const propName = node.left.property;
|
|
3470
|
+
if (propsParams.some((param) => param.name === propName)) {
|
|
3471
|
+
const fieldRef = `in.${capitalizeFieldName(propName)}`;
|
|
3472
|
+
return `func() map[string]interface{} { ` + `if m := bf.AsMap(${fieldRef}); m != nil { return m }; ` + `return map[string]interface{}{} }()`;
|
|
3473
|
+
}
|
|
3474
|
+
}
|
|
3475
|
+
return null;
|
|
3209
3476
|
}
|
|
3210
3477
|
templatePartsToGoCode(parts, propsParams) {
|
|
3211
3478
|
const segments = [];
|
|
@@ -3271,12 +3538,14 @@ ${goFields.join(`
|
|
|
3271
3538
|
}
|
|
3272
3539
|
const memo = memos.find((m) => m.name === getterName);
|
|
3273
3540
|
if (memo) {
|
|
3274
|
-
return computeMemoInitialValueOrNull(this.emitCtx, memo, signals, propsParams);
|
|
3541
|
+
return computeMemoInitialValueOrNull(this.emitCtx, memo, signals, propsParams, undefined, new Set([memo.name]));
|
|
3275
3542
|
}
|
|
3276
3543
|
}
|
|
3277
3544
|
return null;
|
|
3278
3545
|
}
|
|
3279
3546
|
inferMemoType(memo, signals, propsParamMap) {
|
|
3547
|
+
if (isListFilterMemo(memo))
|
|
3548
|
+
return "[]any";
|
|
3280
3549
|
if (memo.bodyIsTemplateLiteral)
|
|
3281
3550
|
return "string";
|
|
3282
3551
|
if (memo.computation.includes("*") || memo.computation.includes("/") || memo.computation.includes("+") || memo.computation.includes("-")) {
|
|
@@ -3673,15 +3942,19 @@ ${goFields.join(`
|
|
|
3673
3942
|
if (objHO && (objHO.method === "find" || objHO.method === "findLast")) {
|
|
3674
3943
|
const findResult = this.renderHigherOrderExpr(objHO, emit);
|
|
3675
3944
|
if (findResult) {
|
|
3676
|
-
return `{{with ${findResult}}}{{.${
|
|
3945
|
+
return `{{with ${findResult}}}{{.${goFieldNameForKey(property)}}}{{end}}`;
|
|
3677
3946
|
}
|
|
3678
|
-
const templateBlock = this.renderFindTemplateBlock(objHO, emit,
|
|
3947
|
+
const templateBlock = this.renderFindTemplateBlock(objHO, emit, goFieldNameForKey(property));
|
|
3679
3948
|
if (templateBlock)
|
|
3680
3949
|
return templateBlock;
|
|
3681
3950
|
}
|
|
3682
3951
|
if (object.kind === "identifier" && this.state.propsObjectName && object.name === this.state.propsObjectName) {
|
|
3683
3952
|
return this.rootFieldRef(property);
|
|
3684
3953
|
}
|
|
3954
|
+
if (this.isMapRootedContextChain(object)) {
|
|
3955
|
+
const objGo = emit(object);
|
|
3956
|
+
return `bf_get ${wrapIfMultiToken(objGo)} ${JSON.stringify(property)}`;
|
|
3957
|
+
}
|
|
3685
3958
|
if (object.kind === "identifier") {
|
|
3686
3959
|
const staticValue = this.resolveStaticRecordLiteralIndex(`${object.name}.${property}`);
|
|
3687
3960
|
if (staticValue !== null)
|
|
@@ -3689,12 +3962,12 @@ ${goFields.join(`
|
|
|
3689
3962
|
}
|
|
3690
3963
|
const currentLoopParam = this.loopParamStack[this.loopParamStack.length - 1];
|
|
3691
3964
|
if (object.kind === "identifier" && currentLoopParam && object.name === currentLoopParam) {
|
|
3692
|
-
return `.${
|
|
3965
|
+
return `.${goFieldNameForKey(property)}`;
|
|
3693
3966
|
}
|
|
3694
3967
|
const obj = emit(object);
|
|
3695
3968
|
if (property === "length")
|
|
3696
3969
|
return `len ${obj}`;
|
|
3697
|
-
return `${obj}.${
|
|
3970
|
+
return `${obj}.${goFieldNameForKey(property)}`;
|
|
3698
3971
|
}
|
|
3699
3972
|
indexAccess(object, index, emit) {
|
|
3700
3973
|
return `index ${wrapIfMultiToken(emit(object))} ${wrapIfMultiToken(emit(index))}`;
|
|
@@ -3786,7 +4059,16 @@ ${goFields.join(`
|
|
|
3786
4059
|
return `bf_arr ${parts.join(" ")}`;
|
|
3787
4060
|
}
|
|
3788
4061
|
objectLiteral(_properties, raw, _emit) {
|
|
3789
|
-
|
|
4062
|
+
this.state.errors.push({
|
|
4063
|
+
code: "BF101",
|
|
4064
|
+
severity: "error",
|
|
4065
|
+
message: `Expression not supported: ${raw}`,
|
|
4066
|
+
loc: this.makeLoc(),
|
|
4067
|
+
suggestion: {
|
|
4068
|
+
message: `Go templates have no object/map literal syntax, so the \`?? {}\` fallback can't render server-side. ${GO_REMEDIATION_OPTIONS}`
|
|
4069
|
+
}
|
|
4070
|
+
});
|
|
4071
|
+
return `""`;
|
|
3790
4072
|
}
|
|
3791
4073
|
static PREDICATE_METHODS = new Set([
|
|
3792
4074
|
"filter",
|
|
@@ -3798,7 +4080,7 @@ ${goFields.join(`
|
|
|
3798
4080
|
"some"
|
|
3799
4081
|
]);
|
|
3800
4082
|
higherOrderShapeOf(node) {
|
|
3801
|
-
const cb =
|
|
4083
|
+
const cb = asCallbackMethodCall3(node);
|
|
3802
4084
|
if (!cb)
|
|
3803
4085
|
return null;
|
|
3804
4086
|
if (!GoTemplateAdapter.PREDICATE_METHODS.has(cb.method))
|
|
@@ -3873,6 +4155,12 @@ ${goFields.join(`
|
|
|
3873
4155
|
return evalForm;
|
|
3874
4156
|
return this.pushCallbackBF101(method, true);
|
|
3875
4157
|
}
|
|
4158
|
+
if (method === "map") {
|
|
4159
|
+
const evalForm = emitMapEval(recv, body, params[0] ?? "_", emit);
|
|
4160
|
+
if (evalForm !== null)
|
|
4161
|
+
return evalForm;
|
|
4162
|
+
return this.pushCallbackBF101(method, true);
|
|
4163
|
+
}
|
|
3876
4164
|
return this.pushCallbackBF101(method, true);
|
|
3877
4165
|
}
|
|
3878
4166
|
arrayMethod(method, object, args, emit) {
|
|
@@ -3993,6 +4281,9 @@ ${goFields.join(`
|
|
|
3993
4281
|
}
|
|
3994
4282
|
}
|
|
3995
4283
|
flatMethod(object, depth, emit) {
|
|
4284
|
+
if (typeof depth === "object") {
|
|
4285
|
+
return `bf_flat_dynamic ${wrapIfMultiToken(emit(object))} ${wrapIfMultiToken(emit(depth.expr))}`;
|
|
4286
|
+
}
|
|
3996
4287
|
const d = depth === "infinity" ? -1 : depth;
|
|
3997
4288
|
return `bf_flat ${wrapIfMultiToken(emit(object))} ${d}`;
|
|
3998
4289
|
}
|
|
@@ -4226,6 +4517,9 @@ ${goFields.join(`
|
|
|
4226
4517
|
if (expr.callee.kind === "identifier" && expr.args.length === 0) {
|
|
4227
4518
|
return `$.${capitalizeFieldName(expr.callee.name)}`;
|
|
4228
4519
|
}
|
|
4520
|
+
if (asCallbackMethodCall3(expr) !== null) {
|
|
4521
|
+
return this.refuseFilterExprNode(expr);
|
|
4522
|
+
}
|
|
4229
4523
|
const result = this.renderFilterExpr(expr.callee, param, localVarMap);
|
|
4230
4524
|
if (this.filterExprUnsupported)
|
|
4231
4525
|
return "false";
|
|
@@ -4290,21 +4584,23 @@ ${goFields.join(`
|
|
|
4290
4584
|
}
|
|
4291
4585
|
return `or (${left}) (${right})`;
|
|
4292
4586
|
}
|
|
4293
|
-
default:
|
|
4294
|
-
this.
|
|
4295
|
-
this.state.errors.push({
|
|
4296
|
-
code: "BF101",
|
|
4297
|
-
severity: "error",
|
|
4298
|
-
message: `Filter predicate contains an expression that cannot be lowered to a Go template action: ${exprToString(expr)}`,
|
|
4299
|
-
loc: this.makeLoc(),
|
|
4300
|
-
suggestion: {
|
|
4301
|
-
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)"
|
|
4302
|
-
}
|
|
4303
|
-
});
|
|
4304
|
-
return "false";
|
|
4305
|
-
}
|
|
4587
|
+
default:
|
|
4588
|
+
return this.refuseFilterExprNode(expr);
|
|
4306
4589
|
}
|
|
4307
4590
|
}
|
|
4591
|
+
refuseFilterExprNode(expr) {
|
|
4592
|
+
this.filterExprUnsupported = true;
|
|
4593
|
+
this.state.errors.push({
|
|
4594
|
+
code: "BF101",
|
|
4595
|
+
severity: "error",
|
|
4596
|
+
message: `Filter predicate contains an expression that cannot be lowered to a Go template action: ${exprToString(expr)}`,
|
|
4597
|
+
loc: this.makeLoc(),
|
|
4598
|
+
suggestion: {
|
|
4599
|
+
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)"
|
|
4600
|
+
}
|
|
4601
|
+
});
|
|
4602
|
+
return "false";
|
|
4603
|
+
}
|
|
4308
4604
|
isGoFunctionCall(expr) {
|
|
4309
4605
|
switch (expr.kind) {
|
|
4310
4606
|
case "binary":
|
|
@@ -4558,7 +4854,7 @@ ${goFields.join(`
|
|
|
4558
4854
|
});
|
|
4559
4855
|
return plain("false");
|
|
4560
4856
|
}
|
|
4561
|
-
if (
|
|
4857
|
+
if (asCallbackMethodCall3(expr)) {
|
|
4562
4858
|
const rendered = this.renderParsedExpr(expr);
|
|
4563
4859
|
const split = this.splitPreamble(rendered);
|
|
4564
4860
|
if (split)
|
|
@@ -4686,23 +4982,44 @@ ${goFields.join(`
|
|
|
4686
4982
|
return plain(expr.raw);
|
|
4687
4983
|
}
|
|
4688
4984
|
}
|
|
4985
|
+
buildSegmentAccessor(base, segments) {
|
|
4986
|
+
let acc = base;
|
|
4987
|
+
for (const seg of segments) {
|
|
4988
|
+
acc = seg.kind === "field" ? `${acc}.${goFieldNameForKey(seg.key)}` : `(index ${acc} ${seg.index})`;
|
|
4989
|
+
}
|
|
4990
|
+
return acc;
|
|
4991
|
+
}
|
|
4689
4992
|
buildDestructureBindingMap(loop, rangeVar) {
|
|
4690
|
-
const
|
|
4993
|
+
const bindings = new Map;
|
|
4994
|
+
const restExcludes = new Map;
|
|
4995
|
+
const base = `$${rangeVar}`;
|
|
4691
4996
|
for (const b of loop.paramBindings ?? []) {
|
|
4692
|
-
|
|
4693
|
-
|
|
4997
|
+
const parent = this.buildSegmentAccessor(base, b.segments ?? []);
|
|
4998
|
+
if (!b.rest) {
|
|
4999
|
+
bindings.set(b.name, parent);
|
|
5000
|
+
} else if (b.rest.kind === "array") {
|
|
5001
|
+
bindings.set(b.name, `(bf_slice ${parent} ${b.rest.from})`);
|
|
4694
5002
|
} else {
|
|
4695
|
-
|
|
5003
|
+
bindings.set(b.name, parent);
|
|
5004
|
+
restExcludes.set(b.name, { parent, excludeKeys: b.rest.exclude.map((k) => k.key) });
|
|
4696
5005
|
}
|
|
4697
5006
|
}
|
|
4698
|
-
return
|
|
5007
|
+
return { bindings, restExcludes };
|
|
5008
|
+
}
|
|
5009
|
+
lookupRestExclude(name) {
|
|
5010
|
+
for (let i = this.loopRestExcludeStack.length - 1;i >= 0; i--) {
|
|
5011
|
+
const info = this.loopRestExcludeStack[i].get(name);
|
|
5012
|
+
if (info)
|
|
5013
|
+
return info;
|
|
5014
|
+
}
|
|
5015
|
+
return;
|
|
4699
5016
|
}
|
|
4700
5017
|
renderLoop(loop) {
|
|
4701
5018
|
if (loop.clientOnly) {
|
|
4702
5019
|
return `{{bfComment "loop:${loop.markerId}"}}{{bfComment "/loop:${loop.markerId}"}}`;
|
|
4703
5020
|
}
|
|
4704
5021
|
const destructure = !!(loop.paramBindings && loop.paramBindings.length > 0);
|
|
4705
|
-
const supportableDestructure = destructure &&
|
|
5022
|
+
const supportableDestructure = destructure && isLowerableLoopDestructure(loop);
|
|
4706
5023
|
if (destructure && !supportableDestructure) {
|
|
4707
5024
|
this.state.errors.push({
|
|
4708
5025
|
code: "BF104",
|
|
@@ -4717,6 +5034,21 @@ ${goFields.join(`
|
|
|
4717
5034
|
}
|
|
4718
5035
|
});
|
|
4719
5036
|
}
|
|
5037
|
+
const arrayName = loop.array.trim();
|
|
5038
|
+
if (/^[A-Za-z_$][\w$]*$/.test(arrayName)) {
|
|
5039
|
+
const arrayConst = this.state.localConstants.find((c) => c.name === arrayName);
|
|
5040
|
+
if (arrayConst && !arrayConst.isModule && arrayConst.parsed && !this.isStringExpr(arrayConst.parsed, new Set)) {
|
|
5041
|
+
this.state.errors.push({
|
|
5042
|
+
code: "BF101",
|
|
5043
|
+
severity: "error",
|
|
5044
|
+
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.`,
|
|
5045
|
+
loc: loop.loc ?? this.makeLoc(),
|
|
5046
|
+
suggestion: {
|
|
5047
|
+
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."
|
|
5048
|
+
}
|
|
5049
|
+
});
|
|
5050
|
+
}
|
|
5051
|
+
}
|
|
4720
5052
|
let goArray = this.convertExpressionToGo(loop.array);
|
|
4721
5053
|
const param = loop.param;
|
|
4722
5054
|
let index = loop.index || "_";
|
|
@@ -4726,15 +5058,16 @@ ${goFields.join(`
|
|
|
4726
5058
|
rangeIndex = param;
|
|
4727
5059
|
rangeValue = "_";
|
|
4728
5060
|
}
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
goArray = `.${childComponent.name}s`;
|
|
5061
|
+
if (loop.childComponent) {
|
|
5062
|
+
goArray = `.${loop.childComponent.name}s`;
|
|
4732
5063
|
}
|
|
4733
5064
|
this.inLoop = true;
|
|
4734
5065
|
const addedLoopVars = [];
|
|
4735
5066
|
let pushedBindingMap = false;
|
|
4736
5067
|
if (supportableDestructure) {
|
|
4737
|
-
this.
|
|
5068
|
+
const built = this.buildDestructureBindingMap(loop, rangeValue);
|
|
5069
|
+
this.loopBindingStack.push(built.bindings);
|
|
5070
|
+
this.loopRestExcludeStack.push(built.restExcludes);
|
|
4738
5071
|
pushedBindingMap = true;
|
|
4739
5072
|
this.loopParamStack.push("");
|
|
4740
5073
|
if (rangeIndex !== "_") {
|
|
@@ -4753,7 +5086,9 @@ ${goFields.join(`
|
|
|
4753
5086
|
}
|
|
4754
5087
|
}
|
|
4755
5088
|
this.loopScalarItemStack.push(this.scalarLiteralLoopGoType(loop.arrayParsed, loop.itemType) !== null);
|
|
5089
|
+
this.loopWrapperStack.push(!!loop.childComponent);
|
|
4756
5090
|
const children = this.renderChildren(loop.children);
|
|
5091
|
+
this.loopWrapperStack.pop();
|
|
4757
5092
|
this.loopScalarItemStack.pop();
|
|
4758
5093
|
const itemMarker = this.loopItemMarker(loop);
|
|
4759
5094
|
for (const v of addedLoopVars) {
|
|
@@ -4764,8 +5099,10 @@ ${goFields.join(`
|
|
|
4764
5099
|
this.loopVarRefCount.set(v, rc);
|
|
4765
5100
|
}
|
|
4766
5101
|
this.loopParamStack.pop();
|
|
4767
|
-
if (pushedBindingMap)
|
|
5102
|
+
if (pushedBindingMap) {
|
|
4768
5103
|
this.loopBindingStack.pop();
|
|
5104
|
+
this.loopRestExcludeStack.pop();
|
|
5105
|
+
}
|
|
4769
5106
|
this.inLoop = false;
|
|
4770
5107
|
if (loop.sortComparator) {
|
|
4771
5108
|
const sortEmit = (e) => this.renderParsedExpr(e);
|
|
@@ -4794,24 +5131,6 @@ ${goFields.join(`
|
|
|
4794
5131
|
}
|
|
4795
5132
|
return "";
|
|
4796
5133
|
}
|
|
4797
|
-
findChildComponent(nodes) {
|
|
4798
|
-
for (const node of nodes) {
|
|
4799
|
-
if (node.type === "component") {
|
|
4800
|
-
return node;
|
|
4801
|
-
}
|
|
4802
|
-
if (node.type === "element" && node.children) {
|
|
4803
|
-
const found = this.findChildComponent(node.children);
|
|
4804
|
-
if (found)
|
|
4805
|
-
return found;
|
|
4806
|
-
}
|
|
4807
|
-
if (node.type === "fragment" && node.children) {
|
|
4808
|
-
const found = this.findChildComponent(node.children);
|
|
4809
|
-
if (found)
|
|
4810
|
-
return found;
|
|
4811
|
-
}
|
|
4812
|
-
}
|
|
4813
|
-
return null;
|
|
4814
|
-
}
|
|
4815
5134
|
queueDynamicChildrenDefine(comp) {
|
|
4816
5135
|
const effectiveChildren = comp.children.length > 0 ? comp.children : this.jsxChildrenPropNodes(comp.props);
|
|
4817
5136
|
if (effectiveChildren.length === 0)
|
|
@@ -4859,7 +5178,7 @@ ${goFields.join(`
|
|
|
4859
5178
|
return this.renderChildren(comp.children);
|
|
4860
5179
|
}
|
|
4861
5180
|
let templateCall;
|
|
4862
|
-
if (this.inLoop) {
|
|
5181
|
+
if (this.inLoop && (this.loopWrapperStack[this.loopWrapperStack.length - 1] ?? false)) {
|
|
4863
5182
|
const loopBodyDefine = this.queueLoopBodyChildrenDefine(comp);
|
|
4864
5183
|
if (loopBodyDefine) {
|
|
4865
5184
|
const bodyData = this.loopScalarItemStack[this.loopScalarItemStack.length - 1] ? ".BfLoopItem" : ".";
|
|
@@ -4867,6 +5186,12 @@ ${goFields.join(`
|
|
|
4867
5186
|
} else {
|
|
4868
5187
|
templateCall = `{{template "${comp.name}" .}}`;
|
|
4869
5188
|
}
|
|
5189
|
+
} else if (this.inLoop && comp.slotId) {
|
|
5190
|
+
const suffix = slotIdToFieldSuffix(comp.slotId);
|
|
5191
|
+
const loopBodyDefine = this.queueLoopBodyChildrenDefine(comp);
|
|
5192
|
+
templateCall = loopBodyDefine ? `{{template "${comp.name}" (bf_with_children $.${comp.name}${suffix} (bf_tmpl "${loopBodyDefine}" .))}}` : `{{template "${comp.name}" $.${comp.name}${suffix}}}`;
|
|
5193
|
+
} else if (this.inLoop) {
|
|
5194
|
+
templateCall = `{{template "${comp.name}" .}}`;
|
|
4870
5195
|
} else if (comp.slotId) {
|
|
4871
5196
|
const suffix = slotIdToFieldSuffix(comp.slotId);
|
|
4872
5197
|
const childrenDefine = this.queueDynamicChildrenDefine(comp);
|
|
@@ -4962,6 +5287,12 @@ ${children}`;
|
|
|
4962
5287
|
if (currentLoopParam && trimmed === currentLoopParam) {
|
|
4963
5288
|
return `{{bf_spread_attrs .}}`;
|
|
4964
5289
|
}
|
|
5290
|
+
const restInfo = this.lookupRestExclude(trimmed);
|
|
5291
|
+
if (restInfo) {
|
|
5292
|
+
const excludeArgs = restInfo.excludeKeys.map((k) => JSON.stringify(k)).join(" ");
|
|
5293
|
+
const omitArgs = excludeArgs ? `${restInfo.parent} ${excludeArgs}` : restInfo.parent;
|
|
5294
|
+
return `{{bf_spread_attrs (bf_omit ${omitArgs})}}`;
|
|
5295
|
+
}
|
|
4965
5296
|
const goExpr = this.convertExpressionToGo(value.expr);
|
|
4966
5297
|
return `{{bf_spread_attrs ${goExpr}}}`;
|
|
4967
5298
|
}
|
|
@@ -5089,7 +5420,26 @@ ${children}`;
|
|
|
5089
5420
|
}
|
|
5090
5421
|
}
|
|
5091
5422
|
var goTemplateAdapter = new GoTemplateAdapter;
|
|
5423
|
+
// src/conformance-pins.ts
|
|
5424
|
+
var conformancePins = {
|
|
5425
|
+
"static-array-children": [{ code: "BF103", severity: "error" }],
|
|
5426
|
+
"todo-app": [{ code: "BF103", severity: "error" }],
|
|
5427
|
+
"todo-app-ssr": [{ code: "BF103", severity: "error" }],
|
|
5428
|
+
"static-array-from-props": [{ code: "BF101", severity: "error" }],
|
|
5429
|
+
"static-array-from-props-with-component": [
|
|
5430
|
+
{ code: "BF103", severity: "error" },
|
|
5431
|
+
{ code: "BF101", severity: "error" }
|
|
5432
|
+
],
|
|
5433
|
+
"filter-nested-callback-predicate": [
|
|
5434
|
+
{ code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2038" }
|
|
5435
|
+
],
|
|
5436
|
+
"filter-nested-find-predicate": [
|
|
5437
|
+
{ code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2038" }
|
|
5438
|
+
],
|
|
5439
|
+
"array-map-function-reference": [{ code: "BF101", severity: "error" }]
|
|
5440
|
+
};
|
|
5092
5441
|
export {
|
|
5093
5442
|
goTemplateAdapter,
|
|
5443
|
+
conformancePins,
|
|
5094
5444
|
GoTemplateAdapter
|
|
5095
5445
|
};
|