@barefootjs/go-template 0.18.4 → 0.18.5
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 +35 -1
- package/dist/adapter/go-template-adapter.d.ts.map +1 -1
- package/dist/adapter/index.js +162 -21
- package/dist/adapter/lib/compile-state.d.ts +7 -0
- package/dist/adapter/lib/compile-state.d.ts.map +1 -1
- package/dist/adapter/lib/constants.d.ts.map +1 -1
- package/dist/adapter/memo/memo-compute.d.ts.map +1 -1
- package/dist/adapter/props/prop-classes.d.ts +21 -0
- package/dist/adapter/props/prop-classes.d.ts.map +1 -0
- package/dist/adapter/props/prop-types.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/value-lowering.d.ts.map +1 -1
- package/dist/build.js +162 -21
- package/dist/conformance-pins.d.ts.map +1 -1
- package/dist/index.js +164 -40
- package/dist/render-divergences.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/go-template-adapter.test.ts +1 -1
- package/src/adapter/go-template-adapter.ts +226 -9
- package/src/adapter/lib/compile-state.ts +8 -0
- package/src/adapter/lib/constants.ts +1 -0
- package/src/adapter/memo/memo-compute.ts +37 -9
- package/src/adapter/props/prop-classes.ts +45 -0
- package/src/adapter/props/prop-types.ts +69 -1
- package/src/adapter/type/type-codegen.ts +19 -2
- package/src/adapter/value/value-lowering.ts +27 -2
- package/src/conformance-pins.ts +0 -5
- package/src/render-divergences.ts +0 -30
- package/src/test-render.ts +23 -8
package/dist/index.js
CHANGED
|
@@ -42,10 +42,11 @@ import {
|
|
|
42
42
|
collectModuleStringConsts as collectModuleStringConstsShared,
|
|
43
43
|
prepareLoweringMatchers,
|
|
44
44
|
envSignalReaderFor,
|
|
45
|
-
computeSsrSeedPlan
|
|
45
|
+
computeSsrSeedPlan,
|
|
46
|
+
isStringConcatBinary
|
|
46
47
|
} from "@barefootjs/jsx";
|
|
47
48
|
import { findInterpolationEnd } from "@barefootjs/jsx/scanner";
|
|
48
|
-
import { BF_REGION } from "@barefootjs/shared";
|
|
49
|
+
import { BF_REGION, escapeHtml } from "@barefootjs/shared";
|
|
49
50
|
|
|
50
51
|
// src/adapter/lib/go-naming.ts
|
|
51
52
|
var GO_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
@@ -332,6 +333,7 @@ var GO_TEMPLATE_PRIMITIVES = {
|
|
|
332
333
|
"Math.floor": { arity: 1, emit: (args) => `bf_floor ${wrapGoArg(args[0])}` },
|
|
333
334
|
"Math.ceil": { arity: 1, emit: (args) => `bf_ceil ${wrapGoArg(args[0])}` },
|
|
334
335
|
"Math.round": { arity: 1, emit: (args) => `bf_round ${wrapGoArg(args[0])}` },
|
|
336
|
+
"Math.abs": { arity: 1, emit: (args) => `bf_abs ${wrapGoArg(args[0])}` },
|
|
335
337
|
"Math.min": { arity: 2, emit: (args) => `bf_min ${wrapGoArg(args[0])} ${wrapGoArg(args[1])}` },
|
|
336
338
|
"Math.max": { arity: 2, emit: (args) => `bf_max ${wrapGoArg(args[0])} ${wrapGoArg(args[1])}` }
|
|
337
339
|
};
|
|
@@ -357,6 +359,7 @@ class CompileState {
|
|
|
357
359
|
hoistedMemoLocals = new Map;
|
|
358
360
|
loweringMatchers = [];
|
|
359
361
|
nillablePropNames = new Set;
|
|
362
|
+
stringValueNames = new Set;
|
|
360
363
|
rootScopeNodes = new Set;
|
|
361
364
|
memoBackedLoopSlice = new Map;
|
|
362
365
|
usesHtmlTemplate = false;
|
|
@@ -776,7 +779,7 @@ function typeInfoToGo(ctx, typeInfo, defaultValue) {
|
|
|
776
779
|
case "string":
|
|
777
780
|
return "string";
|
|
778
781
|
case "number":
|
|
779
|
-
return "int";
|
|
782
|
+
return defaultValue !== undefined ? numberPrimitiveGoType(defaultValue) : "int";
|
|
780
783
|
case "boolean":
|
|
781
784
|
return "bool";
|
|
782
785
|
default:
|
|
@@ -827,6 +830,9 @@ function tsTypeStringToGo(ctx, tsType) {
|
|
|
827
830
|
return t;
|
|
828
831
|
return "interface{}";
|
|
829
832
|
}
|
|
833
|
+
function numberPrimitiveGoType(value) {
|
|
834
|
+
return /^-?\d+\.\d+$/.test(value) ? "float64" : "int";
|
|
835
|
+
}
|
|
830
836
|
function inferTypeFromValue(value) {
|
|
831
837
|
if (value === "true" || value === "false")
|
|
832
838
|
return "bool";
|
|
@@ -939,9 +945,9 @@ function convertInitialValue(ctx, value, typeInfo, propsParams, preParsed) {
|
|
|
939
945
|
return value === "true" ? "true" : "false";
|
|
940
946
|
}
|
|
941
947
|
if (typeInfo.primitive === "number") {
|
|
942
|
-
if (
|
|
948
|
+
if (/^-?\d+$/.test(value))
|
|
943
949
|
return value;
|
|
944
|
-
if (
|
|
950
|
+
if (/^-?\d+\.\d+$/.test(value))
|
|
945
951
|
return value;
|
|
946
952
|
return "0";
|
|
947
953
|
}
|
|
@@ -966,6 +972,12 @@ function convertInitialValue(ctx, value, typeInfo, propsParams, preParsed) {
|
|
|
966
972
|
}
|
|
967
973
|
return '""';
|
|
968
974
|
}
|
|
975
|
+
if (ctx.state.localStructFields.has(typeInfo.raw)) {
|
|
976
|
+
const baked = jsLiteralToGo(ctx, typeInfo, preParsed);
|
|
977
|
+
if (baked !== null)
|
|
978
|
+
return baked;
|
|
979
|
+
return `${typeInfo.raw}{}`;
|
|
980
|
+
}
|
|
969
981
|
}
|
|
970
982
|
return "nil";
|
|
971
983
|
}
|
|
@@ -1656,10 +1668,11 @@ function memoInitialFromParsedBody(ctx, body, signals, propsParams, propFallback
|
|
|
1656
1668
|
const operand = String(body.right.value);
|
|
1657
1669
|
const depName = getterCallName(body.left);
|
|
1658
1670
|
if (depName) {
|
|
1659
|
-
const
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1671
|
+
const depInitial = resolveGetterValueAsGo(ctx, depName, signals, propsParams, propFallbackVars, resolving);
|
|
1672
|
+
const isArithmeticSafe = depInitial !== null && !depInitial.startsWith("func(");
|
|
1673
|
+
if (isArithmeticSafe) {
|
|
1674
|
+
const wrapped = /\s/.test(depInitial) ? `(${depInitial})` : depInitial;
|
|
1675
|
+
return `${wrapped} ${operator} ${operand}`;
|
|
1663
1676
|
}
|
|
1664
1677
|
}
|
|
1665
1678
|
const propName = propsMemberName(body.left);
|
|
@@ -1694,9 +1707,9 @@ function memoInitialFromParsedBody(ctx, body, signals, propsParams, propFallback
|
|
|
1694
1707
|
}
|
|
1695
1708
|
const simpleDep = getterCallName(body);
|
|
1696
1709
|
if (simpleDep) {
|
|
1697
|
-
const
|
|
1698
|
-
if (
|
|
1699
|
-
return
|
|
1710
|
+
const depInitial = resolveGetterValueAsGo(ctx, simpleDep, signals, propsParams, propFallbackVars, resolving);
|
|
1711
|
+
if (depInitial !== null) {
|
|
1712
|
+
return depInitial;
|
|
1700
1713
|
}
|
|
1701
1714
|
}
|
|
1702
1715
|
const simpleProp = propsMemberName(body);
|
|
@@ -2087,8 +2100,47 @@ function buildPropTypeOverrides(ctx, ir) {
|
|
|
2087
2100
|
}
|
|
2088
2101
|
}
|
|
2089
2102
|
}
|
|
2103
|
+
for (const propName of collectToFixedPropNames(ir.root)) {
|
|
2104
|
+
const param = ir.metadata.propsParams.find((p) => p.name === propName);
|
|
2105
|
+
if (!param)
|
|
2106
|
+
continue;
|
|
2107
|
+
const resolved = overrides.get(propName) ?? typeInfoToGo(ctx, param.type, param.defaultValue);
|
|
2108
|
+
if (resolved === "int") {
|
|
2109
|
+
overrides.set(propName, "float64");
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2090
2112
|
return overrides;
|
|
2091
2113
|
}
|
|
2114
|
+
function collectToFixedPropNames(root) {
|
|
2115
|
+
const names = new Set;
|
|
2116
|
+
const checkExpr = (expr) => {
|
|
2117
|
+
if (expr?.kind === "array-method" && expr.method === "toFixed" && expr.object.kind === "identifier") {
|
|
2118
|
+
names.add(expr.object.name);
|
|
2119
|
+
}
|
|
2120
|
+
};
|
|
2121
|
+
const walk = (node) => {
|
|
2122
|
+
if (!node)
|
|
2123
|
+
return;
|
|
2124
|
+
if (node.type === "expression")
|
|
2125
|
+
checkExpr(node.parsed);
|
|
2126
|
+
if (node.type === "conditional") {
|
|
2127
|
+
checkExpr(node.parsedCondition);
|
|
2128
|
+
walk(node.whenTrue);
|
|
2129
|
+
walk(node.whenFalse);
|
|
2130
|
+
}
|
|
2131
|
+
if (node.type === "element") {
|
|
2132
|
+
for (const attr of node.attrs) {
|
|
2133
|
+
if (attr.value.kind === "expression")
|
|
2134
|
+
checkExpr(attr.value.parsed);
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
if ("children" in node && Array.isArray(node.children)) {
|
|
2138
|
+
node.children.forEach(walk);
|
|
2139
|
+
}
|
|
2140
|
+
};
|
|
2141
|
+
walk(root);
|
|
2142
|
+
return names;
|
|
2143
|
+
}
|
|
2092
2144
|
function resolvePropGoType(ctx, param, propTypeOverrides) {
|
|
2093
2145
|
const base = propTypeOverrides.get(param.name) ?? typeInfoToGo(ctx, param.type, param.defaultValue);
|
|
2094
2146
|
if (param.optional && ctx.state.localStructFields.has(base)) {
|
|
@@ -2107,6 +2159,30 @@ function collectNillablePropNames(ctx, ir) {
|
|
|
2107
2159
|
return nillable;
|
|
2108
2160
|
}
|
|
2109
2161
|
|
|
2162
|
+
// src/adapter/props/prop-classes.ts
|
|
2163
|
+
function isStringTypeInfo(type) {
|
|
2164
|
+
return type.kind === "primitive" && type.primitive === "string";
|
|
2165
|
+
}
|
|
2166
|
+
function isBareStringLiteral(initialValue) {
|
|
2167
|
+
if (!initialValue)
|
|
2168
|
+
return false;
|
|
2169
|
+
const v = initialValue.trim();
|
|
2170
|
+
return v.startsWith("'") && v.endsWith("'") || v.startsWith('"') && v.endsWith('"');
|
|
2171
|
+
}
|
|
2172
|
+
function collectStringValueNames(ir) {
|
|
2173
|
+
const names = new Set;
|
|
2174
|
+
for (const s of ir.metadata.signals) {
|
|
2175
|
+
if (isStringTypeInfo(s.type) || isBareStringLiteral(s.initialValue)) {
|
|
2176
|
+
names.add(s.getter);
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
for (const p of ir.metadata.propsParams) {
|
|
2180
|
+
if (isStringTypeInfo(p.type))
|
|
2181
|
+
names.add(p.name);
|
|
2182
|
+
}
|
|
2183
|
+
return names;
|
|
2184
|
+
}
|
|
2185
|
+
|
|
2110
2186
|
// src/adapter/go-template-adapter.ts
|
|
2111
2187
|
var STRING_METHODS = new Set([
|
|
2112
2188
|
"replace",
|
|
@@ -2149,6 +2225,7 @@ class GoTemplateAdapter extends BaseAdapter {
|
|
|
2149
2225
|
}
|
|
2150
2226
|
inLoop = false;
|
|
2151
2227
|
loopParamStack = [];
|
|
2228
|
+
loopKeyDepthStack = [];
|
|
2152
2229
|
loopScalarItemStack = [];
|
|
2153
2230
|
loopWrapperStack = [];
|
|
2154
2231
|
loopVarRefCount = new Map;
|
|
@@ -2196,6 +2273,7 @@ class GoTemplateAdapter extends BaseAdapter {
|
|
|
2196
2273
|
this.state.pendingChildrenDefines = [];
|
|
2197
2274
|
this.primeCompileState(ir);
|
|
2198
2275
|
this.state.nillablePropNames = collectNillablePropNames(this.emitCtx, ir);
|
|
2276
|
+
this.state.stringValueNames = collectStringValueNames(ir);
|
|
2199
2277
|
if (!options?.siblingTemplatesRegistered) {
|
|
2200
2278
|
this.checkImportedLoopChildComponents(ir);
|
|
2201
2279
|
}
|
|
@@ -2893,6 +2971,13 @@ ${goFields.join(`
|
|
|
2893
2971
|
break;
|
|
2894
2972
|
}
|
|
2895
2973
|
}
|
|
2974
|
+
if (parsedValue) {
|
|
2975
|
+
const goVal = parsedLiteralToGo(this.emitCtx, parsedValue);
|
|
2976
|
+
if (goVal !== null) {
|
|
2977
|
+
emitChildField(prop.name, goVal);
|
|
2978
|
+
break;
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2896
2981
|
const resolvedValue = this.resolveDynamicPropValue(exprText, ir.metadata.signals, ir.metadata.memos, ir.metadata.propsParams);
|
|
2897
2982
|
if (resolvedValue !== null) {
|
|
2898
2983
|
emitChildField(prop.name, resolvedValue);
|
|
@@ -2900,6 +2985,24 @@ ${goFields.join(`
|
|
|
2900
2985
|
break;
|
|
2901
2986
|
}
|
|
2902
2987
|
case "jsx-children":
|
|
2988
|
+
if (prop.name !== "children") {
|
|
2989
|
+
const text = this.extractTextChildren(prop.value.children);
|
|
2990
|
+
if (text !== null) {
|
|
2991
|
+
emitChildField(prop.name, JSON.stringify(text));
|
|
2992
|
+
} else {
|
|
2993
|
+
const html = this.extractHtmlChildren(prop.value.children);
|
|
2994
|
+
if (html !== null) {
|
|
2995
|
+
this.state.usesHtmlTemplate = true;
|
|
2996
|
+
emitChildField(prop.name, `template.HTML(${JSON.stringify(html)})`);
|
|
2997
|
+
} else {
|
|
2998
|
+
const scopedHtml = this.extractScopedHtmlChildren(prop.value.children);
|
|
2999
|
+
if (scopedHtml !== null) {
|
|
3000
|
+
this.state.usesHtmlTemplate = true;
|
|
3001
|
+
emitChildField(prop.name, `template.HTML(${scopedHtml})`);
|
|
3002
|
+
}
|
|
3003
|
+
}
|
|
3004
|
+
}
|
|
3005
|
+
}
|
|
2903
3006
|
break;
|
|
2904
3007
|
}
|
|
2905
3008
|
}
|
|
@@ -3541,6 +3644,17 @@ ${goFields.join(`
|
|
|
3541
3644
|
return computeMemoInitialValueOrNull(this.emitCtx, memo, signals, propsParams, undefined, new Set([memo.name]));
|
|
3542
3645
|
}
|
|
3543
3646
|
}
|
|
3647
|
+
const propsObjectName = this.state.propsObjectName;
|
|
3648
|
+
const identifierPattern = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
3649
|
+
const bareIdentifier = identifierPattern.test(expr) ? expr : null;
|
|
3650
|
+
const barePropAccess = propsObjectName && expr.startsWith(`${propsObjectName}.`) && identifierPattern.test(expr.slice(propsObjectName.length + 1)) ? expr.slice(propsObjectName.length + 1) : null;
|
|
3651
|
+
const passthroughName = bareIdentifier ?? barePropAccess;
|
|
3652
|
+
const localConst = this.state.localConstants.find((c) => c.name === passthroughName);
|
|
3653
|
+
const isPropsDestructureAlias = localConst !== undefined && propsObjectName !== null && localConst.value === `${propsObjectName}.${passthroughName}`;
|
|
3654
|
+
const shadowedByLocal = passthroughName !== null && (localConst !== undefined && !isPropsDestructureAlias || this.state.localHelperNames.has(passthroughName));
|
|
3655
|
+
if (passthroughName && !shadowedByLocal && propsParams.some((p) => p.name === passthroughName)) {
|
|
3656
|
+
return `in.${capitalizeFieldName(passthroughName)}`;
|
|
3657
|
+
}
|
|
3544
3658
|
return null;
|
|
3545
3659
|
}
|
|
3546
3660
|
inferMemoType(memo, signals, propsParamMap) {
|
|
@@ -3665,7 +3779,7 @@ ${goFields.join(`
|
|
|
3665
3779
|
return this.renderElement(node);
|
|
3666
3780
|
}
|
|
3667
3781
|
emitText(node) {
|
|
3668
|
-
return node.value;
|
|
3782
|
+
return escapeHtml(node.value);
|
|
3669
3783
|
}
|
|
3670
3784
|
emitExpression(node) {
|
|
3671
3785
|
return this.renderExpression(node);
|
|
@@ -3925,7 +4039,7 @@ ${goFields.join(`
|
|
|
3925
4039
|
const argsStr = args.map(emit).join(" ");
|
|
3926
4040
|
return `${calleeStr} ${argsStr}`;
|
|
3927
4041
|
}
|
|
3928
|
-
member(object, property, _computed, emit) {
|
|
4042
|
+
member(object, property, _computed, optional, emit) {
|
|
3929
4043
|
const objHO = this.higherOrderShapeOf(object);
|
|
3930
4044
|
if (property === "length" && objHO) {
|
|
3931
4045
|
const result = this.renderFilterLengthExpr(objHO, emit);
|
|
@@ -3967,6 +4081,9 @@ ${goFields.join(`
|
|
|
3967
4081
|
const obj = emit(object);
|
|
3968
4082
|
if (property === "length")
|
|
3969
4083
|
return `len ${obj}`;
|
|
4084
|
+
if (optional) {
|
|
4085
|
+
return `bf_get ${wrapIfMultiToken(obj)} ${JSON.stringify(goFieldNameForKey(property))}`;
|
|
4086
|
+
}
|
|
3970
4087
|
return `${obj}.${goFieldNameForKey(property)}`;
|
|
3971
4088
|
}
|
|
3972
4089
|
indexAccess(object, index, emit) {
|
|
@@ -3997,7 +4114,7 @@ ${goFields.join(`
|
|
|
3997
4114
|
case "<=":
|
|
3998
4115
|
return `le ${wl} ${wr}`;
|
|
3999
4116
|
case "+":
|
|
4000
|
-
return
|
|
4117
|
+
return this._emitPlus(left, right, wl, wr);
|
|
4001
4118
|
case "-":
|
|
4002
4119
|
return `bf_sub ${wl} ${wr}`;
|
|
4003
4120
|
case "*":
|
|
@@ -4010,6 +4127,15 @@ ${goFields.join(`
|
|
|
4010
4127
|
return `${l} ${op} ${r}`;
|
|
4011
4128
|
}
|
|
4012
4129
|
}
|
|
4130
|
+
_emitPlus(leftExpr, rightExpr, leftRendered, rightRendered) {
|
|
4131
|
+
if (isStringConcatBinary("+", leftExpr, rightExpr, (n) => this._isStringValueName(n))) {
|
|
4132
|
+
return `bf_concat_str ${leftRendered} ${rightRendered}`;
|
|
4133
|
+
}
|
|
4134
|
+
return `bf_add ${leftRendered} ${rightRendered}`;
|
|
4135
|
+
}
|
|
4136
|
+
_isStringValueName(name) {
|
|
4137
|
+
return this.state.stringValueNames.has(name);
|
|
4138
|
+
}
|
|
4013
4139
|
unary(op, argument, emit) {
|
|
4014
4140
|
const arg = emit(argument);
|
|
4015
4141
|
if (op === "!")
|
|
@@ -4221,6 +4347,12 @@ ${goFields.join(`
|
|
|
4221
4347
|
const recv = emit(object);
|
|
4222
4348
|
return `bf_trim ${wrapIfMultiToken(recv)}`;
|
|
4223
4349
|
}
|
|
4350
|
+
case "trimStart":
|
|
4351
|
+
case "trimEnd": {
|
|
4352
|
+
const fn = method === "trimStart" ? "bf_trim_start" : "bf_trim_end";
|
|
4353
|
+
const recv = emit(object);
|
|
4354
|
+
return `${fn} ${wrapIfMultiToken(recv)}`;
|
|
4355
|
+
}
|
|
4224
4356
|
case "toFixed": {
|
|
4225
4357
|
const recv = emit(object);
|
|
4226
4358
|
const digits = args.length >= 1 ? emit(args[0]) : "0";
|
|
@@ -4255,6 +4387,12 @@ ${goFields.join(`
|
|
|
4255
4387
|
const newS = emit(args[1]);
|
|
4256
4388
|
return `bf_replace ${wrapIfMultiToken(recv)} ${wrapIfMultiToken(oldS)} ${wrapIfMultiToken(newS)}`;
|
|
4257
4389
|
}
|
|
4390
|
+
case "replaceAll": {
|
|
4391
|
+
const recv = emit(object);
|
|
4392
|
+
const oldS = emit(args[0]);
|
|
4393
|
+
const newS = emit(args[1]);
|
|
4394
|
+
return `bf_replace_all ${wrapIfMultiToken(recv)} ${wrapIfMultiToken(oldS)} ${wrapIfMultiToken(newS)}`;
|
|
4395
|
+
}
|
|
4258
4396
|
case "repeat": {
|
|
4259
4397
|
const recv = emit(object);
|
|
4260
4398
|
const count = args.length === 0 ? "0" : emit(args[0]);
|
|
@@ -4561,7 +4699,7 @@ ${goFields.join(`
|
|
|
4561
4699
|
case "<=":
|
|
4562
4700
|
return `le ${left} ${right}`;
|
|
4563
4701
|
case "+":
|
|
4564
|
-
return
|
|
4702
|
+
return this._emitPlus(expr.left, expr.right, left, right);
|
|
4565
4703
|
case "-":
|
|
4566
4704
|
return `bf_sub ${left} ${right}`;
|
|
4567
4705
|
case "*":
|
|
@@ -4930,7 +5068,7 @@ ${goFields.join(`
|
|
|
4930
5068
|
result = `le ${left} ${right}`;
|
|
4931
5069
|
break;
|
|
4932
5070
|
case "+":
|
|
4933
|
-
result =
|
|
5071
|
+
result = this._emitPlus(expr.left, expr.right, left, right);
|
|
4934
5072
|
break;
|
|
4935
5073
|
case "-":
|
|
4936
5074
|
result = `bf_sub ${left} ${right}`;
|
|
@@ -5087,7 +5225,9 @@ ${goFields.join(`
|
|
|
5087
5225
|
}
|
|
5088
5226
|
this.loopScalarItemStack.push(this.scalarLiteralLoopGoType(loop.arrayParsed, loop.itemType) !== null);
|
|
5089
5227
|
this.loopWrapperStack.push(!!loop.childComponent);
|
|
5228
|
+
this.loopKeyDepthStack.push(loop.depth);
|
|
5090
5229
|
const children = this.renderChildren(loop.children);
|
|
5230
|
+
this.loopKeyDepthStack.pop();
|
|
5091
5231
|
this.loopWrapperStack.pop();
|
|
5092
5232
|
this.loopScalarItemStack.pop();
|
|
5093
5233
|
const itemMarker = this.loopItemMarker(loop);
|
|
@@ -5230,7 +5370,7 @@ ${goFields.join(`
|
|
|
5230
5370
|
${children}`;
|
|
5231
5371
|
}
|
|
5232
5372
|
elementAttrEmitter = {
|
|
5233
|
-
emitLiteral: (value, name) => `${name}="${value.value}"`,
|
|
5373
|
+
emitLiteral: (value, name) => `${name}="${escapeHtml(value.value)}"`,
|
|
5234
5374
|
emitExpression: (value, name) => {
|
|
5235
5375
|
if (name === "style") {
|
|
5236
5376
|
const css = this.tryLowerStyleObject(value.expr);
|
|
@@ -5320,9 +5460,10 @@ ${children}`;
|
|
|
5320
5460
|
let attrName;
|
|
5321
5461
|
if (attr.name === "className")
|
|
5322
5462
|
attrName = "class";
|
|
5323
|
-
else if (attr.name === "key")
|
|
5324
|
-
|
|
5325
|
-
|
|
5463
|
+
else if (attr.name === "key") {
|
|
5464
|
+
const depth = this.loopKeyDepthStack.at(-1) ?? 0;
|
|
5465
|
+
attrName = depth > 0 ? `data-key-${depth}` : "data-key";
|
|
5466
|
+
} else
|
|
5326
5467
|
attrName = attr.name;
|
|
5327
5468
|
const lowered = emitAttrValue(attr.value, this.elementAttrEmitter, attrName);
|
|
5328
5469
|
if (lowered)
|
|
@@ -5437,27 +5578,10 @@ var conformancePins = {
|
|
|
5437
5578
|
{ code: "BF101", severity: "error", issue: "https://github.com/piconic-ai/barefootjs/issues/2038" }
|
|
5438
5579
|
],
|
|
5439
5580
|
"array-map-function-reference": [{ code: "BF101", severity: "error" }],
|
|
5440
|
-
"dangerous-inner-html": [{ code: "BF101", severity: "error" }]
|
|
5441
|
-
"string-replaceall": [{ code: "BF101", severity: "error" }]
|
|
5581
|
+
"dangerous-inner-html": [{ code: "BF101", severity: "error" }]
|
|
5442
5582
|
};
|
|
5443
5583
|
// src/render-divergences.ts
|
|
5444
|
-
var renderDivergences = {
|
|
5445
|
-
"html-entity-text": "`©` in JSX literal text: Hono decodes to `©`, this adapter re-emits the raw entity — same DOM, different bytes",
|
|
5446
|
-
"string-concat-plus": "`'Hello, ' + name` renders \"0\" — JS string-concat `+` lowered through numeric addition",
|
|
5447
|
-
"optional-chaining-prop": "`user?.name ?? …` on an object prop: generated Go fails to run (exit 1) — optional chaining into a struct/map prop has no lowering",
|
|
5448
|
-
"number-tofixed": "`.toFixed(2)` on a number PROP: generated Go fails to run (exit 1)",
|
|
5449
|
-
"math-methods": "Math.min/max/abs over a signal: generated Go fails to run (exit 1) — only Math.floor is registered",
|
|
5450
|
-
"static-attr-escape": 'static attribute values are not HTML-escaped (`title="Fish & Chips"` emitted raw; Hono escapes)',
|
|
5451
|
-
"object-entries-map": "`Object.entries(prop).map(([k, v]) => …)`: generated Go fails to run (exit 1) — no object-iteration loop lowering",
|
|
5452
|
-
"nested-loop-outer-binding": "nested-loop inner items carry `data-key` where the reference emits the depth-suffixed `data-key-1`",
|
|
5453
|
-
"jsx-element-prop": "a JSX element passed as a NON-children prop renders an empty slot — the element value is silently dropped",
|
|
5454
|
-
"grandchild-composition": "three-level composition: the grandchild's threaded prop renders EMPTY — prop forwarding through two template-render layers loses the value",
|
|
5455
|
-
"child-primitive-props": "numeric/boolean LITERAL props on a child (`count={5}` `active={true}`) render as Go zero values (0 / false)",
|
|
5456
|
-
"memo-chain": "a memo derived from another memo renders EMPTY for the second layer — the constructor folds only one derivation level",
|
|
5457
|
-
"signal-object-field": "object-valued signal (`user().name`): generated Go fails to run (exit 1) — no struct synthesis outside loops",
|
|
5458
|
-
"string-slice": '`.slice()` on a STRING routes through the array `bf_slice` helper and renders "[]" instead of the substring',
|
|
5459
|
-
"string-trim-sided": "`.trimStart()` / `.trimEnd()`: generated Go fails to run (exit 1) — only both-sides `bf_trim` exists"
|
|
5460
|
-
};
|
|
5584
|
+
var renderDivergences = {};
|
|
5461
5585
|
export {
|
|
5462
5586
|
renderDivergences,
|
|
5463
5587
|
goTemplateAdapter,
|
|
@@ -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,iBAC/B,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/go-template",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.5",
|
|
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.18.
|
|
52
|
+
"@barefootjs/shared": "0.18.5"
|
|
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.18.
|
|
60
|
+
"@barefootjs/jsx": "0.18.5"
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -2286,7 +2286,7 @@ export function Tagged(props: { className?: string }) {
|
|
|
2286
2286
|
// list rather than replace.
|
|
2287
2287
|
const a = new GoTemplateAdapter()
|
|
2288
2288
|
const keys = Object.keys(a.templatePrimitives ?? {}).sort()
|
|
2289
|
-
expect(keys).toEqual(['JSON.stringify', 'Math.ceil', 'Math.floor', 'Math.max', 'Math.min', 'Math.round', 'Number', 'String'])
|
|
2289
|
+
expect(keys).toEqual(['JSON.stringify', 'Math.abs', 'Math.ceil', 'Math.floor', 'Math.max', 'Math.min', 'Math.round', 'Number', 'String'])
|
|
2290
2290
|
})
|
|
2291
2291
|
|
|
2292
2292
|
test('unregistered identifier-path callee is NOT accepted by the registry', () => {
|