@barefootjs/go-template 0.1.2 → 0.2.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/build.js CHANGED
@@ -420,9 +420,11 @@ class GoTemplateAdapter extends BaseAdapter {
420
420
  options;
421
421
  inLoop = false;
422
422
  loopParamStack = [];
423
+ loopVarRefCount = new Map;
423
424
  errors = [];
424
425
  propsObjectName = null;
425
426
  restPropsName = null;
427
+ templateVarCounter = 0;
426
428
  localTypeNames = new Set;
427
429
  localTypeAliases = new Map;
428
430
  usesHtmlTemplate = false;
@@ -437,6 +439,7 @@ class GoTemplateAdapter extends BaseAdapter {
437
439
  generate(ir, options) {
438
440
  this.componentName = ir.metadata.componentName;
439
441
  this.errors = [];
442
+ this.templateVarCounter = 0;
440
443
  this.propsObjectName = ir.metadata.propsObjectName;
441
444
  this.restPropsName = ir.metadata.restPropsName ?? null;
442
445
  if (!options?.siblingTemplatesRegistered) {
@@ -776,7 +779,7 @@ ${goFields.join(`
776
779
  lines.push("\tScopeID string // Optional: if empty, random ID is generated");
777
780
  lines.push("\tBfParent string // Optional: parent scope id");
778
781
  lines.push("\tBfMount string // Optional: slot id in parent");
779
- const staticNested = nestedComponents.filter((n) => !n.isDynamic);
782
+ const inputNested = nestedComponents.filter((n) => !n.isDynamic || n.isPropDerived);
780
783
  const nestedArrayFields = new Set(nestedComponents.map((n) => `${n.name}s`));
781
784
  for (const param of ir.metadata.propsParams) {
782
785
  const fieldName = this.capitalizeFieldName(param.name);
@@ -785,7 +788,7 @@ ${goFields.join(`
785
788
  const goType = propTypeOverrides.get(param.name) ?? this.typeInfoToGo(param.type, param.defaultValue);
786
789
  lines.push(` ${fieldName} ${goType}`);
787
790
  }
788
- for (const nested of staticNested) {
791
+ for (const nested of inputNested) {
789
792
  lines.push(` ${nested.name}s []${nested.name}Input`);
790
793
  }
791
794
  const restPropsName = ir.metadata.restPropsName;
@@ -861,7 +864,7 @@ ${goFields.join(`
861
864
  lines.push(` ${fieldName} ${goType} \`json:"${jsonTag}"\``);
862
865
  }
863
866
  for (const nested of nestedComponents) {
864
- if (nested.isDynamic) {
867
+ if (nested.isDynamic && !nested.isPropDerived) {
865
868
  lines.push(` ${nested.name}s []${nested.name}Props \`json:"-"\``);
866
869
  } else {
867
870
  const jsonTag = this.toJsonTag(`${nested.name.charAt(0).toLowerCase()}${nested.name.slice(1)}s`);
@@ -882,9 +885,9 @@ ${goFields.join(`
882
885
  generateNewPropsFunction(lines, ir, componentName, nestedComponents, spreadSlots) {
883
886
  const inputTypeName = `${componentName}Input`;
884
887
  const propsTypeName = `${componentName}Props`;
885
- const dynamicNested = nestedComponents.filter((n) => n.isDynamic);
888
+ const signalDynamicNested = nestedComponents.filter((n) => n.isDynamic && !n.isPropDerived);
886
889
  lines.push(`// New${componentName}Props creates ${propsTypeName} from ${inputTypeName}.`);
887
- for (const nested of dynamicNested) {
890
+ for (const nested of signalDynamicNested) {
888
891
  const arrayField = `${nested.name}s`;
889
892
  lines.push(`//`);
890
893
  lines.push(`// NOTE: \`${arrayField}\` is populated by the route handler, not by`);
@@ -906,7 +909,7 @@ ${goFields.join(`
906
909
  lines.push(` scopeID = "${componentName}_" + randomID(6)`);
907
910
  lines.push("\t}");
908
911
  lines.push("");
909
- const staticNested = nestedComponents.filter((n) => !n.isDynamic);
912
+ const staticNested = nestedComponents.filter((n) => !n.isDynamic || n.isPropDerived);
910
913
  if (staticNested.length > 0) {
911
914
  for (const nested of staticNested) {
912
915
  const varName = `${nested.name.charAt(0).toLowerCase()}${nested.name.slice(1)}s`;
@@ -1054,7 +1057,8 @@ ${goFields.join(`
1054
1057
  if (!result.some((c) => c.name === loop.childComponent.name)) {
1055
1058
  result.push({
1056
1059
  ...loop.childComponent,
1057
- isDynamic: !loop.isStaticArray
1060
+ isDynamic: !loop.isStaticArray,
1061
+ isPropDerived: !!loop.isPropDerivedArray
1058
1062
  });
1059
1063
  }
1060
1064
  }
@@ -1871,13 +1875,18 @@ ${goFields.join(`
1871
1875
  return emitParsedExpr(expr, this);
1872
1876
  }
1873
1877
  identifier(name) {
1878
+ const currentLoopParam = this.loopParamStack[this.loopParamStack.length - 1];
1879
+ if (currentLoopParam && name === currentLoopParam)
1880
+ return ".";
1881
+ if (this.loopVarRefCount.has(name))
1882
+ return `$${name}`;
1874
1883
  return `.${this.capitalizeFieldName(name)}`;
1875
1884
  }
1876
1885
  literal(value, literalType) {
1877
1886
  if (literalType === "string")
1878
1887
  return `"${value}"`;
1879
1888
  if (literalType === "null")
1880
- return '""';
1889
+ return "nil";
1881
1890
  return String(value);
1882
1891
  }
1883
1892
  call(callee, args, emit) {
@@ -1913,7 +1922,7 @@ ${goFields.join(`
1913
1922
  if (result)
1914
1923
  return result;
1915
1924
  }
1916
- if (object.kind === "higher-order" && object.method === "find") {
1925
+ if (object.kind === "higher-order" && (object.method === "find" || object.method === "findLast")) {
1917
1926
  const findResult = this.renderHigherOrderExpr(object, emit);
1918
1927
  if (findResult) {
1919
1928
  return `{{with ${findResult}}}{{.${this.capitalizeFieldName(property)}}}{{end}}`;
@@ -2017,7 +2026,7 @@ ${goFields.join(`
2017
2026
  const result = this.renderHigherOrderExpr(reconstructed, emit);
2018
2027
  if (result)
2019
2028
  return result;
2020
- if (method === "find" || method === "findIndex") {
2029
+ if (method === "find" || method === "findIndex" || method === "findLast" || method === "findLastIndex") {
2021
2030
  const templateBlock = this.renderFindTemplateBlock(reconstructed, emit);
2022
2031
  if (templateBlock)
2023
2032
  return templateBlock;
@@ -2157,12 +2166,17 @@ ${goFields.join(`
2157
2166
  const value = negated ? "false" : "true";
2158
2167
  return `bf_filter ${arrayExpr} "${field}" ${value}`;
2159
2168
  }
2160
- if (expr.method === "find" || expr.method === "findIndex") {
2169
+ if (expr.method === "find" || expr.method === "findIndex" || expr.method === "findLast" || expr.method === "findLastIndex") {
2161
2170
  const eqPred = this.extractEqualityPredicate(expr.predicate, expr.param, (e) => this.renderParsedExpr(e));
2162
2171
  if (!eqPred)
2163
2172
  return null;
2164
- const func = expr.method === "find" ? "bf_find" : "bf_find_index";
2165
- return `${func} ${arrayExpr} "${eqPred.field}" ${eqPred.value}`;
2173
+ const funcMap = {
2174
+ find: "bf_find",
2175
+ findIndex: "bf_find_index",
2176
+ findLast: "bf_find_last",
2177
+ findLastIndex: "bf_find_last_index"
2178
+ };
2179
+ return `${funcMap[expr.method]} ${arrayExpr} "${eqPred.field}" ${eqPred.value}`;
2166
2180
  }
2167
2181
  return null;
2168
2182
  }
@@ -2178,6 +2192,15 @@ ${goFields.join(`
2178
2192
  if (expr.method === "findIndex") {
2179
2193
  return `{{range $i, $_ := ${arrayExpr}}}{{if ${condition}}}{{$i}}{{break}}{{end}}{{end}}`;
2180
2194
  }
2195
+ if (expr.method === "findLast") {
2196
+ const v = `$bf_r${this.templateVarCounter++}`;
2197
+ const capture = propertyAccess ? `.${propertyAccess}` : ".";
2198
+ return `{{${v} := ""}}{{range ${arrayExpr}}}{{if ${condition}}}{{${v} = ${capture}}}{{end}}{{end}}{{${v}}}`;
2199
+ }
2200
+ if (expr.method === "findLastIndex") {
2201
+ const v = `$bf_r${this.templateVarCounter++}`;
2202
+ return `{{${v} := -1}}{{range $i, $_ := ${arrayExpr}}}{{if ${condition}}}{{${v} = $i}}{{end}}{{end}}{{${v}}}`;
2203
+ }
2181
2204
  return null;
2182
2205
  }
2183
2206
  renderEverySomeTemplateBlock(expr, renderArray) {
@@ -2186,11 +2209,13 @@ ${goFields.join(`
2186
2209
  if (condition.includes("[UNSUPPORTED"))
2187
2210
  return null;
2188
2211
  if (expr.method === "every") {
2212
+ const v = `$bf_r${this.templateVarCounter++}`;
2189
2213
  const negated = this.negateGoCondition(condition);
2190
- return `{{$bf_result := true}}{{range ${arrayExpr}}}{{if ${negated}}}{{$bf_result = false}}{{break}}{{end}}{{end}}{{$bf_result}}`;
2214
+ return `{{${v} := true}}{{range ${arrayExpr}}}{{if ${negated}}}{{${v} = false}}{{break}}{{end}}{{end}}{{${v}}}`;
2191
2215
  }
2192
2216
  if (expr.method === "some") {
2193
- return `{{$bf_result := false}}{{range ${arrayExpr}}}{{if ${condition}}}{{$bf_result = true}}{{break}}{{end}}{{end}}{{$bf_result}}`;
2217
+ const v = `$bf_r${this.templateVarCounter++}`;
2218
+ return `{{${v} := false}}{{range ${arrayExpr}}}{{if ${condition}}}{{${v} = true}}{{break}}{{end}}{{end}}{{${v}}}`;
2194
2219
  }
2195
2220
  return null;
2196
2221
  }
@@ -2219,6 +2244,22 @@ ${goFields.join(`
2219
2244
  needsParens(expr) {
2220
2245
  return expr.kind === "logical" || expr.kind === "unary" || expr.kind === "conditional";
2221
2246
  }
2247
+ splitPreamble(rendered) {
2248
+ if (!rendered.includes("{{"))
2249
+ return null;
2250
+ const lastOpen = rendered.lastIndexOf("{{");
2251
+ const lastClose = rendered.lastIndexOf("}}");
2252
+ if (lastOpen >= 0 && lastClose > lastOpen) {
2253
+ const candidate = rendered.substring(lastOpen + 2, lastClose);
2254
+ if (!candidate.startsWith("$"))
2255
+ return null;
2256
+ return {
2257
+ preamble: rendered.substring(0, lastOpen),
2258
+ expr: candidate
2259
+ };
2260
+ }
2261
+ return null;
2262
+ }
2222
2263
  renderBlockBodyCondition(statements, param) {
2223
2264
  const localVarMap = new Map;
2224
2265
  const paths = this.collectReturnPaths(statements, [], localVarMap, param);
@@ -2339,7 +2380,7 @@ ${goFields.join(`
2339
2380
  return `"${expr.value}"`;
2340
2381
  }
2341
2382
  if (expr.literalType === "null") {
2342
- return '""';
2383
+ return "nil";
2343
2384
  }
2344
2385
  return String(expr.value);
2345
2386
  case "member": {
@@ -2616,138 +2657,141 @@ Options:
2616
2657
  });
2617
2658
  return { condition: `false`, preamble: "" };
2618
2659
  }
2619
- const rendered = this.renderConditionExpr(parsed);
2620
- if (rendered.startsWith("{{")) {
2621
- const lastOpen = rendered.lastIndexOf("{{");
2622
- const lastClose = rendered.lastIndexOf("}}");
2623
- if (lastOpen >= 0 && lastClose > lastOpen) {
2624
- const preamble = rendered.substring(0, lastOpen);
2625
- const condition = rendered.substring(lastOpen + 2, lastClose);
2626
- return { condition, preamble };
2627
- }
2628
- }
2629
- return { condition: rendered, preamble: "" };
2660
+ const { preamble, expr: condition } = this.renderConditionExpr(parsed);
2661
+ return { condition, preamble };
2630
2662
  }
2631
2663
  renderConditionExpr(expr) {
2664
+ const plain = (e) => ({ preamble: "", expr: e });
2632
2665
  switch (expr.kind) {
2633
2666
  case "identifier":
2634
2667
  {
2635
2668
  const currentLoopParam = this.loopParamStack[this.loopParamStack.length - 1];
2636
2669
  if (currentLoopParam && expr.name === currentLoopParam) {
2637
- return ".";
2670
+ return plain(".");
2671
+ }
2672
+ if (this.loopVarRefCount.has(expr.name)) {
2673
+ return plain(`$${expr.name}`);
2638
2674
  }
2639
2675
  }
2640
- return `.${this.capitalizeFieldName(expr.name)}`;
2676
+ return plain(`.${this.capitalizeFieldName(expr.name)}`);
2641
2677
  case "literal":
2642
- if (expr.literalType === "string") {
2643
- return `"${expr.value}"`;
2644
- }
2645
- if (expr.literalType === "null") {
2646
- return '""';
2647
- }
2648
- return String(expr.value);
2678
+ if (expr.literalType === "string")
2679
+ return plain(`"${expr.value}"`);
2680
+ if (expr.literalType === "null")
2681
+ return plain("nil");
2682
+ return plain(String(expr.value));
2649
2683
  case "call": {
2650
2684
  if (expr.callee.kind === "identifier" && expr.args.length === 0) {
2651
- return `.${this.capitalizeFieldName(expr.callee.name)}`;
2685
+ return plain(`.${this.capitalizeFieldName(expr.callee.name)}`);
2652
2686
  }
2653
- return this.renderParsedExpr(expr);
2687
+ return plain(this.renderParsedExpr(expr));
2654
2688
  }
2655
2689
  case "member": {
2656
2690
  if (expr.property === "length" && expr.object.kind === "higher-order") {
2657
- const result = this.renderFilterLengthExpr(expr.object, (e) => this.renderConditionExpr(e));
2658
- if (result) {
2659
- return result;
2660
- }
2691
+ const result = this.renderFilterLengthExpr(expr.object, (e) => this.renderConditionExpr(e).expr);
2692
+ if (result)
2693
+ return plain(result);
2661
2694
  }
2662
2695
  if (expr.object.kind === "identifier" && this.propsObjectName && expr.object.name === this.propsObjectName) {
2663
- return `.${this.capitalizeFieldName(expr.property)}`;
2696
+ return plain(`.${this.capitalizeFieldName(expr.property)}`);
2664
2697
  }
2665
2698
  {
2666
2699
  const currentLoopParam = this.loopParamStack[this.loopParamStack.length - 1];
2667
2700
  if (expr.object.kind === "identifier" && currentLoopParam && expr.object.name === currentLoopParam) {
2668
- return `.${this.capitalizeFieldName(expr.property)}`;
2701
+ return plain(`.${this.capitalizeFieldName(expr.property)}`);
2669
2702
  }
2670
2703
  }
2671
2704
  const obj = this.renderConditionExpr(expr.object);
2672
2705
  if (expr.property === "length") {
2673
- return `len ${obj}`;
2706
+ return { preamble: obj.preamble, expr: `len ${obj.expr}` };
2674
2707
  }
2675
- return `${obj}.${this.capitalizeFieldName(expr.property)}`;
2708
+ return { preamble: obj.preamble, expr: `${obj.expr}.${this.capitalizeFieldName(expr.property)}` };
2676
2709
  }
2677
2710
  case "binary": {
2678
2711
  const leftNeedsParens = this.needsParensInGoTemplate(expr.left);
2679
- let left = this.renderConditionExpr(expr.left);
2680
- if (leftNeedsParens) {
2681
- left = `(${left})`;
2682
- }
2712
+ const leftResult = this.renderConditionExpr(expr.left);
2713
+ const left = leftNeedsParens ? `(${leftResult.expr})` : leftResult.expr;
2683
2714
  const rightNeedsParens = this.needsParensInGoTemplate(expr.right);
2684
- let right = this.renderConditionExpr(expr.right);
2685
- if (rightNeedsParens) {
2686
- right = `(${right})`;
2687
- }
2715
+ const rightResult = this.renderConditionExpr(expr.right);
2716
+ const right = rightNeedsParens ? `(${rightResult.expr})` : rightResult.expr;
2717
+ const preamble = leftResult.preamble + rightResult.preamble;
2718
+ let result;
2688
2719
  switch (expr.op) {
2689
2720
  case "===":
2690
2721
  case "==":
2691
- return `eq ${left} ${right}`;
2722
+ result = `eq ${left} ${right}`;
2723
+ break;
2692
2724
  case "!==":
2693
2725
  case "!=":
2694
- return `ne ${left} ${right}`;
2726
+ result = `ne ${left} ${right}`;
2727
+ break;
2695
2728
  case ">":
2696
- return `gt ${left} ${right}`;
2729
+ result = `gt ${left} ${right}`;
2730
+ break;
2697
2731
  case "<":
2698
- return `lt ${left} ${right}`;
2732
+ result = `lt ${left} ${right}`;
2733
+ break;
2699
2734
  case ">=":
2700
- return `ge ${left} ${right}`;
2735
+ result = `ge ${left} ${right}`;
2736
+ break;
2701
2737
  case "<=":
2702
- return `le ${left} ${right}`;
2738
+ result = `le ${left} ${right}`;
2739
+ break;
2703
2740
  case "+":
2704
- return `bf_add ${left} ${right}`;
2741
+ result = `bf_add ${left} ${right}`;
2742
+ break;
2705
2743
  case "-":
2706
- return `bf_sub ${left} ${right}`;
2744
+ result = `bf_sub ${left} ${right}`;
2745
+ break;
2707
2746
  case "*":
2708
- return `bf_mul ${left} ${right}`;
2747
+ result = `bf_mul ${left} ${right}`;
2748
+ break;
2709
2749
  case "/":
2710
- return `bf_div ${left} ${right}`;
2750
+ result = `bf_div ${left} ${right}`;
2751
+ break;
2711
2752
  default:
2712
- return `${left} ${expr.op} ${right}`;
2753
+ result = `${left} ${expr.op} ${right}`;
2713
2754
  }
2755
+ return { preamble, expr: result };
2714
2756
  }
2715
2757
  case "unary": {
2716
2758
  const arg = this.renderConditionExpr(expr.argument);
2717
- if (expr.op === "!") {
2718
- return `not ${arg}`;
2719
- }
2720
- if (expr.op === "-") {
2721
- return `bf_neg ${arg}`;
2722
- }
2759
+ if (expr.op === "!")
2760
+ return { preamble: arg.preamble, expr: `not ${arg.expr}` };
2761
+ if (expr.op === "-")
2762
+ return { preamble: arg.preamble, expr: `bf_neg ${arg.expr}` };
2723
2763
  return arg;
2724
2764
  }
2725
2765
  case "logical": {
2726
- const left = this.renderConditionExpr(expr.left);
2727
- const right = this.renderConditionExpr(expr.right);
2728
- const wrapLeft = this.needsParens(expr.left) ? `(${left})` : left;
2729
- const wrapRight = this.needsParens(expr.right) ? `(${right})` : right;
2730
- if (expr.op === "&&") {
2731
- return `and ${wrapLeft} ${wrapRight}`;
2732
- }
2733
- return `or ${wrapLeft} ${wrapRight}`;
2766
+ const leftResult = this.renderConditionExpr(expr.left);
2767
+ const rightResult = this.renderConditionExpr(expr.right);
2768
+ const preamble = leftResult.preamble + rightResult.preamble;
2769
+ const wrapLeft = this.needsParens(expr.left) ? `(${leftResult.expr})` : leftResult.expr;
2770
+ const wrapRight = this.needsParens(expr.right) ? `(${rightResult.expr})` : rightResult.expr;
2771
+ const result = expr.op === "&&" ? `and ${wrapLeft} ${wrapRight}` : `or ${wrapLeft} ${wrapRight}`;
2772
+ return { preamble, expr: result };
2734
2773
  }
2735
2774
  case "conditional": {
2736
2775
  const test = this.renderConditionExpr(expr.test);
2737
2776
  return test;
2738
2777
  }
2739
2778
  case "template-literal":
2740
- return this.renderParsedExpr(expr);
2779
+ return plain(this.renderParsedExpr(expr));
2741
2780
  case "arrow-fn":
2742
- return "[ARROW-FN]";
2743
- case "higher-order":
2744
- return this.renderParsedExpr(expr);
2781
+ return plain("[ARROW-FN]");
2782
+ case "higher-order": {
2783
+ const rendered = this.renderParsedExpr(expr);
2784
+ const split = this.splitPreamble(rendered);
2785
+ if (split)
2786
+ return split;
2787
+ return plain(rendered);
2788
+ }
2745
2789
  case "array-literal":
2746
- return this.renderParsedExpr(expr);
2790
+ return plain(this.renderParsedExpr(expr));
2747
2791
  case "array-method":
2748
- return this.renderParsedExpr(expr);
2792
+ return plain(this.renderParsedExpr(expr));
2749
2793
  case "unsupported":
2750
- return expr.raw;
2794
+ return plain(expr.raw);
2751
2795
  }
2752
2796
  }
2753
2797
  renderLoop(loop) {
@@ -2770,14 +2814,38 @@ Options:
2770
2814
  }
2771
2815
  let goArray = this.convertExpressionToGo(loop.array);
2772
2816
  const param = loop.param;
2773
- const index = loop.index || "_";
2817
+ let index = loop.index || "_";
2818
+ let rangeIndex = index;
2819
+ let rangeValue = param;
2820
+ if (loop.iterationShape === "keys") {
2821
+ rangeIndex = param;
2822
+ rangeValue = "_";
2823
+ }
2774
2824
  const childComponent = this.findChildComponent(loop.children);
2775
2825
  if (childComponent) {
2776
2826
  goArray = `.${childComponent.name}s`;
2777
2827
  }
2778
2828
  this.inLoop = true;
2779
- this.loopParamStack.push(param);
2829
+ const addedLoopVars = [];
2830
+ if (loop.iterationShape === "keys") {
2831
+ this.loopParamStack.push("");
2832
+ this.loopVarRefCount.set(param, (this.loopVarRefCount.get(param) ?? 0) + 1);
2833
+ addedLoopVars.push(param);
2834
+ } else {
2835
+ this.loopParamStack.push(param);
2836
+ if (rangeIndex !== "_") {
2837
+ this.loopVarRefCount.set(rangeIndex, (this.loopVarRefCount.get(rangeIndex) ?? 0) + 1);
2838
+ addedLoopVars.push(rangeIndex);
2839
+ }
2840
+ }
2780
2841
  const children = this.renderChildren(loop.children);
2842
+ for (const v of addedLoopVars) {
2843
+ const rc = (this.loopVarRefCount.get(v) ?? 1) - 1;
2844
+ if (rc <= 0)
2845
+ this.loopVarRefCount.delete(v);
2846
+ else
2847
+ this.loopVarRefCount.set(v, rc);
2848
+ }
2781
2849
  this.loopParamStack.pop();
2782
2850
  this.inLoop = false;
2783
2851
  if (loop.sortComparator) {
@@ -2793,10 +2861,10 @@ Options:
2793
2861
  filterCond = "true";
2794
2862
  }
2795
2863
  const itemMarker2 = loop.bodyIsMultiRoot ? `{{bfComment "bf-loop-i"}}` : "";
2796
- return `{{bfComment "loop:${loop.markerId}"}}{{range $${index}, $${param} := ${goArray}}}{{if ${filterCond}}}${itemMarker2}${children}{{end}}{{end}}{{bfComment "/loop:${loop.markerId}"}}`;
2864
+ return `{{bfComment "loop:${loop.markerId}"}}{{range $${rangeIndex}, $${rangeValue} := ${goArray}}}{{if ${filterCond}}}${itemMarker2}${children}{{end}}{{end}}{{bfComment "/loop:${loop.markerId}"}}`;
2797
2865
  }
2798
2866
  const itemMarker = loop.bodyIsMultiRoot ? `{{bfComment "bf-loop-i"}}` : "";
2799
- return `{{bfComment "loop:${loop.markerId}"}}{{range $${index}, $${param} := ${goArray}}}${itemMarker}${children}{{end}}{{bfComment "/loop:${loop.markerId}"}}`;
2867
+ return `{{bfComment "loop:${loop.markerId}"}}{{range $${rangeIndex}, $${rangeValue} := ${goArray}}}${itemMarker}${children}{{end}}{{bfComment "/loop:${loop.markerId}"}}`;
2800
2868
  }
2801
2869
  findChildComponent(nodes) {
2802
2870
  for (const node of nodes) {