@barefootjs/go-template 0.17.0 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter/go-template-adapter.d.ts +10 -0
- package/dist/adapter/go-template-adapter.d.ts.map +1 -1
- package/dist/adapter/index.js +221 -36
- 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/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/build.js +221 -36
- package/dist/index.js +221 -36
- package/package.json +3 -3
- package/src/__tests__/go-template-adapter.test.ts +280 -0
- package/src/adapter/go-template-adapter.ts +126 -31
- package/src/adapter/lib/compile-state.ts +31 -0
- package/src/adapter/lib/go-emit.ts +20 -0
- package/src/adapter/memo/memo-compute.ts +228 -18
- package/src/adapter/memo/memo-type.ts +19 -0
- package/src/test-render.ts +46 -8
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ 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,
|
|
@@ -40,8 +40,9 @@ import {
|
|
|
40
40
|
collectContextConsumers,
|
|
41
41
|
isLowerableObjectRestDestructure,
|
|
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";
|
|
@@ -224,6 +225,13 @@ function emitFlatMapEval(recv, body, param, emit) {
|
|
|
224
225
|
const env = emitEvalEnvArg(body, [param], emit);
|
|
225
226
|
return `bf_flat_map_eval ${wrapIfMultiToken(recv)} "${escapeGoString(json)}" "${param}" ${env}`;
|
|
226
227
|
}
|
|
228
|
+
function emitMapEval(recv, body, param, emit) {
|
|
229
|
+
const json = serializeParsedExpr(body);
|
|
230
|
+
if (json === null)
|
|
231
|
+
return null;
|
|
232
|
+
const env = emitEvalEnvArg(body, [param], emit);
|
|
233
|
+
return `bf_map_eval ${wrapIfMultiToken(recv)} "${escapeGoString(json)}" "${param}" ${env}`;
|
|
234
|
+
}
|
|
227
235
|
function stringTolerantEqOperands(l, r) {
|
|
228
236
|
const isStrLit = (x) => /^"(?:[^"\\]|\\.)*"$/.test(x);
|
|
229
237
|
if (isStrLit(l) === isStrLit(r))
|
|
@@ -337,6 +345,9 @@ class CompileState {
|
|
|
337
345
|
currentTypeDefinitions = [];
|
|
338
346
|
contextConsumers = [];
|
|
339
347
|
searchParamsLocals = new Set;
|
|
348
|
+
envSignalReadersByLocal = new Map;
|
|
349
|
+
ssrSeedPlan = { baseScope: [], steps: [] };
|
|
350
|
+
hoistedMemoLocals = new Map;
|
|
340
351
|
loweringMatchers = [];
|
|
341
352
|
nillablePropNames = new Set;
|
|
342
353
|
rootScopeNodes = new Set;
|
|
@@ -977,8 +988,17 @@ function getSignalInitialValueAsGo(ctx, initialValue, propsParams, propFallbackV
|
|
|
977
988
|
}
|
|
978
989
|
|
|
979
990
|
// src/adapter/memo/memo-type.ts
|
|
991
|
+
import { asCallbackMethodCall } from "@barefootjs/jsx";
|
|
992
|
+
function isListFilterMemo(memo) {
|
|
993
|
+
if (!memo.parsed)
|
|
994
|
+
return false;
|
|
995
|
+
const cb = asCallbackMethodCall(memo.parsed);
|
|
996
|
+
return cb !== null && cb.method === "filter";
|
|
997
|
+
}
|
|
980
998
|
function isBooleanMemo(ctx, memo, signals, propsParamMap) {
|
|
981
999
|
const c = memo.computation;
|
|
1000
|
+
if (isListFilterMemo(memo))
|
|
1001
|
+
return false;
|
|
982
1002
|
if (isStringTernaryMemo(ctx, memo.parsed))
|
|
983
1003
|
return false;
|
|
984
1004
|
if (/(!==|===|!=(?!=)|==(?!=))/.test(c))
|
|
@@ -1269,6 +1289,14 @@ function computeObjectMemoInitialValue(ctx, memo) {
|
|
|
1269
1289
|
}`;
|
|
1270
1290
|
}
|
|
1271
1291
|
|
|
1292
|
+
// src/adapter/memo/memo-compute.ts
|
|
1293
|
+
import {
|
|
1294
|
+
asCallbackMethodCall as asCallbackMethodCall2,
|
|
1295
|
+
freeVarsInBody as freeVarsInBody2,
|
|
1296
|
+
materializeGetterCalls,
|
|
1297
|
+
serializeParsedExpr as serializeParsedExpr2
|
|
1298
|
+
} from "@barefootjs/jsx";
|
|
1299
|
+
|
|
1272
1300
|
// src/adapter/memo/template-interp.ts
|
|
1273
1301
|
import ts from "typescript";
|
|
1274
1302
|
function computeTemplateLiteralMemoInitialValue(ctx, memo, propsParams) {
|
|
@@ -1409,8 +1437,49 @@ function propsAccessNameFromParsed(ctx, node) {
|
|
|
1409
1437
|
|
|
1410
1438
|
// src/adapter/memo/memo-compute.ts
|
|
1411
1439
|
var EMPTY_PROP_FALLBACK_VARS2 = new Map;
|
|
1440
|
+
function getterCallName(e) {
|
|
1441
|
+
return e.kind === "call" && e.callee.kind === "identifier" && e.args.length === 0 ? e.callee.name : null;
|
|
1442
|
+
}
|
|
1443
|
+
function propsMemberName(e) {
|
|
1444
|
+
return e.kind === "member" && !e.computed && e.object.kind === "identifier" && e.object.name === "props" ? e.property : null;
|
|
1445
|
+
}
|
|
1446
|
+
function matchFilterArmMemo(ctx, body, signals, propsParams) {
|
|
1447
|
+
const cb = asCallbackMethodCall2(body);
|
|
1448
|
+
if (!cb || cb.method !== "filter")
|
|
1449
|
+
return null;
|
|
1450
|
+
const propName = propsMemberName(cb.object);
|
|
1451
|
+
const param = propName ? propsParams.find((p) => p.name === propName) : undefined;
|
|
1452
|
+
if (!propName || !param)
|
|
1453
|
+
return null;
|
|
1454
|
+
const knownGetterNames = new Set(ctx.state.ssrSeedPlan.steps.filter((s) => s.kind !== "env-reader").map((s) => s.name));
|
|
1455
|
+
const materialized = materializeGetterCalls(cb.arrow.body, knownGetterNames);
|
|
1456
|
+
const predJSON = serializeParsedExpr2(materialized);
|
|
1457
|
+
if (predJSON === null)
|
|
1458
|
+
return null;
|
|
1459
|
+
const paramName = cb.arrow.params[0] ?? "_";
|
|
1460
|
+
const freeVars = freeVarsInBody2(materialized, new Set(cb.arrow.params));
|
|
1461
|
+
return { propName, predJSON, paramName, freeVars };
|
|
1462
|
+
}
|
|
1463
|
+
function filterArmEarlierSiblingRefs(ctx, memo, signals, propsParams) {
|
|
1464
|
+
if (!memo.parsed)
|
|
1465
|
+
return [];
|
|
1466
|
+
const match = matchFilterArmMemo(ctx, memo.parsed, signals, propsParams);
|
|
1467
|
+
if (!match)
|
|
1468
|
+
return [];
|
|
1469
|
+
const memos = ctx.state.currentMemos ?? [];
|
|
1470
|
+
const currentIndex = memos.findIndex((m) => m.name === memo.name);
|
|
1471
|
+
if (currentIndex < 0)
|
|
1472
|
+
return [];
|
|
1473
|
+
const refs = [];
|
|
1474
|
+
for (const name of match.freeVars) {
|
|
1475
|
+
const idx = memos.findIndex((m) => m.name === name);
|
|
1476
|
+
if (idx >= 0 && idx < currentIndex)
|
|
1477
|
+
refs.push(name);
|
|
1478
|
+
}
|
|
1479
|
+
return refs;
|
|
1480
|
+
}
|
|
1412
1481
|
function computeMemoInitialValue(ctx, memo, signals, propsParams, propFallbackVars = EMPTY_PROP_FALLBACK_VARS2, goType) {
|
|
1413
|
-
const resolved = computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFallbackVars);
|
|
1482
|
+
const resolved = computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFallbackVars, new Set([memo.name]));
|
|
1414
1483
|
if (resolved !== null)
|
|
1415
1484
|
return resolved;
|
|
1416
1485
|
if (goType === "bool")
|
|
@@ -1422,15 +1491,79 @@ function computeMemoInitialValue(ctx, memo, signals, propsParams, propFallbackVa
|
|
|
1422
1491
|
}
|
|
1423
1492
|
return "0";
|
|
1424
1493
|
}
|
|
1425
|
-
function memoInitialFromParsedBody(ctx, body, signals, propsParams, propFallbackVars) {
|
|
1494
|
+
function memoInitialFromParsedBody(ctx, body, signals, propsParams, propFallbackVars, currentMemoName, resolving = new Set) {
|
|
1426
1495
|
const propRef = (propName) => {
|
|
1427
1496
|
const hoisted = propFallbackVars.get(propName);
|
|
1428
1497
|
if (hoisted)
|
|
1429
1498
|
return hoisted.varName;
|
|
1430
1499
|
return `in.${capitalizeFieldName(propName)}`;
|
|
1431
1500
|
};
|
|
1432
|
-
const
|
|
1433
|
-
|
|
1501
|
+
const envGetKey = (e) => {
|
|
1502
|
+
if (e.kind !== "call" || e.callee.kind !== "member" || e.callee.computed)
|
|
1503
|
+
return null;
|
|
1504
|
+
const recvName = getterCallName(e.callee.object);
|
|
1505
|
+
if (recvName === null)
|
|
1506
|
+
return null;
|
|
1507
|
+
const reader = ctx.state.envSignalReadersByLocal.get(recvName);
|
|
1508
|
+
if (!reader || !reader.methods.has(e.callee.property))
|
|
1509
|
+
return null;
|
|
1510
|
+
const arg = e.args[0];
|
|
1511
|
+
if (!arg || arg.kind !== "literal" || arg.literalType !== "string")
|
|
1512
|
+
return null;
|
|
1513
|
+
return { key: String(arg.value), fieldName: capitalizeFieldName(reader.canonicalName) };
|
|
1514
|
+
};
|
|
1515
|
+
{
|
|
1516
|
+
const m = envGetKey(body);
|
|
1517
|
+
if (m !== null)
|
|
1518
|
+
return `in.${m.fieldName}.Get(${JSON.stringify(m.key)})`;
|
|
1519
|
+
}
|
|
1520
|
+
if (body.kind === "logical" && (body.op === "??" || body.op === "||") && body.right.kind === "literal" && body.right.literalType === "string") {
|
|
1521
|
+
const m = envGetKey(body.left);
|
|
1522
|
+
if (m !== null) {
|
|
1523
|
+
const def = JSON.stringify(String(body.right.value));
|
|
1524
|
+
return `func() string { if v := in.${m.fieldName}.Get(${JSON.stringify(m.key)}); v != "" { return v }; return ${def} }()`;
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
{
|
|
1528
|
+
const match = matchFilterArmMemo(ctx, body, signals, propsParams);
|
|
1529
|
+
if (match) {
|
|
1530
|
+
const { propName, predJSON, paramName, freeVars } = match;
|
|
1531
|
+
const currentIndex = (ctx.state.currentMemos ?? []).findIndex((m) => m.name === currentMemoName);
|
|
1532
|
+
const envEntries = [];
|
|
1533
|
+
let unresolved = false;
|
|
1534
|
+
for (const name of freeVars) {
|
|
1535
|
+
let goExpr = null;
|
|
1536
|
+
const siblingIndex = (ctx.state.currentMemos ?? []).findIndex((m) => m.name === name);
|
|
1537
|
+
if (siblingIndex >= 0) {
|
|
1538
|
+
const siblingMemo = ctx.state.currentMemos[siblingIndex];
|
|
1539
|
+
const eligible = currentIndex >= 0 && siblingIndex < currentIndex && !resolving.has(siblingMemo.name);
|
|
1540
|
+
if (eligible) {
|
|
1541
|
+
const hoisted = ctx.state.hoistedMemoLocals.get(siblingMemo.name);
|
|
1542
|
+
goExpr = hoisted ?? computeMemoInitialValueOrNull(ctx, siblingMemo, signals, propsParams, propFallbackVars, new Set([...resolving, siblingMemo.name]));
|
|
1543
|
+
}
|
|
1544
|
+
} else {
|
|
1545
|
+
const sig = signals.find((s) => s.getter === name);
|
|
1546
|
+
if (sig) {
|
|
1547
|
+
goExpr = getSignalInitialValueAsGo(ctx, sig.initialValue, propsParams, propFallbackVars);
|
|
1548
|
+
} else {
|
|
1549
|
+
const p = propsParams.find((pp) => pp.name === name);
|
|
1550
|
+
if (p)
|
|
1551
|
+
goExpr = propRef(name);
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
if (goExpr === null) {
|
|
1555
|
+
unresolved = true;
|
|
1556
|
+
break;
|
|
1557
|
+
}
|
|
1558
|
+
envEntries.push(`${JSON.stringify(name)}: ${goExpr}`);
|
|
1559
|
+
}
|
|
1560
|
+
if (!unresolved) {
|
|
1561
|
+
const itemsField = `in.${capitalizeFieldName(propName)}`;
|
|
1562
|
+
const envMap = `map[string]any{${envEntries.join(", ")}}`;
|
|
1563
|
+
return `bf.FilterEval(${itemsField}, "${escapeGoString(predJSON)}", ${JSON.stringify(paramName)}, ${envMap})`;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1434
1567
|
if (body.kind === "binary" && ["===", "!==", "==", "!="].includes(body.op) && body.right.kind === "literal" && body.right.literalType === "string") {
|
|
1435
1568
|
const depName = getterCallName(body.left);
|
|
1436
1569
|
if (depName) {
|
|
@@ -1469,8 +1602,8 @@ function memoInitialFromParsedBody(ctx, body, signals, propsParams, propFallback
|
|
|
1469
1602
|
condGo = getSignalInitialValueAsGo(ctx, condSignal.initialValue, propsParams, propFallbackVars);
|
|
1470
1603
|
} else {
|
|
1471
1604
|
const condMemo = (ctx.state.currentMemos ?? []).find((m) => m.name === condName);
|
|
1472
|
-
if (condMemo) {
|
|
1473
|
-
condGo = computeMemoInitialValueOrNull(ctx, condMemo, signals, propsParams, propFallbackVars);
|
|
1605
|
+
if (condMemo && !resolving.has(condMemo.name)) {
|
|
1606
|
+
condGo = computeMemoInitialValueOrNull(ctx, condMemo, signals, propsParams, propFallbackVars, new Set([...resolving, condMemo.name]));
|
|
1474
1607
|
}
|
|
1475
1608
|
}
|
|
1476
1609
|
if (condGo === "true")
|
|
@@ -1544,17 +1677,17 @@ function memoInitialFromParsedBody(ctx, body, signals, propsParams, propFallback
|
|
|
1544
1677
|
}
|
|
1545
1678
|
return null;
|
|
1546
1679
|
}
|
|
1547
|
-
function computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFallbackVars = EMPTY_PROP_FALLBACK_VARS2) {
|
|
1680
|
+
function computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFallbackVars = EMPTY_PROP_FALLBACK_VARS2, resolving = new Set) {
|
|
1548
1681
|
const computation = memo.computation;
|
|
1549
1682
|
const tmplMemo = computeTemplateLiteralMemoInitialValue(ctx, memo, propsParams);
|
|
1550
1683
|
if (tmplMemo !== null)
|
|
1551
1684
|
return tmplMemo;
|
|
1552
1685
|
if (memo.parsed) {
|
|
1553
|
-
const fromParsed = memoInitialFromParsedBody(ctx, memo.parsed, signals, propsParams, propFallbackVars);
|
|
1686
|
+
const fromParsed = memoInitialFromParsedBody(ctx, memo.parsed, signals, propsParams, propFallbackVars, memo.name, resolving);
|
|
1554
1687
|
if (fromParsed !== null)
|
|
1555
1688
|
return fromParsed;
|
|
1556
1689
|
}
|
|
1557
|
-
const cmpTernary = computeComparisonTernaryGo(ctx, memo.parsed, signals, propsParams, propFallbackVars);
|
|
1690
|
+
const cmpTernary = computeComparisonTernaryGo(ctx, memo.parsed, signals, propsParams, propFallbackVars, resolving);
|
|
1558
1691
|
if (cmpTernary !== null)
|
|
1559
1692
|
return cmpTernary;
|
|
1560
1693
|
const blockReturn = resolveBlockBodyMemoModuleConst(ctx, memo, signals);
|
|
@@ -1566,20 +1699,22 @@ function computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFall
|
|
|
1566
1699
|
return objMemo;
|
|
1567
1700
|
return null;
|
|
1568
1701
|
}
|
|
1569
|
-
function resolveGetterValueAsGo(ctx, name, signals, propsParams, propFallbackVars) {
|
|
1702
|
+
function resolveGetterValueAsGo(ctx, name, signals, propsParams, propFallbackVars, resolving = new Set) {
|
|
1570
1703
|
const signal = signals.find((s) => s.getter === name);
|
|
1571
1704
|
if (signal) {
|
|
1572
1705
|
return getSignalInitialValueAsGo(ctx, signal.initialValue, propsParams, propFallbackVars);
|
|
1573
1706
|
}
|
|
1574
1707
|
const memo = (ctx.state.currentMemos ?? []).find((m) => m.name === name);
|
|
1575
1708
|
if (memo) {
|
|
1709
|
+
if (resolving.has(memo.name))
|
|
1710
|
+
return null;
|
|
1576
1711
|
const stripped = memo.computation.replace(/^\(\)\s*=>\s*/, "");
|
|
1577
1712
|
const fb = ctx.extractPropFallback(stripped);
|
|
1578
1713
|
if (fb && capitalizeFieldName(fb.propName) === capitalizeFieldName(memo.name)) {
|
|
1579
1714
|
const field = `in.${capitalizeFieldName(fb.propName)}`;
|
|
1580
1715
|
return `func() interface{} { v := interface{}(${field}); if v == nil || v == "" { return ${fb.goFallback} }; return v }()`;
|
|
1581
1716
|
}
|
|
1582
|
-
return computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFallbackVars);
|
|
1717
|
+
return computeMemoInitialValueOrNull(ctx, memo, signals, propsParams, propFallbackVars, new Set([...resolving, memo.name]));
|
|
1583
1718
|
}
|
|
1584
1719
|
const param = propsParams.find((p) => p.name === name);
|
|
1585
1720
|
if (param) {
|
|
@@ -1588,7 +1723,7 @@ function resolveGetterValueAsGo(ctx, name, signals, propsParams, propFallbackVar
|
|
|
1588
1723
|
}
|
|
1589
1724
|
return null;
|
|
1590
1725
|
}
|
|
1591
|
-
function computeComparisonTernaryGo(ctx, parsed, signals, propsParams, propFallbackVars) {
|
|
1726
|
+
function computeComparisonTernaryGo(ctx, parsed, signals, propsParams, propFallbackVars, resolving = new Set) {
|
|
1592
1727
|
if (!parsed || parsed.kind !== "conditional")
|
|
1593
1728
|
return null;
|
|
1594
1729
|
const cond = parsed.test;
|
|
@@ -1613,16 +1748,16 @@ function computeComparisonTernaryGo(ctx, parsed, signals, propsParams, propFallb
|
|
|
1613
1748
|
const f = branch(parsed.alternate);
|
|
1614
1749
|
if (t === null || f === null)
|
|
1615
1750
|
return null;
|
|
1616
|
-
const condGo = resolveComparisonOperandGo(ctx, cond.left, signals, propsParams, propFallbackVars);
|
|
1751
|
+
const condGo = resolveComparisonOperandGo(ctx, cond.left, signals, propsParams, propFallbackVars, resolving);
|
|
1617
1752
|
if (condGo === null)
|
|
1618
1753
|
return null;
|
|
1619
1754
|
const eqBranch = isEq ? t : f;
|
|
1620
1755
|
const neBranch = isEq ? f : t;
|
|
1621
1756
|
return `func() string { if ${condGo} == ${JSON.stringify(cond.right.value)} { return ${eqBranch} }; return ${neBranch} }()`;
|
|
1622
1757
|
}
|
|
1623
|
-
function resolveComparisonOperandGo(ctx, node, signals, propsParams, propFallbackVars) {
|
|
1758
|
+
function resolveComparisonOperandGo(ctx, node, signals, propsParams, propFallbackVars, resolving = new Set) {
|
|
1624
1759
|
if (node.kind === "call" && node.callee.kind === "identifier" && node.args.length === 0) {
|
|
1625
|
-
return resolveGetterValueAsGo(ctx, node.callee.name, signals, propsParams, propFallbackVars);
|
|
1760
|
+
return resolveGetterValueAsGo(ctx, node.callee.name, signals, propsParams, propFallbackVars, resolving);
|
|
1626
1761
|
}
|
|
1627
1762
|
if (node.kind === "logical" && node.op === "??" && node.right.kind === "literal" && node.right.literalType === "string") {
|
|
1628
1763
|
const propName = propsAccessNameFromParsed2(ctx, node.left);
|
|
@@ -2001,7 +2136,18 @@ class GoTemplateAdapter extends BaseAdapter {
|
|
|
2001
2136
|
this.state.currentMemos = ir.metadata.memos ?? [];
|
|
2002
2137
|
this.state.currentTypeDefinitions = ir.metadata.typeDefinitions ?? [];
|
|
2003
2138
|
this.state.contextConsumers = collectContextConsumers(ir.metadata);
|
|
2004
|
-
this.state.
|
|
2139
|
+
this.state.ssrSeedPlan = ir.metadata.ssrSeedPlan ?? computeSsrSeedPlan(ir.metadata);
|
|
2140
|
+
this.state.envSignalReadersByLocal = new Map;
|
|
2141
|
+
this.state.searchParamsLocals = new Set;
|
|
2142
|
+
for (const step of this.state.ssrSeedPlan.steps) {
|
|
2143
|
+
if (step.kind !== "env-reader")
|
|
2144
|
+
continue;
|
|
2145
|
+
const reader = envSignalReaderFor(step.reader.key);
|
|
2146
|
+
if (reader)
|
|
2147
|
+
this.state.envSignalReadersByLocal.set(step.name, reader);
|
|
2148
|
+
if (step.reader.key === "search")
|
|
2149
|
+
this.state.searchParamsLocals.add(step.name);
|
|
2150
|
+
}
|
|
2005
2151
|
this.state.loweringMatchers = prepareLoweringMatchers(ir.metadata);
|
|
2006
2152
|
augmentInheritedPropAccesses(ir);
|
|
2007
2153
|
}
|
|
@@ -2505,6 +2651,28 @@ ${goFields.join(`
|
|
|
2505
2651
|
if (propFallbackVars.size > 0)
|
|
2506
2652
|
lines.push("");
|
|
2507
2653
|
this.emitDynamicBodyWrappers(lines, ir, componentName, dynamicWithBody, propFallbackVars, emittedWrapperVars);
|
|
2654
|
+
const memoPropsParamMap = new Map(ir.metadata.propsParams.map((p) => [p.name, p]));
|
|
2655
|
+
this.state.hoistedMemoLocals = new Map;
|
|
2656
|
+
const hoistNames = new Set;
|
|
2657
|
+
for (const memo of ir.metadata.memos) {
|
|
2658
|
+
for (const name of filterArmEarlierSiblingRefs(this.emitCtx, memo, ir.metadata.signals, ir.metadata.propsParams)) {
|
|
2659
|
+
hoistNames.add(name);
|
|
2660
|
+
}
|
|
2661
|
+
}
|
|
2662
|
+
if (hoistNames.size > 0) {
|
|
2663
|
+
for (const memo of ir.metadata.memos) {
|
|
2664
|
+
if (!hoistNames.has(memo.name))
|
|
2665
|
+
continue;
|
|
2666
|
+
const goType = this.inferMemoType(memo, ir.metadata.signals, memoPropsParamMap);
|
|
2667
|
+
const value = computeMemoInitialValue(this.emitCtx, memo, ir.metadata.signals, ir.metadata.propsParams, propFallbackVars, goType);
|
|
2668
|
+
let localName = `memo${capitalizeFieldName(memo.name)}`;
|
|
2669
|
+
while (GO_KEYWORDS.has(localName))
|
|
2670
|
+
localName += "_";
|
|
2671
|
+
lines.push(` var ${localName} ${goType} = ${value}`);
|
|
2672
|
+
this.state.hoistedMemoLocals.set(memo.name, localName);
|
|
2673
|
+
}
|
|
2674
|
+
lines.push("");
|
|
2675
|
+
}
|
|
2508
2676
|
lines.push(` return ${propsTypeName}{`);
|
|
2509
2677
|
lines.push("\t\tScopeID: scopeID,");
|
|
2510
2678
|
lines.push("\t\tBfParent: in.BfParent,");
|
|
@@ -2578,11 +2746,15 @@ ${goFields.join(`
|
|
|
2578
2746
|
continue;
|
|
2579
2747
|
lines.push(` ${nested.name}s: ${varName},`);
|
|
2580
2748
|
}
|
|
2581
|
-
const memoPropsParamMap = new Map(ir.metadata.propsParams.map((p) => [p.name, p]));
|
|
2582
2749
|
for (const memo of ir.metadata.memos) {
|
|
2583
2750
|
const fieldName = capitalizeFieldName(memo.name);
|
|
2584
2751
|
if (propFieldNames.has(fieldName))
|
|
2585
2752
|
continue;
|
|
2753
|
+
const hoistedLocal = this.state.hoistedMemoLocals.get(memo.name);
|
|
2754
|
+
if (hoistedLocal) {
|
|
2755
|
+
lines.push(` ${fieldName}: ${hoistedLocal},`);
|
|
2756
|
+
continue;
|
|
2757
|
+
}
|
|
2586
2758
|
const goType = this.inferMemoType(memo, ir.metadata.signals, memoPropsParamMap);
|
|
2587
2759
|
const memoValue = computeMemoInitialValue(this.emitCtx, memo, ir.metadata.signals, ir.metadata.propsParams, propFallbackVars, goType);
|
|
2588
2760
|
lines.push(` ${fieldName}: ${memoValue},`);
|
|
@@ -3271,12 +3443,14 @@ ${goFields.join(`
|
|
|
3271
3443
|
}
|
|
3272
3444
|
const memo = memos.find((m) => m.name === getterName);
|
|
3273
3445
|
if (memo) {
|
|
3274
|
-
return computeMemoInitialValueOrNull(this.emitCtx, memo, signals, propsParams);
|
|
3446
|
+
return computeMemoInitialValueOrNull(this.emitCtx, memo, signals, propsParams, undefined, new Set([memo.name]));
|
|
3275
3447
|
}
|
|
3276
3448
|
}
|
|
3277
3449
|
return null;
|
|
3278
3450
|
}
|
|
3279
3451
|
inferMemoType(memo, signals, propsParamMap) {
|
|
3452
|
+
if (isListFilterMemo(memo))
|
|
3453
|
+
return "[]any";
|
|
3280
3454
|
if (memo.bodyIsTemplateLiteral)
|
|
3281
3455
|
return "string";
|
|
3282
3456
|
if (memo.computation.includes("*") || memo.computation.includes("/") || memo.computation.includes("+") || memo.computation.includes("-")) {
|
|
@@ -3798,7 +3972,7 @@ ${goFields.join(`
|
|
|
3798
3972
|
"some"
|
|
3799
3973
|
]);
|
|
3800
3974
|
higherOrderShapeOf(node) {
|
|
3801
|
-
const cb =
|
|
3975
|
+
const cb = asCallbackMethodCall3(node);
|
|
3802
3976
|
if (!cb)
|
|
3803
3977
|
return null;
|
|
3804
3978
|
if (!GoTemplateAdapter.PREDICATE_METHODS.has(cb.method))
|
|
@@ -3873,6 +4047,12 @@ ${goFields.join(`
|
|
|
3873
4047
|
return evalForm;
|
|
3874
4048
|
return this.pushCallbackBF101(method, true);
|
|
3875
4049
|
}
|
|
4050
|
+
if (method === "map") {
|
|
4051
|
+
const evalForm = emitMapEval(recv, body, params[0] ?? "_", emit);
|
|
4052
|
+
if (evalForm !== null)
|
|
4053
|
+
return evalForm;
|
|
4054
|
+
return this.pushCallbackBF101(method, true);
|
|
4055
|
+
}
|
|
3876
4056
|
return this.pushCallbackBF101(method, true);
|
|
3877
4057
|
}
|
|
3878
4058
|
arrayMethod(method, object, args, emit) {
|
|
@@ -4226,6 +4406,9 @@ ${goFields.join(`
|
|
|
4226
4406
|
if (expr.callee.kind === "identifier" && expr.args.length === 0) {
|
|
4227
4407
|
return `$.${capitalizeFieldName(expr.callee.name)}`;
|
|
4228
4408
|
}
|
|
4409
|
+
if (asCallbackMethodCall3(expr) !== null) {
|
|
4410
|
+
return this.refuseFilterExprNode(expr);
|
|
4411
|
+
}
|
|
4229
4412
|
const result = this.renderFilterExpr(expr.callee, param, localVarMap);
|
|
4230
4413
|
if (this.filterExprUnsupported)
|
|
4231
4414
|
return "false";
|
|
@@ -4290,21 +4473,23 @@ ${goFields.join(`
|
|
|
4290
4473
|
}
|
|
4291
4474
|
return `or (${left}) (${right})`;
|
|
4292
4475
|
}
|
|
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
|
-
}
|
|
4476
|
+
default:
|
|
4477
|
+
return this.refuseFilterExprNode(expr);
|
|
4306
4478
|
}
|
|
4307
4479
|
}
|
|
4480
|
+
refuseFilterExprNode(expr) {
|
|
4481
|
+
this.filterExprUnsupported = true;
|
|
4482
|
+
this.state.errors.push({
|
|
4483
|
+
code: "BF101",
|
|
4484
|
+
severity: "error",
|
|
4485
|
+
message: `Filter predicate contains an expression that cannot be lowered to a Go template action: ${exprToString(expr)}`,
|
|
4486
|
+
loc: this.makeLoc(),
|
|
4487
|
+
suggestion: {
|
|
4488
|
+
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)"
|
|
4489
|
+
}
|
|
4490
|
+
});
|
|
4491
|
+
return "false";
|
|
4492
|
+
}
|
|
4308
4493
|
isGoFunctionCall(expr) {
|
|
4309
4494
|
switch (expr.kind) {
|
|
4310
4495
|
case "binary":
|
|
@@ -4558,7 +4743,7 @@ ${goFields.join(`
|
|
|
4558
4743
|
});
|
|
4559
4744
|
return plain("false");
|
|
4560
4745
|
}
|
|
4561
|
-
if (
|
|
4746
|
+
if (asCallbackMethodCall3(expr)) {
|
|
4562
4747
|
const rendered = this.renderParsedExpr(expr);
|
|
4563
4748
|
const split = this.splitPreamble(rendered);
|
|
4564
4749
|
if (split)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/go-template",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.1",
|
|
4
4
|
"description": "Go html/template adapter for BarefootJS - generates Go template files from IR",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"directory": "packages/adapter-go-template"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@barefootjs/shared": "0.17.
|
|
52
|
+
"@barefootjs/shared": "0.17.1"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"@barefootjs/jsx": ">=0.2.0",
|
|
@@ -57,6 +57,6 @@
|
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@barefootjs/adapter-tests": "0.1.0",
|
|
60
|
-
"@barefootjs/jsx": "0.17.
|
|
60
|
+
"@barefootjs/jsx": "0.17.1"
|
|
61
61
|
}
|
|
62
62
|
}
|