@barefootjs/go-template 0.29.0 → 0.30.2
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 +224 -0
- package/dist/adapter/go-template-adapter.d.ts.map +1 -1
- package/dist/adapter/index.js +294 -8
- package/dist/adapter/memo/memo-compute.d.ts +36 -0
- package/dist/adapter/memo/memo-compute.d.ts.map +1 -1
- package/dist/adapter/type/type-codegen.d.ts +21 -1
- package/dist/adapter/type/type-codegen.d.ts.map +1 -1
- package/dist/adapter/value/value-lowering.d.ts +1 -1
- package/dist/adapter/value/value-lowering.d.ts.map +1 -1
- package/dist/build.js +294 -8
- package/dist/conformance-pins.d.ts.map +1 -1
- package/dist/index.js +300 -10
- package/dist/render-divergences.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/go-template-adapter.test.ts +626 -6
- package/src/adapter/go-template-adapter.ts +597 -13
- package/src/adapter/memo/memo-compute.ts +125 -0
- package/src/adapter/type/type-codegen.ts +44 -1
- package/src/adapter/value/value-lowering.ts +6 -1
- package/src/conformance-pins.ts +0 -5
- package/src/render-divergences.ts +24 -9
package/dist/index.js
CHANGED
|
@@ -972,7 +972,26 @@ function renderLoweringNode(ctx, node) {
|
|
|
972
972
|
}
|
|
973
973
|
|
|
974
974
|
// src/adapter/type/type-codegen.ts
|
|
975
|
-
function
|
|
975
|
+
function collapseLiteralUnion(typeInfo) {
|
|
976
|
+
if (typeInfo.kind !== "union" || !typeInfo.unionTypes || typeInfo.unionTypes.length === 0) {
|
|
977
|
+
return typeInfo;
|
|
978
|
+
}
|
|
979
|
+
const familyOf = (m) => {
|
|
980
|
+
if (m.kind !== "primitive")
|
|
981
|
+
return null;
|
|
982
|
+
return m.primitive === "string" || m.primitive === "number" || m.primitive === "boolean" ? m.primitive : null;
|
|
983
|
+
};
|
|
984
|
+
const first = familyOf(typeInfo.unionTypes[0]);
|
|
985
|
+
if (!first)
|
|
986
|
+
return typeInfo;
|
|
987
|
+
for (const m of typeInfo.unionTypes) {
|
|
988
|
+
if (familyOf(m) !== first)
|
|
989
|
+
return typeInfo;
|
|
990
|
+
}
|
|
991
|
+
return { kind: "primitive", raw: typeInfo.raw, primitive: first };
|
|
992
|
+
}
|
|
993
|
+
function typeInfoToGo(ctx, _typeInfo, defaultValue) {
|
|
994
|
+
const typeInfo = collapseLiteralUnion(_typeInfo);
|
|
976
995
|
switch (typeInfo.kind) {
|
|
977
996
|
case "primitive":
|
|
978
997
|
switch (typeInfo.primitive) {
|
|
@@ -1142,7 +1161,8 @@ function nillableAwarePropRef(ctx, propName, expectedType) {
|
|
|
1142
1161
|
}
|
|
1143
1162
|
return fieldRef;
|
|
1144
1163
|
}
|
|
1145
|
-
function convertInitialValue(ctx, value,
|
|
1164
|
+
function convertInitialValue(ctx, value, _typeInfo, propsParams, preParsed) {
|
|
1165
|
+
const typeInfo = collapseLiteralUnion(_typeInfo);
|
|
1146
1166
|
const propRef = (propName2) => nillableAwarePropRef(ctx, propName2, typeInfo);
|
|
1147
1167
|
if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(value)) {
|
|
1148
1168
|
if (propsParams?.some((p) => p.name === value)) {
|
|
@@ -2090,6 +2110,78 @@ function propsAccessNameFromParsed2(ctx, node) {
|
|
|
2090
2110
|
return null;
|
|
2091
2111
|
return node.property;
|
|
2092
2112
|
}
|
|
2113
|
+
function collectPropsReadByCtorInit(body, propsObjectName, propNames) {
|
|
2114
|
+
const found = new Set;
|
|
2115
|
+
const visit = (e, bound) => {
|
|
2116
|
+
switch (e.kind) {
|
|
2117
|
+
case "identifier":
|
|
2118
|
+
if (!propsObjectName && propNames.has(e.name) && !bound.has(e.name))
|
|
2119
|
+
found.add(e.name);
|
|
2120
|
+
return;
|
|
2121
|
+
case "member":
|
|
2122
|
+
if (propsObjectName && !e.computed && e.object.kind === "identifier" && e.object.name === propsObjectName) {
|
|
2123
|
+
found.add(e.property);
|
|
2124
|
+
return;
|
|
2125
|
+
}
|
|
2126
|
+
visit(e.object, bound);
|
|
2127
|
+
return;
|
|
2128
|
+
case "index-access":
|
|
2129
|
+
visit(e.object, bound);
|
|
2130
|
+
visit(e.index, bound);
|
|
2131
|
+
return;
|
|
2132
|
+
case "binary":
|
|
2133
|
+
case "logical":
|
|
2134
|
+
visit(e.left, bound);
|
|
2135
|
+
visit(e.right, bound);
|
|
2136
|
+
return;
|
|
2137
|
+
case "unary":
|
|
2138
|
+
visit(e.argument, bound);
|
|
2139
|
+
return;
|
|
2140
|
+
case "conditional":
|
|
2141
|
+
visit(e.test, bound);
|
|
2142
|
+
visit(e.consequent, bound);
|
|
2143
|
+
visit(e.alternate, bound);
|
|
2144
|
+
return;
|
|
2145
|
+
case "call":
|
|
2146
|
+
visit(e.callee, bound);
|
|
2147
|
+
e.args.forEach((a) => visit(a, bound));
|
|
2148
|
+
return;
|
|
2149
|
+
case "template-literal":
|
|
2150
|
+
for (const p of e.parts)
|
|
2151
|
+
if (p.type === "expression")
|
|
2152
|
+
visit(p.expr, bound);
|
|
2153
|
+
return;
|
|
2154
|
+
case "array-literal":
|
|
2155
|
+
e.elements.forEach((el) => visit(el, bound));
|
|
2156
|
+
return;
|
|
2157
|
+
case "object-literal":
|
|
2158
|
+
for (const p of e.properties)
|
|
2159
|
+
visit(p.value, bound);
|
|
2160
|
+
return;
|
|
2161
|
+
case "array-method":
|
|
2162
|
+
visit(e.object, bound);
|
|
2163
|
+
e.args.forEach((a) => visit(a, bound));
|
|
2164
|
+
if (e.method === "flat" && e.depthExpr)
|
|
2165
|
+
visit(e.depthExpr, bound);
|
|
2166
|
+
return;
|
|
2167
|
+
case "arrow": {
|
|
2168
|
+
const inner = e.params.length === 0 ? bound : new Set([...bound, ...e.params]);
|
|
2169
|
+
visit(e.body, inner);
|
|
2170
|
+
return;
|
|
2171
|
+
}
|
|
2172
|
+
case "literal":
|
|
2173
|
+
case "regex":
|
|
2174
|
+
case "unsupported":
|
|
2175
|
+
return;
|
|
2176
|
+
default: {
|
|
2177
|
+
const _exhaustive = e;
|
|
2178
|
+
return;
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
};
|
|
2182
|
+
visit(body, new Set);
|
|
2183
|
+
return found;
|
|
2184
|
+
}
|
|
2093
2185
|
|
|
2094
2186
|
// src/adapter/spread/spread-codegen.ts
|
|
2095
2187
|
import ts2 from "typescript";
|
|
@@ -2691,6 +2783,7 @@ class GoTemplateAdapter extends BaseAdapter {
|
|
|
2691
2783
|
this.state.pendingChildrenDefines = [];
|
|
2692
2784
|
this.primeCompileState(ir);
|
|
2693
2785
|
this.state.stringValueNames = collectStringValueNames(ir);
|
|
2786
|
+
this.recordDerivedFieldDeps(ir, new Set((ir.metadata.propsParams ?? []).map((p) => p.name)));
|
|
2694
2787
|
if (!options?.siblingTemplatesRegistered) {
|
|
2695
2788
|
this.checkImportedLoopChildComponents(ir);
|
|
2696
2789
|
}
|
|
@@ -2827,15 +2920,50 @@ ${scriptRegistrations}${templateBody}
|
|
|
2827
2920
|
return `{{if .Scripts}}${registrations.join("")}{{end}}
|
|
2828
2921
|
`;
|
|
2829
2922
|
}
|
|
2923
|
+
childDerivedFieldDeps = new Map;
|
|
2924
|
+
childPropFieldNames = new Map;
|
|
2925
|
+
childRepropsReady = new Map;
|
|
2926
|
+
repropsOwner = new Map;
|
|
2927
|
+
recordDerivedFieldDeps(ir, paramNames) {
|
|
2928
|
+
const name = ir.metadata.componentName;
|
|
2929
|
+
if (!name)
|
|
2930
|
+
return;
|
|
2931
|
+
const sourceOf = new Map((ir.metadata.propsParams ?? []).map((p) => [p.name, p.sourceName ?? p.name]));
|
|
2932
|
+
const canonical = (local) => capitalizeFieldName(sourceOf.get(local) ?? local);
|
|
2933
|
+
const propFieldNames = new Set([...paramNames].map(canonical));
|
|
2934
|
+
const fieldNames = new Map;
|
|
2935
|
+
for (const p of ir.metadata.propsParams ?? []) {
|
|
2936
|
+
fieldNames.set(p.sourceName ?? p.name, capitalizeFieldName(p.name));
|
|
2937
|
+
}
|
|
2938
|
+
this.childPropFieldNames.set(name, fieldNames);
|
|
2939
|
+
const deps = new Map;
|
|
2940
|
+
const ctorInits = [
|
|
2941
|
+
...(ir.metadata.memos ?? []).map((m) => ({ field: m.name, init: m.parsed })),
|
|
2942
|
+
...(ir.metadata.signals ?? []).map((s) => ({ field: s.getter, init: s.parsed }))
|
|
2943
|
+
];
|
|
2944
|
+
for (const { field, init } of ctorInits) {
|
|
2945
|
+
if (propFieldNames.has(capitalizeFieldName(field)))
|
|
2946
|
+
continue;
|
|
2947
|
+
if (!init)
|
|
2948
|
+
continue;
|
|
2949
|
+
const read = collectPropsReadByCtorInit(init, ir.metadata.propsObjectName ?? null, paramNames);
|
|
2950
|
+
if (read.size === 0)
|
|
2951
|
+
continue;
|
|
2952
|
+
deps.set(field, new Set([...read].map(canonical)));
|
|
2953
|
+
}
|
|
2954
|
+
if (deps.size > 0)
|
|
2955
|
+
this.childDerivedFieldDeps.set(name, deps);
|
|
2956
|
+
}
|
|
2830
2957
|
registerChildComponentShape(ir) {
|
|
2831
2958
|
const name = ir.metadata.componentName;
|
|
2832
2959
|
if (!name)
|
|
2833
2960
|
return;
|
|
2834
|
-
const paramNames = new Set((ir.metadata.propsParams ?? []).map((p) => p.name));
|
|
2961
|
+
const paramNames = new Set((ir.metadata.propsParams ?? []).map((p) => p.sourceName ?? p.name));
|
|
2835
2962
|
const restPropsName = ir.metadata.restPropsName ?? null;
|
|
2836
2963
|
const restBagField = restPropsName ? capitalizeFieldName(restPropsName) : null;
|
|
2837
|
-
const mapTypedParamNames = new Set((ir.metadata.propsParams ?? []).filter((p) => p.optional && (p.type.kind === "object" || p.type.kind === "interface" && !!p.type.raw)).map((p) => p.name));
|
|
2964
|
+
const mapTypedParamNames = new Set((ir.metadata.propsParams ?? []).filter((p) => p.optional && (p.type.kind === "object" || p.type.kind === "interface" && !!p.type.raw)).map((p) => p.sourceName ?? p.name));
|
|
2838
2965
|
this.childComponentShapes.set(name, { paramNames, restBagField, mapTypedParamNames });
|
|
2966
|
+
this.recordDerivedFieldDeps(ir, new Set((ir.metadata.propsParams ?? []).map((p) => p.name)));
|
|
2839
2967
|
this.childContextConsumers.set(name, collectContextConsumers(ir.metadata));
|
|
2840
2968
|
}
|
|
2841
2969
|
contextFieldName(c) {
|
|
@@ -2904,8 +3032,86 @@ ${scriptRegistrations}${templateBody}
|
|
|
2904
3032
|
this.state.needsStringsImport = false;
|
|
2905
3033
|
this.generatePropsStruct(lines, ir, componentName, nestedComponents, propTypeOverrides, spreadSlots);
|
|
2906
3034
|
this.generateNewPropsFunction(lines, ir, componentName, nestedComponents, spreadSlots, propTypeOverrides);
|
|
3035
|
+
this.recordRepropsSpec(ir, componentName, nestedComponents, spreadSlots);
|
|
3036
|
+
this.emitOwnedReprops(lines, componentName);
|
|
2907
3037
|
return this.composeFileHeader(lines);
|
|
2908
3038
|
}
|
|
3039
|
+
recordRepropsSpec(ir, componentName, nestedComponents, spreadSlots) {
|
|
3040
|
+
if (!this.childDerivedFieldDeps.has(componentName))
|
|
3041
|
+
return;
|
|
3042
|
+
const nestedArrayFields = new Set(nestedComponents.map((n) => `${n.name}s`));
|
|
3043
|
+
const params = (ir.metadata.propsParams ?? []).filter((p) => !nestedArrayFields.has(capitalizeFieldName(p.name)));
|
|
3044
|
+
const takenInput = new Set((ir.metadata.propsParams ?? []).map((p) => capitalizeFieldName(p.name)));
|
|
3045
|
+
const eligible = nestedComponents.every((n) => n.isDynamic && !n.isPropDerived) && spreadSlots.length === 0 && !ir.metadata.restPropsName && this.nonCollidingContextConsumers(takenInput).length === 0;
|
|
3046
|
+
if (!eligible)
|
|
3047
|
+
return;
|
|
3048
|
+
this.childRepropsReady.set(componentName, {
|
|
3049
|
+
params: params.map((p) => capitalizeFieldName(p.name)),
|
|
3050
|
+
usesSearchParams: this.usesSearchParams(ir)
|
|
3051
|
+
});
|
|
3052
|
+
}
|
|
3053
|
+
emitOwnedReprops(lines, owner) {
|
|
3054
|
+
for (const [childName, ownerName] of this.repropsOwner) {
|
|
3055
|
+
if (ownerName !== owner)
|
|
3056
|
+
continue;
|
|
3057
|
+
const spec = this.childRepropsReady.get(childName);
|
|
3058
|
+
if (!spec)
|
|
3059
|
+
continue;
|
|
3060
|
+
this.emitRepropsRegistration(lines, childName, spec);
|
|
3061
|
+
}
|
|
3062
|
+
}
|
|
3063
|
+
emitRepropsRegistration(lines, componentName, spec) {
|
|
3064
|
+
const { params, usesSearchParams } = spec;
|
|
3065
|
+
const inputTypeName = `${componentName}Input`;
|
|
3066
|
+
const q = JSON.stringify(componentName);
|
|
3067
|
+
lines.push(`// ${componentName} computes at least one field from an input prop when its`);
|
|
3068
|
+
lines.push("// props are constructed, so a per-row override inside a composite loop row");
|
|
3069
|
+
lines.push("// cannot be applied by patching fields — the derived field would keep the");
|
|
3070
|
+
lines.push("// shared instance's one-shot value on every row (#2448). This rebuilder");
|
|
3071
|
+
lines.push(`// re-runs New${componentName}Props with the row's overrides folded into the`);
|
|
3072
|
+
lines.push("// Input; the parent calls it through bf_reprops.");
|
|
3073
|
+
lines.push("func init() {");
|
|
3074
|
+
lines.push(` bf.RegisterReprops(${q}, func(base interface{}, kv ...interface{}) (interface{}, error) {`);
|
|
3075
|
+
lines.push(` b, ok := base.(${componentName}Props)`);
|
|
3076
|
+
lines.push("\t\tif !ok {");
|
|
3077
|
+
lines.push(` return nil, bf.RepropsTypeError(${q}, base)`);
|
|
3078
|
+
lines.push("\t\t}");
|
|
3079
|
+
lines.push(` in := ${inputTypeName}{`);
|
|
3080
|
+
lines.push("\t\t\tScopeID: b.ScopeID,");
|
|
3081
|
+
lines.push("\t\t\tBfParent: b.BfParent,");
|
|
3082
|
+
lines.push("\t\t\tBfMount: b.BfMount,");
|
|
3083
|
+
if (usesSearchParams)
|
|
3084
|
+
lines.push("\t\t\tSearchParams: b.SearchParams,");
|
|
3085
|
+
for (const field of params) {
|
|
3086
|
+
lines.push(` ${field}: b.${field},`);
|
|
3087
|
+
}
|
|
3088
|
+
lines.push("\t\t}");
|
|
3089
|
+
lines.push("\t\tfor i := 0; i < len(kv); i += 2 {");
|
|
3090
|
+
lines.push("\t\t\tname, _ := kv[i].(string)");
|
|
3091
|
+
lines.push("\t\t\tvar err error");
|
|
3092
|
+
lines.push("\t\t\tswitch name {");
|
|
3093
|
+
for (const field of params) {
|
|
3094
|
+
lines.push(` case ${JSON.stringify(field)}:`);
|
|
3095
|
+
lines.push(` err = bf.RepropsAssign(${q}, ${JSON.stringify(field)}, &in.${field}, kv[i+1])`);
|
|
3096
|
+
}
|
|
3097
|
+
lines.push("\t\t\tdefault:");
|
|
3098
|
+
lines.push(` err = bf.RepropsUnknownFieldError(${q}, name)`);
|
|
3099
|
+
lines.push("\t\t\t}");
|
|
3100
|
+
lines.push("\t\t\tif err != nil {");
|
|
3101
|
+
lines.push("\t\t\t\treturn nil, err");
|
|
3102
|
+
lines.push("\t\t\t}");
|
|
3103
|
+
lines.push("\t\t}");
|
|
3104
|
+
lines.push(` p := New${componentName}Props(in)`);
|
|
3105
|
+
lines.push("\t\t// Props-only state, absent from Input and therefore not rebuilt.");
|
|
3106
|
+
lines.push("\t\tp.Scripts = b.Scripts");
|
|
3107
|
+
lines.push("\t\tp.BfIsRoot = b.BfIsRoot");
|
|
3108
|
+
lines.push("\t\tp.BfIsChild = b.BfIsChild");
|
|
3109
|
+
lines.push("\t\tp.BfDataKey = b.BfDataKey");
|
|
3110
|
+
lines.push("\t\treturn p, nil");
|
|
3111
|
+
lines.push("\t})");
|
|
3112
|
+
lines.push("}");
|
|
3113
|
+
lines.push("");
|
|
3114
|
+
}
|
|
2909
3115
|
typeDefinitionToGo(td) {
|
|
2910
3116
|
if (td.definition.match(/^type \w+ = ('[^']*'(\s*\|\s*'[^']*')*)/)) {
|
|
2911
3117
|
return `// ${td.name} is a string type.
|
|
@@ -3389,7 +3595,8 @@ ${goFields.join(`
|
|
|
3389
3595
|
}
|
|
3390
3596
|
if (jsxName.includes("-"))
|
|
3391
3597
|
return;
|
|
3392
|
-
|
|
3598
|
+
const fieldName = this.childPropFieldNames.get(child.name)?.get(jsxName) ?? capitalizeFieldName(jsxName);
|
|
3599
|
+
lines.push(` ${fieldName}: ${goValue},`);
|
|
3393
3600
|
};
|
|
3394
3601
|
for (const prop of child.props) {
|
|
3395
3602
|
switch (prop.value.kind) {
|
|
@@ -5373,6 +5580,78 @@ ${goFields.join(`
|
|
|
5373
5580
|
isLoopShadowedName(name) {
|
|
5374
5581
|
return this.loopParamStack.length > 0 && this.loopParamStack[this.loopParamStack.length - 1] === name || this.loopVarRefCount.has(name) || this.isOuterLoopParam(name) || this.loopBindingStack.some((bindings) => bindings.has(name));
|
|
5375
5582
|
}
|
|
5583
|
+
loopRowChildPropOverrides(comp) {
|
|
5584
|
+
const childShape = this.childComponentShapes.get(comp.name);
|
|
5585
|
+
const args = [];
|
|
5586
|
+
let needsRebuild = false;
|
|
5587
|
+
for (const prop of comp.props) {
|
|
5588
|
+
if (prop.clientOnly)
|
|
5589
|
+
continue;
|
|
5590
|
+
if (prop.name === "key" || prop.name === "children")
|
|
5591
|
+
continue;
|
|
5592
|
+
if (prop.name.startsWith("on") && prop.name.length > 2)
|
|
5593
|
+
continue;
|
|
5594
|
+
if (prop.name.includes("-"))
|
|
5595
|
+
continue;
|
|
5596
|
+
if (childShape?.restBagField && !childShape.paramNames.has(prop.name))
|
|
5597
|
+
continue;
|
|
5598
|
+
if (prop.value.kind !== "expression")
|
|
5599
|
+
continue;
|
|
5600
|
+
const free = prop.freeIdentifiers;
|
|
5601
|
+
if (!free || ![...free].some((name) => this.isLoopShadowedName(name)))
|
|
5602
|
+
continue;
|
|
5603
|
+
{
|
|
5604
|
+
const derived = this.childDerivedFieldDeps.get(comp.name);
|
|
5605
|
+
const overriddenField = capitalizeFieldName(prop.name);
|
|
5606
|
+
const staleField = derived ? [...derived].find(([, deps]) => deps.has(overriddenField))?.[0] : undefined;
|
|
5607
|
+
if (staleField && !this.childRepropsReady.has(comp.name)) {
|
|
5608
|
+
this.state.errors.push({
|
|
5609
|
+
code: "BF101",
|
|
5610
|
+
severity: "error",
|
|
5611
|
+
message: `Prop '${prop.name}' on <${comp.name}> nested inside a dynamic loop row is overridden per row, but <${comp.name}>'s '${staleField}' field is computed from '${prop.name}' when the shared instance is first constructed and won't recompute per row — it would keep the first row's value on every row.`,
|
|
5612
|
+
loc: prop.loc,
|
|
5613
|
+
suggestion: {
|
|
5614
|
+
message: `Mark this loop position '@client' to render <${comp.name}> client-side, or compute '${staleField}' in the parent and pass it to <${comp.name}> as a plain prop instead of deriving it inside <${comp.name}>.`
|
|
5615
|
+
}
|
|
5616
|
+
});
|
|
5617
|
+
continue;
|
|
5618
|
+
}
|
|
5619
|
+
if (staleField) {
|
|
5620
|
+
needsRebuild = true;
|
|
5621
|
+
if (!this.repropsOwner.has(comp.name)) {
|
|
5622
|
+
this.repropsOwner.set(comp.name, this.state.componentName);
|
|
5623
|
+
}
|
|
5624
|
+
}
|
|
5625
|
+
}
|
|
5626
|
+
const exprOut = {};
|
|
5627
|
+
const errorCountBefore = this.state.errors.length;
|
|
5628
|
+
let go = this.convertExpressionToGo(prop.value.expr, exprOut, prop.value.parsed);
|
|
5629
|
+
if (this.state.errors.length > errorCountBefore) {
|
|
5630
|
+
for (let i = errorCountBefore;i < this.state.errors.length; i++) {
|
|
5631
|
+
this.state.errors[i].loc = prop.loc;
|
|
5632
|
+
}
|
|
5633
|
+
continue;
|
|
5634
|
+
}
|
|
5635
|
+
const singlePartTemplateLiteral = exprOut.parsed?.kind === "template-literal" && exprOut.parsed.parts.length === 1 && exprOut.parsed.parts[0].type !== "string" && go.startsWith("{{") && go.endsWith("}}");
|
|
5636
|
+
if (singlePartTemplateLiteral) {
|
|
5637
|
+
go = go.slice(2, -2);
|
|
5638
|
+
}
|
|
5639
|
+
if (!singlePartTemplateLiteral && this.isTemplateFragment(go, exprOut.parsed?.kind)) {
|
|
5640
|
+
this.state.errors.push({
|
|
5641
|
+
code: "BF101",
|
|
5642
|
+
severity: "error",
|
|
5643
|
+
message: `Prop '${prop.name}' on <${comp.name}> nested inside a dynamic loop row reads the row but can't be lowered to a Go template pipeline argument`,
|
|
5644
|
+
loc: prop.loc
|
|
5645
|
+
});
|
|
5646
|
+
continue;
|
|
5647
|
+
}
|
|
5648
|
+
const fieldName = this.childPropFieldNames.get(comp.name)?.get(prop.name) ?? capitalizeFieldName(prop.name);
|
|
5649
|
+
args.push(`${JSON.stringify(fieldName)} ${wrapIfMultiToken(go)}`);
|
|
5650
|
+
}
|
|
5651
|
+
if (args.length === 0)
|
|
5652
|
+
return null;
|
|
5653
|
+
return { args: args.join(" "), helper: needsRebuild ? "bf_reprops" : "bf_with_props" };
|
|
5654
|
+
}
|
|
5376
5655
|
resolveStaticRecordLiteralIndex(jsExpr) {
|
|
5377
5656
|
const m = /^([A-Za-z_$][\w$]*)\[\s*(?:'([^']*)'|"([^"]*)")\s*\]$/.exec(jsExpr) ?? /^([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)$/.exec(jsExpr);
|
|
5378
5657
|
if (!m)
|
|
@@ -5782,6 +6061,10 @@ ${goFields.join(`
|
|
|
5782
6061
|
}
|
|
5783
6062
|
this.inLoop = true;
|
|
5784
6063
|
const addedLoopVars = [];
|
|
6064
|
+
for (const d of loop.preamble?.declarations ?? []) {
|
|
6065
|
+
this.loopVarRefCount.set(d.name, (this.loopVarRefCount.get(d.name) ?? 0) + 1);
|
|
6066
|
+
addedLoopVars.push(d.name);
|
|
6067
|
+
}
|
|
5785
6068
|
let pushedBindingMap = false;
|
|
5786
6069
|
if (supportableDestructure) {
|
|
5787
6070
|
const built = this.buildDestructureBindingMap(loop, rangeValue);
|
|
@@ -5807,6 +6090,7 @@ ${goFields.join(`
|
|
|
5807
6090
|
this.loopScalarItemStack.push(this.scalarLiteralLoopGoType(loop.arrayParsed, loop.itemType) !== null);
|
|
5808
6091
|
this.loopWrapperStack.push(!!loop.childComponent);
|
|
5809
6092
|
this.loopKeyDepthStack.push(loop.depth);
|
|
6093
|
+
const preambleAssignments = (loop.preamble?.declarations ?? []).map((d) => `{{$${d.name} := ${this.renderParsedExpr(d.valueParsed)}}}`).join("");
|
|
5810
6094
|
const children = this.renderChildren(loop.children);
|
|
5811
6095
|
this.loopKeyDepthStack.pop();
|
|
5812
6096
|
this.loopWrapperStack.pop();
|
|
@@ -5841,9 +6125,9 @@ ${goFields.join(`
|
|
|
5841
6125
|
} else {
|
|
5842
6126
|
filterCond = "true";
|
|
5843
6127
|
}
|
|
5844
|
-
return `{{bfComment "loop:${loop.markerId}"}}{{range $${rangeIndex}, $${rangeValue} := ${goArray}}}{{if ${filterCond}}}${itemMarker}${children}{{end}}{{end}}{{bfComment "/loop:${loop.markerId}"}}`;
|
|
6128
|
+
return `{{bfComment "loop:${loop.markerId}"}}{{range $${rangeIndex}, $${rangeValue} := ${goArray}}}{{if ${filterCond}}}${preambleAssignments}${itemMarker}${children}{{end}}{{end}}{{bfComment "/loop:${loop.markerId}"}}`;
|
|
5845
6129
|
}
|
|
5846
|
-
return `{{bfComment "loop:${loop.markerId}"}}{{range $${rangeIndex}, $${rangeValue} := ${goArray}}}${itemMarker}${children}{{end}}{{bfComment "/loop:${loop.markerId}"}}`;
|
|
6130
|
+
return `{{bfComment "loop:${loop.markerId}"}}{{range $${rangeIndex}, $${rangeValue} := ${goArray}}}${preambleAssignments}${itemMarker}${children}{{end}}{{bfComment "/loop:${loop.markerId}"}}`;
|
|
5847
6131
|
}
|
|
5848
6132
|
renderUnrolledStaticElementLoop(loop, items) {
|
|
5849
6133
|
this.inLoop = true;
|
|
@@ -5942,8 +6226,10 @@ ${goFields.join(`
|
|
|
5942
6226
|
}
|
|
5943
6227
|
} else if (this.inLoop && comp.slotId) {
|
|
5944
6228
|
const suffix = slotIdToFieldSuffix(comp.slotId);
|
|
6229
|
+
const overrides = this.loopRowChildPropOverrides(comp);
|
|
5945
6230
|
const loopBodyDefine = this.queueLoopBodyChildrenDefine(comp);
|
|
5946
|
-
|
|
6231
|
+
const base = overrides ? overrides.helper === "bf_reprops" ? `(bf_reprops ${JSON.stringify(comp.name)} $.${comp.name}${suffix} ${overrides.args})` : `(bf_with_props $.${comp.name}${suffix} ${overrides.args})` : `$.${comp.name}${suffix}`;
|
|
6232
|
+
templateCall = loopBodyDefine ? `{{template "${comp.name}" (bf_with_children ${base} (bf_tmpl "${loopBodyDefine}" .))}}` : `{{template "${comp.name}" ${base}}}`;
|
|
5947
6233
|
} else if (this.inLoop) {
|
|
5948
6234
|
templateCall = `{{template "${comp.name}" .}}`;
|
|
5949
6235
|
} else if (comp.slotId) {
|
|
@@ -6184,7 +6470,6 @@ var goTemplateAdapter = new GoTemplateAdapter;
|
|
|
6184
6470
|
// src/conformance-pins.ts
|
|
6185
6471
|
var conformancePins = {
|
|
6186
6472
|
"filter-typeof-predicate": [{ code: "BF021", severity: "error" }],
|
|
6187
|
-
"map-preamble-branch-body": [{ code: "BF021", severity: "error" }],
|
|
6188
6473
|
"map-array-builder-body": [{ code: "BF021", severity: "error" }],
|
|
6189
6474
|
"map-array-builder-escaping": [{ code: "BF021", severity: "error" }],
|
|
6190
6475
|
"fill-unsupported": [{ code: "BF101", severity: "error" }],
|
|
@@ -6212,7 +6497,12 @@ var conformancePins = {
|
|
|
6212
6497
|
};
|
|
6213
6498
|
// src/render-divergences.ts
|
|
6214
6499
|
var renderDivergences = {
|
|
6215
|
-
"
|
|
6500
|
+
"aliased-destructured-prop": 'aliased destructured prop `{ n: count }` loses its rename — the Input struct field is Count `json:"count"`, so the caller-side struct literal keyed by the real prop name fails `go run` outright (unknown field N, exit 1) (https://github.com/piconic-ai/barefootjs/issues/2460)',
|
|
6501
|
+
"loop-destructured-param-condition": "a destructured .map() param binding used as a row ternary CONDITION emits the root-scope `{{if $.Active}}` — `renderConditionExpr` omits `loopBindingStack`, unlike `identifierToGoRef` (text positions resolve the same binding correctly) (https://github.com/piconic-ai/barefootjs/issues/2486)",
|
|
6502
|
+
"nested-loop-tail-content": "outer-row content AFTER a nested inner loop renders through non-loop arms (spread lowers to the component-root `.Spread_0`) — `inLoop` is cleared, not restored, by the inner loop's exit; the same content BEFORE the inner loop emits correctly (https://github.com/piconic-ai/barefootjs/issues/2487)",
|
|
6503
|
+
"loop-param-shadows-spread-const": "spreading a loop row object mangles attribute names (`id` → `-i-d`, `title` → `-title`); the spread VALUE is correctly row-scoped, distinguishing this from the template-adapter const-shadow hole #2489 (https://github.com/piconic-ai/barefootjs/issues/2490)",
|
|
6504
|
+
"loop-param-shadows-record-template-span": "a dynamic-key element access on a loop row (`tone[k]`) renders empty at execute time — the emitted template contains no baked const (correct post-fix), but the row lookup resolves to nothing (https://github.com/piconic-ai/barefootjs/issues/2491)",
|
|
6505
|
+
"callback-param-shadows-prop": "JS-computed signal/memo initializers (`[…].map(…).join(…)`, memo over signal + prop) don't seed Go SSR — renders `[]` / empty where every other adapter renders the computed value; hydration snaps to correct (https://github.com/piconic-ai/barefootjs/issues/2492)"
|
|
6216
6506
|
};
|
|
6217
6507
|
export {
|
|
6218
6508
|
renderDivergences,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAExD,eAAO,MAAM,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAExD,eAAO,MAAM,iBAAiB,EAAE,iBAsC/B,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/go-template",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.2",
|
|
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.
|
|
52
|
+
"@barefootjs/shared": "0.30.2"
|
|
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.
|
|
60
|
+
"@barefootjs/jsx": "0.30.2"
|
|
61
61
|
}
|
|
62
62
|
}
|