@barefootjs/go-template 0.31.8 → 0.31.10

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/index.js CHANGED
@@ -358,8 +358,13 @@ class CompileState {
358
358
  localTypeAliases = new Map;
359
359
  localStructFields = new Map;
360
360
  synthStructTypes = new Map;
361
+ synthObjectStructNames = new Map;
361
362
  needsStringsImport = false;
362
363
  }
364
+ function resolveSignalParsedThroughSeedPlan(state, signal) {
365
+ const step = state.ssrSeedPlan.steps.find((s) => s.kind === "derived" && s.origin === "signal" && s.name === signal.getter);
366
+ return step?.kind === "derived" ? step.parsed : signal.parsed;
367
+ }
363
368
 
364
369
  // src/adapter/analysis/component-tree.ts
365
370
  function hasClientInteractivity(ir) {
@@ -1024,8 +1029,10 @@ function typeInfoToGo(ctx, _typeInfo, defaultValue, preParsed) {
1024
1029
  return `[]${typeInfoToGo(ctx, typeInfo.elementType)}`;
1025
1030
  }
1026
1031
  return "[]interface{}";
1027
- case "object":
1028
- return "map[string]interface{}";
1032
+ case "object": {
1033
+ const synthName = ctx.state.synthObjectStructNames.get(typeInfo);
1034
+ return synthName ?? "map[string]interface{}";
1035
+ }
1029
1036
  case "interface":
1030
1037
  if (typeInfo.raw && (ctx.state.localStructFields.has(typeInfo.raw) || ctx.state.localTypeAliases.has(typeInfo.raw))) {
1031
1038
  return typeInfo.raw;
@@ -2583,11 +2590,11 @@ function buildPropTypeOverrides(ctx, ir) {
2583
2590
  if (!param)
2584
2591
  continue;
2585
2592
  const propGoType = typeInfoToGo(ctx, param.type, param.defaultValue, param.parsed);
2586
- if (propGoType.includes("interface{}")) {
2587
- const signalGoType = typeInfoToGo(ctx, signal.type, signal.initialValue, signal.parsed);
2588
- if (!signalGoType.includes("interface{}")) {
2589
- overrides.set(propName, signalGoType);
2590
- }
2593
+ const signalGoType = typeInfoToGo(ctx, signal.type, signal.initialValue, signal.parsed);
2594
+ if (signalGoType.includes("interface{}"))
2595
+ continue;
2596
+ if (propGoType.includes("interface{}") || signalGoType !== propGoType) {
2597
+ overrides.set(propName, signalGoType);
2591
2598
  }
2592
2599
  }
2593
2600
  }
@@ -2670,7 +2677,7 @@ function collectNullishConsumedPropNames(ctx, ir) {
2670
2677
  };
2671
2678
  walk(ir.root);
2672
2679
  for (const signal of ir.metadata.signals) {
2673
- const match = ctx.extractPropFallback(signal.initialValue, signal.parsed);
2680
+ const match = ctx.extractPropFallback(signal.initialValue, resolveSignalParsedThroughSeedPlan(ctx.state, signal));
2674
2681
  if (!match || !optionalParams.has(match.propName))
2675
2682
  continue;
2676
2683
  const f = match.goFallback;
@@ -2818,6 +2825,11 @@ function collectStringValueNames(ir) {
2818
2825
  }
2819
2826
 
2820
2827
  // src/adapter/go-template-adapter.ts
2828
+ var SYNTH_TYPE_LOC = {
2829
+ file: "<synthesized>",
2830
+ start: { line: 0, column: 0 },
2831
+ end: { line: 0, column: 0 }
2832
+ };
2821
2833
  var STRING_METHODS = new Set([
2822
2834
  "replace",
2823
2835
  "trim",
@@ -3179,6 +3191,7 @@ ${scriptRegistrations}${templateBody}
3179
3191
  const lines = [];
3180
3192
  const componentName = ir.metadata.componentName;
3181
3193
  this.buildLocalTypeTables(ir, componentName);
3194
+ this.emitSynthPropStructs(lines, ir, componentName);
3182
3195
  this.emitLocalTypeStructs(lines, ir, componentName);
3183
3196
  this.emitSynthStructs(lines, ir, componentName);
3184
3197
  const nestedComponents = findNestedComponents(ir.root);
@@ -3682,7 +3695,7 @@ ${goFields.join(`
3682
3695
  const fieldName = capitalizeFieldName(signal.getter);
3683
3696
  if (propFieldNames.has(fieldName))
3684
3697
  continue;
3685
- const fallbackMatch = this.extractPropFallback(signal.initialValue, signal.parsed);
3698
+ const fallbackMatch = this.extractPropFallback(signal.initialValue, this.resolvedSignalParsed(signal));
3686
3699
  const hoisted = fallbackMatch ? propFallbackVars.get(fallbackMatch.propName) : undefined;
3687
3700
  if (hoisted) {
3688
3701
  lines.push(` ${fieldName}: ${hoisted.varName},`);
@@ -4038,6 +4051,65 @@ ${goFields.join(`
4038
4051
  }
4039
4052
  }
4040
4053
  }
4054
+ emitSynthPropStructs(lines, ir, componentName) {
4055
+ this.state.synthObjectStructNames = new Map;
4056
+ this.state.currentTypeDefinitions = [...this.state.currentTypeDefinitions];
4057
+ const visitObject = (typeInfo, desiredName) => {
4058
+ if (this.state.synthObjectStructNames.has(typeInfo))
4059
+ return;
4060
+ if (this.state.localTypeNames.has(desiredName))
4061
+ return;
4062
+ this.state.localTypeNames.add(desiredName);
4063
+ this.state.synthObjectStructNames.set(typeInfo, desiredName);
4064
+ for (const prop of typeInfo.properties ?? []) {
4065
+ visit(prop.type, desiredName, prop.name);
4066
+ }
4067
+ const fields = this.structFieldsFor(typeInfo);
4068
+ this.state.localStructFields.set(desiredName, new Map(fields.map((f) => [f.tsName, f.goName])));
4069
+ this.state.currentTypeDefinitions.push({
4070
+ kind: "type",
4071
+ name: desiredName,
4072
+ definition: "",
4073
+ properties: typeInfo.properties ?? [],
4074
+ loc: SYNTH_TYPE_LOC
4075
+ });
4076
+ const goFields = fields.map((f) => ` ${f.goName} ${f.goType} \`json:"${this.toJsonTag(f.tsName)}"\``);
4077
+ lines.push(`// ${desiredName} is a synthesised type for an anonymous object type (#2674).`);
4078
+ lines.push(`type ${desiredName} struct {
4079
+ ${goFields.join(`
4080
+ `)}
4081
+ }`);
4082
+ lines.push("");
4083
+ };
4084
+ const visitArrayElem = (elemType, parentName, propName) => {
4085
+ if (!elemType)
4086
+ return;
4087
+ if (elemType.kind === "array") {
4088
+ visitArrayElem(elemType.elementType, parentName, propName);
4089
+ } else if (elemType.kind === "object") {
4090
+ visitObject(elemType, `${parentName}${goFieldNameForKey(propName)}Item`);
4091
+ }
4092
+ };
4093
+ const visit = (typeInfo, parentName, propName) => {
4094
+ if (typeInfo.kind === "array") {
4095
+ visitArrayElem(typeInfo.elementType, parentName, propName);
4096
+ } else if (typeInfo.kind === "object") {
4097
+ visitObject(typeInfo, `${parentName}${goFieldNameForKey(propName)}`);
4098
+ }
4099
+ };
4100
+ for (const td of ir.metadata.typeDefinitions) {
4101
+ if (td.name === "Props" || td.name === `${componentName}Props`)
4102
+ continue;
4103
+ if (td.name.endsWith("Props"))
4104
+ continue;
4105
+ for (const prop of td.properties ?? []) {
4106
+ visit(prop.type, td.name, prop.name);
4107
+ }
4108
+ }
4109
+ for (const param of ir.metadata.propsParams) {
4110
+ visit(param.type, componentName, param.name);
4111
+ }
4112
+ }
4041
4113
  emitLocalTypeStructs(lines, ir, componentName) {
4042
4114
  for (const td of ir.metadata.typeDefinitions) {
4043
4115
  if (td.name === "Props" || td.name === `${componentName}Props`)
@@ -4121,7 +4193,7 @@ ${goFields.join(`
4121
4193
  emitPropsStructHeader(lines, ir, propsTypeName, componentName) {
4122
4194
  lines.push(`// ${propsTypeName} is the props type for the ${componentName} component.`);
4123
4195
  lines.push(`type ${propsTypeName} struct {`);
4124
- lines.push('\tScopeID string `json:"scopeID"`');
4196
+ lines.push('\tScopeID string `json:"-"`');
4125
4197
  lines.push('\tBfIsRoot bool `json:"-"`');
4126
4198
  lines.push('\tBfIsChild bool `json:"-"`');
4127
4199
  lines.push('\tBfParent string `json:"-"`');
@@ -4151,7 +4223,7 @@ ${goFields.join(`
4151
4223
  const fieldName = capitalizeFieldName(signal.getter);
4152
4224
  if (propFieldNames.has(fieldName))
4153
4225
  continue;
4154
- const jsonTag = this.claimJsonTag(this.toJsonTag(signal.getter), takenJsonTags);
4226
+ const jsonTag = "-";
4155
4227
  const synthType = this.state.synthStructTypes.get(signal.getter);
4156
4228
  if (synthType) {
4157
4229
  lines.push(` ${fieldName} ${typeInfoToGo(this.emitCtx, synthType)} \`json:"${jsonTag}"\``);
@@ -4183,7 +4255,7 @@ ${goFields.join(`
4183
4255
  const fieldName = capitalizeFieldName(memo.name);
4184
4256
  if (propFieldNames.has(fieldName))
4185
4257
  continue;
4186
- const jsonTag = this.claimJsonTag(this.toJsonTag(memo.name), takenJsonTags);
4258
+ const jsonTag = "-";
4187
4259
  const goType = this.inferMemoType(memo, ir.metadata.signals, propsParamMap);
4188
4260
  lines.push(` ${fieldName} ${goType} \`json:"${jsonTag}"\``);
4189
4261
  }
@@ -4203,15 +4275,22 @@ ${goFields.join(`
4203
4275
  ...ir.metadata.memos.map((m) => capitalizeFieldName(m.name))
4204
4276
  ]);
4205
4277
  for (const c of this.nonCollidingContextConsumers(takenProps)) {
4206
- const jsonTag = this.claimJsonTag(this.toJsonTag(c.localName), takenJsonTags);
4278
+ const jsonTag = "-";
4207
4279
  lines.push(` ${this.contextFieldName(c)} ${this.contextConsumerGoType(c)} \`json:"${jsonTag}"\``);
4208
4280
  }
4281
+ const propDrivingFieldNames = new Set;
4282
+ for (const p of ir.metadata.propsParams) {
4283
+ propDrivingFieldNames.add(capitalizeFieldName(p.name));
4284
+ propDrivingFieldNames.add(capitalizeFieldName(p.sourceName ?? p.name));
4285
+ }
4209
4286
  for (const nested of nestedComponents) {
4210
4287
  if (this.isOrphanedClientOnlyNested(nested))
4211
4288
  continue;
4212
4289
  const elemType = nested.bodyChildren?.length ? this.loopBodyWrapperName(componentName, nested) : `${nested.name}Props`;
4213
4290
  if (nested.isDynamic && !nested.isPropDerived) {
4214
4291
  lines.push(` ${nested.name}s []${elemType} \`json:"-"\``);
4292
+ } else if (nested.isDynamic && nested.isPropDerived && !propDrivingFieldNames.has(`${nested.name}s`)) {
4293
+ lines.push(` ${nested.name}s []${elemType} \`json:"-"\``);
4215
4294
  } else {
4216
4295
  const jsonTag = this.claimJsonTag(this.toJsonTag(`${nested.name.charAt(0).toLowerCase()}${nested.name.slice(1)}s`), takenJsonTags);
4217
4296
  lines.push(` ${nested.name}s []${elemType} \`json:"${jsonTag}"\``);
@@ -4222,7 +4301,7 @@ ${goFields.join(`
4222
4301
  lines.push(` ${child.fieldName} ${child.name}Props \`json:"-"\``);
4223
4302
  }
4224
4303
  for (const slot of spreadSlots) {
4225
- const jsonTag = this.claimJsonTag(this.toJsonTag(slot.slotId), takenJsonTags);
4304
+ const jsonTag = "-";
4226
4305
  lines.push(` ${slot.slotId} map[string]any \`json:"${jsonTag}"\``);
4227
4306
  }
4228
4307
  }
@@ -4535,7 +4614,7 @@ ${goFields.join(`
4535
4614
  }
4536
4615
  const propTypeOverrides = buildPropTypeOverrides(this.emitCtx, ir);
4537
4616
  for (const signal of ir.metadata.signals) {
4538
- const match = this.extractPropFallback(signal.initialValue, signal.parsed);
4617
+ const match = this.extractPropFallback(signal.initialValue, this.resolvedSignalParsed(signal));
4539
4618
  if (!match)
4540
4619
  continue;
4541
4620
  if (result.has(match.propName))
@@ -4579,6 +4658,9 @@ ${goFields.join(`
4579
4658
  }
4580
4659
  return result;
4581
4660
  }
4661
+ resolvedSignalParsed(signal) {
4662
+ return resolveSignalParsedThroughSeedPlan(this.state, signal);
4663
+ }
4582
4664
  extractPropFallback(initialValue, preParsed) {
4583
4665
  const structural = preParsed ? this.extractPropFallbackFromParsed(preParsed) : null;
4584
4666
  if (structural)
@@ -6676,7 +6758,8 @@ var conformancePins = {
6676
6758
  };
6677
6759
  // src/render-divergences.ts
6678
6760
  var renderDivergences = {
6679
- "static-array-from-props-with-component-precomputed": "prop-backed child-component loop renders the loop host empty at SSR (https://github.com/piconic-ai/barefootjs/issues/2630)"
6761
+ "signal-prop-same-name-derived": "self-derived signal collides with its prop field name in the generated Go props struct — the non-idempotent `* 2` derivation is dropped and the signal renders the raw prop value instead (https://github.com/piconic-ai/barefootjs/issues/2683)",
6762
+ "signal-prop-same-name-via-const-derived": "self-derived signal (reached through a component-scope const) collides with its prop field name in the generated Go props struct — the non-idempotent `* 2` derivation is dropped and the signal renders the raw prop value instead (https://github.com/piconic-ai/barefootjs/issues/2683)"
6680
6763
  };
6681
6764
  export {
6682
6765
  renderDivergences,
@@ -5,6 +5,14 @@
5
5
  * one object, so the skip list and the declaration can't drift. Keep the
6
6
  * file even when the set is empty — the next divergence lands here, not in
7
7
  * a re-created file.
8
+ *
9
+ * (#2630's `static-array-from-props-with-component-precomputed` divergence
10
+ * graduated once the harness (`test-render.ts`'s
11
+ * `buildDynamicChildLoopSeeding`, despite the name — see its doc comment)
12
+ * learned to seed a prop-backed static child-component loop's Props slice
13
+ * the same way it already seeded a signal-backed dynamic one: the adapter's
14
+ * own `emission` was never the bug, only this harness's route-handler
15
+ * stand-in was missing the prop-derived case.)
8
16
  */
9
17
  import type { RenderDivergences } from '@barefootjs/jsx';
10
18
  export declare const renderDivergences: RenderDivergences;
@@ -1 +1 @@
1
- {"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAExD,eAAO,MAAM,iBAAiB,EAAE,iBAM/B,CAAA"}
1
+ {"version":3,"file":"render-divergences.d.ts","sourceRoot":"","sources":["../src/render-divergences.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAExD,eAAO,MAAM,iBAAiB,EAAE,iBAwB/B,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"test-render.d.ts","sourceRoot":"","sources":["../src/test-render.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,eAAe,EAA2B,MAAM,iBAAiB,CAAA;AAY/E,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAgCD,MAAM,WAAW,aAAa;IAC5B,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,8BAA8B;IAC9B,OAAO,EAAE,eAAe,CAAA;IACxB,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACzC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,wBAAsB,yBAAyB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAqWvF"}
1
+ {"version":3,"file":"test-render.d.ts","sourceRoot":"","sources":["../src/test-render.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,eAAe,EAA2B,MAAM,iBAAiB,CAAA;AAY/E,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAgCD,MAAM,WAAW,aAAa;IAC5B,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,8BAA8B;IAC9B,OAAO,EAAE,eAAe,CAAA;IACxB,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACzC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,wBAAsB,yBAAyB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA2WvF"}
package/dist/vite.js CHANGED
@@ -3095,6 +3095,34 @@ var SVG_ROOT_TAGS = new Set([
3095
3095
  "animateTransform",
3096
3096
  "animateMotion"
3097
3097
  ]);
3098
+ var MATHML_ROOT_TAGS = new Set([
3099
+ "math",
3100
+ "mrow",
3101
+ "mfrac",
3102
+ "msup",
3103
+ "msub",
3104
+ "msubsup",
3105
+ "mn",
3106
+ "mi",
3107
+ "mo",
3108
+ "mtext",
3109
+ "munder",
3110
+ "mover",
3111
+ "munderover",
3112
+ "mtable",
3113
+ "mtr",
3114
+ "mtd",
3115
+ "msqrt",
3116
+ "mroot",
3117
+ "mstyle",
3118
+ "merror",
3119
+ "mpadded",
3120
+ "mphantom",
3121
+ "menclose",
3122
+ "semantics",
3123
+ "annotation",
3124
+ "annotation-xml"
3125
+ ]);
3098
3126
 
3099
3127
  // ../jsx/src/ir-to-client-js/collect-elements.ts
3100
3128
  var EMPTY_RENDER_EXPRS = new Set(["null", "undefined", "false", "''", '""', "``"]);
@@ -3901,6 +3929,38 @@ function classify(name, origin, expr, parsed, available) {
3901
3929
  }
3902
3930
  return { kind: "derived", name, origin, expr, parsed, frees: [...frees] };
3903
3931
  }
3932
+ function localConstExprsByName(metadata) {
3933
+ const out = new Map;
3934
+ for (const c of metadata.localConstants ?? []) {
3935
+ if (c.isModule || c.declarationKind !== "const" || c.value === undefined)
3936
+ continue;
3937
+ out.set(c.name, c.parsed ?? parseExpression(c.value.trim()));
3938
+ }
3939
+ return out;
3940
+ }
3941
+ function resolveThroughLocalConsts(parsed, localConsts) {
3942
+ let current = parsed;
3943
+ const maxIter = localConsts.size + 1;
3944
+ for (let i = 0;i < maxIter; i++) {
3945
+ const frees = freeIdentifiers(current);
3946
+ if (frees === null)
3947
+ break;
3948
+ let changed = false;
3949
+ for (const name of frees) {
3950
+ const value = localConsts.get(name);
3951
+ if (!value)
3952
+ continue;
3953
+ const inlined = inlineBinding(current, name, value);
3954
+ if (inlined === null)
3955
+ continue;
3956
+ current = inlined;
3957
+ changed = true;
3958
+ }
3959
+ if (!changed)
3960
+ break;
3961
+ }
3962
+ return current;
3963
+ }
3904
3964
  function computeSsrSeedPlan(metadata) {
3905
3965
  const baseScope = metadata.propsParams.map((p) => p.name);
3906
3966
  if (metadata.propsObjectName)
@@ -3909,6 +3969,7 @@ function computeSsrSeedPlan(metadata) {
3909
3969
  baseScope.push(name);
3910
3970
  }
3911
3971
  const available = new Set(baseScope);
3972
+ const localConsts = localConstExprsByName(metadata);
3912
3973
  const steps = [];
3913
3974
  for (const signal of metadata.signals) {
3914
3975
  if (signal.envReader) {
@@ -3920,13 +3981,13 @@ function computeSsrSeedPlan(metadata) {
3920
3981
  }
3921
3982
  }
3922
3983
  const expr = signal.initialValue.trim();
3923
- steps.push(expr === "" ? { kind: "opaque", name: signal.getter, origin: "signal" } : classify(signal.getter, "signal", expr, parseExpression(expr), available));
3984
+ steps.push(expr === "" ? { kind: "opaque", name: signal.getter, origin: "signal" } : classify(signal.getter, "signal", expr, resolveThroughLocalConsts(parseExpression(expr), localConsts), available));
3924
3985
  available.add(signal.getter);
3925
3986
  }
3926
3987
  for (const memo of metadata.memos) {
3927
3988
  const body = extractArrowBodyExpression(memo.computation);
3928
3989
  const expr = body?.trim() ?? "";
3929
- steps.push(expr === "" ? { kind: "opaque", name: memo.name, origin: "memo" } : classify(memo.name, "memo", expr, memo.parsed ?? parseExpression(expr), available));
3990
+ steps.push(expr === "" ? { kind: "opaque", name: memo.name, origin: "memo" } : classify(memo.name, "memo", expr, resolveThroughLocalConsts(memo.parsed ?? parseExpression(expr), localConsts), available));
3930
3991
  available.add(memo.name);
3931
3992
  }
3932
3993
  return { baseScope, steps };
@@ -5427,8 +5488,13 @@ class CompileState {
5427
5488
  localTypeAliases = new Map;
5428
5489
  localStructFields = new Map;
5429
5490
  synthStructTypes = new Map;
5491
+ synthObjectStructNames = new Map;
5430
5492
  needsStringsImport = false;
5431
5493
  }
5494
+ function resolveSignalParsedThroughSeedPlan(state, signal) {
5495
+ const step = state.ssrSeedPlan.steps.find((s) => s.kind === "derived" && s.origin === "signal" && s.name === signal.getter);
5496
+ return step?.kind === "derived" ? step.parsed : signal.parsed;
5497
+ }
5432
5498
 
5433
5499
  // src/adapter/analysis/component-tree.ts
5434
5500
  function hasClientInteractivity(ir) {
@@ -6075,8 +6141,10 @@ function typeInfoToGo(ctx, _typeInfo, defaultValue, preParsed) {
6075
6141
  return `[]${typeInfoToGo(ctx, typeInfo.elementType)}`;
6076
6142
  }
6077
6143
  return "[]interface{}";
6078
- case "object":
6079
- return "map[string]interface{}";
6144
+ case "object": {
6145
+ const synthName = ctx.state.synthObjectStructNames.get(typeInfo);
6146
+ return synthName ?? "map[string]interface{}";
6147
+ }
6080
6148
  case "interface":
6081
6149
  if (typeInfo.raw && (ctx.state.localStructFields.has(typeInfo.raw) || ctx.state.localTypeAliases.has(typeInfo.raw))) {
6082
6150
  return typeInfo.raw;
@@ -7622,11 +7690,11 @@ function buildPropTypeOverrides(ctx, ir) {
7622
7690
  if (!param)
7623
7691
  continue;
7624
7692
  const propGoType = typeInfoToGo(ctx, param.type, param.defaultValue, param.parsed);
7625
- if (propGoType.includes("interface{}")) {
7626
- const signalGoType = typeInfoToGo(ctx, signal.type, signal.initialValue, signal.parsed);
7627
- if (!signalGoType.includes("interface{}")) {
7628
- overrides.set(propName, signalGoType);
7629
- }
7693
+ const signalGoType = typeInfoToGo(ctx, signal.type, signal.initialValue, signal.parsed);
7694
+ if (signalGoType.includes("interface{}"))
7695
+ continue;
7696
+ if (propGoType.includes("interface{}") || signalGoType !== propGoType) {
7697
+ overrides.set(propName, signalGoType);
7630
7698
  }
7631
7699
  }
7632
7700
  }
@@ -7709,7 +7777,7 @@ function collectNullishConsumedPropNames(ctx, ir) {
7709
7777
  };
7710
7778
  walk(ir.root);
7711
7779
  for (const signal of ir.metadata.signals) {
7712
- const match = ctx.extractPropFallback(signal.initialValue, signal.parsed);
7780
+ const match = ctx.extractPropFallback(signal.initialValue, resolveSignalParsedThroughSeedPlan(ctx.state, signal));
7713
7781
  if (!match || !optionalParams.has(match.propName))
7714
7782
  continue;
7715
7783
  const f = match.goFallback;
@@ -7856,6 +7924,11 @@ function collectStringValueNames(ir) {
7856
7924
  }
7857
7925
 
7858
7926
  // src/adapter/go-template-adapter.ts
7927
+ var SYNTH_TYPE_LOC = {
7928
+ file: "<synthesized>",
7929
+ start: { line: 0, column: 0 },
7930
+ end: { line: 0, column: 0 }
7931
+ };
7859
7932
  var STRING_METHODS = new Set([
7860
7933
  "replace",
7861
7934
  "trim",
@@ -8217,6 +8290,7 @@ ${scriptRegistrations}${templateBody}
8217
8290
  const lines = [];
8218
8291
  const componentName = ir.metadata.componentName;
8219
8292
  this.buildLocalTypeTables(ir, componentName);
8293
+ this.emitSynthPropStructs(lines, ir, componentName);
8220
8294
  this.emitLocalTypeStructs(lines, ir, componentName);
8221
8295
  this.emitSynthStructs(lines, ir, componentName);
8222
8296
  const nestedComponents = findNestedComponents(ir.root);
@@ -8720,7 +8794,7 @@ ${goFields.join(`
8720
8794
  const fieldName = capitalizeFieldName(signal.getter);
8721
8795
  if (propFieldNames.has(fieldName))
8722
8796
  continue;
8723
- const fallbackMatch = this.extractPropFallback(signal.initialValue, signal.parsed);
8797
+ const fallbackMatch = this.extractPropFallback(signal.initialValue, this.resolvedSignalParsed(signal));
8724
8798
  const hoisted = fallbackMatch ? propFallbackVars.get(fallbackMatch.propName) : undefined;
8725
8799
  if (hoisted) {
8726
8800
  lines.push(` ${fieldName}: ${hoisted.varName},`);
@@ -9076,6 +9150,65 @@ ${goFields.join(`
9076
9150
  }
9077
9151
  }
9078
9152
  }
9153
+ emitSynthPropStructs(lines, ir, componentName) {
9154
+ this.state.synthObjectStructNames = new Map;
9155
+ this.state.currentTypeDefinitions = [...this.state.currentTypeDefinitions];
9156
+ const visitObject = (typeInfo, desiredName) => {
9157
+ if (this.state.synthObjectStructNames.has(typeInfo))
9158
+ return;
9159
+ if (this.state.localTypeNames.has(desiredName))
9160
+ return;
9161
+ this.state.localTypeNames.add(desiredName);
9162
+ this.state.synthObjectStructNames.set(typeInfo, desiredName);
9163
+ for (const prop of typeInfo.properties ?? []) {
9164
+ visit(prop.type, desiredName, prop.name);
9165
+ }
9166
+ const fields = this.structFieldsFor(typeInfo);
9167
+ this.state.localStructFields.set(desiredName, new Map(fields.map((f) => [f.tsName, f.goName])));
9168
+ this.state.currentTypeDefinitions.push({
9169
+ kind: "type",
9170
+ name: desiredName,
9171
+ definition: "",
9172
+ properties: typeInfo.properties ?? [],
9173
+ loc: SYNTH_TYPE_LOC
9174
+ });
9175
+ const goFields = fields.map((f) => ` ${f.goName} ${f.goType} \`json:"${this.toJsonTag(f.tsName)}"\``);
9176
+ lines.push(`// ${desiredName} is a synthesised type for an anonymous object type (#2674).`);
9177
+ lines.push(`type ${desiredName} struct {
9178
+ ${goFields.join(`
9179
+ `)}
9180
+ }`);
9181
+ lines.push("");
9182
+ };
9183
+ const visitArrayElem = (elemType, parentName, propName) => {
9184
+ if (!elemType)
9185
+ return;
9186
+ if (elemType.kind === "array") {
9187
+ visitArrayElem(elemType.elementType, parentName, propName);
9188
+ } else if (elemType.kind === "object") {
9189
+ visitObject(elemType, `${parentName}${goFieldNameForKey(propName)}Item`);
9190
+ }
9191
+ };
9192
+ const visit = (typeInfo, parentName, propName) => {
9193
+ if (typeInfo.kind === "array") {
9194
+ visitArrayElem(typeInfo.elementType, parentName, propName);
9195
+ } else if (typeInfo.kind === "object") {
9196
+ visitObject(typeInfo, `${parentName}${goFieldNameForKey(propName)}`);
9197
+ }
9198
+ };
9199
+ for (const td of ir.metadata.typeDefinitions) {
9200
+ if (td.name === "Props" || td.name === `${componentName}Props`)
9201
+ continue;
9202
+ if (td.name.endsWith("Props"))
9203
+ continue;
9204
+ for (const prop of td.properties ?? []) {
9205
+ visit(prop.type, td.name, prop.name);
9206
+ }
9207
+ }
9208
+ for (const param of ir.metadata.propsParams) {
9209
+ visit(param.type, componentName, param.name);
9210
+ }
9211
+ }
9079
9212
  emitLocalTypeStructs(lines, ir, componentName) {
9080
9213
  for (const td of ir.metadata.typeDefinitions) {
9081
9214
  if (td.name === "Props" || td.name === `${componentName}Props`)
@@ -9159,7 +9292,7 @@ ${goFields.join(`
9159
9292
  emitPropsStructHeader(lines, ir, propsTypeName, componentName) {
9160
9293
  lines.push(`// ${propsTypeName} is the props type for the ${componentName} component.`);
9161
9294
  lines.push(`type ${propsTypeName} struct {`);
9162
- lines.push('\tScopeID string `json:"scopeID"`');
9295
+ lines.push('\tScopeID string `json:"-"`');
9163
9296
  lines.push('\tBfIsRoot bool `json:"-"`');
9164
9297
  lines.push('\tBfIsChild bool `json:"-"`');
9165
9298
  lines.push('\tBfParent string `json:"-"`');
@@ -9189,7 +9322,7 @@ ${goFields.join(`
9189
9322
  const fieldName = capitalizeFieldName(signal.getter);
9190
9323
  if (propFieldNames.has(fieldName))
9191
9324
  continue;
9192
- const jsonTag = this.claimJsonTag(this.toJsonTag(signal.getter), takenJsonTags);
9325
+ const jsonTag = "-";
9193
9326
  const synthType = this.state.synthStructTypes.get(signal.getter);
9194
9327
  if (synthType) {
9195
9328
  lines.push(` ${fieldName} ${typeInfoToGo(this.emitCtx, synthType)} \`json:"${jsonTag}"\``);
@@ -9221,7 +9354,7 @@ ${goFields.join(`
9221
9354
  const fieldName = capitalizeFieldName(memo.name);
9222
9355
  if (propFieldNames.has(fieldName))
9223
9356
  continue;
9224
- const jsonTag = this.claimJsonTag(this.toJsonTag(memo.name), takenJsonTags);
9357
+ const jsonTag = "-";
9225
9358
  const goType = this.inferMemoType(memo, ir.metadata.signals, propsParamMap);
9226
9359
  lines.push(` ${fieldName} ${goType} \`json:"${jsonTag}"\``);
9227
9360
  }
@@ -9241,15 +9374,22 @@ ${goFields.join(`
9241
9374
  ...ir.metadata.memos.map((m) => capitalizeFieldName(m.name))
9242
9375
  ]);
9243
9376
  for (const c of this.nonCollidingContextConsumers(takenProps)) {
9244
- const jsonTag = this.claimJsonTag(this.toJsonTag(c.localName), takenJsonTags);
9377
+ const jsonTag = "-";
9245
9378
  lines.push(` ${this.contextFieldName(c)} ${this.contextConsumerGoType(c)} \`json:"${jsonTag}"\``);
9246
9379
  }
9380
+ const propDrivingFieldNames = new Set;
9381
+ for (const p of ir.metadata.propsParams) {
9382
+ propDrivingFieldNames.add(capitalizeFieldName(p.name));
9383
+ propDrivingFieldNames.add(capitalizeFieldName(p.sourceName ?? p.name));
9384
+ }
9247
9385
  for (const nested of nestedComponents) {
9248
9386
  if (this.isOrphanedClientOnlyNested(nested))
9249
9387
  continue;
9250
9388
  const elemType = nested.bodyChildren?.length ? this.loopBodyWrapperName(componentName, nested) : `${nested.name}Props`;
9251
9389
  if (nested.isDynamic && !nested.isPropDerived) {
9252
9390
  lines.push(` ${nested.name}s []${elemType} \`json:"-"\``);
9391
+ } else if (nested.isDynamic && nested.isPropDerived && !propDrivingFieldNames.has(`${nested.name}s`)) {
9392
+ lines.push(` ${nested.name}s []${elemType} \`json:"-"\``);
9253
9393
  } else {
9254
9394
  const jsonTag = this.claimJsonTag(this.toJsonTag(`${nested.name.charAt(0).toLowerCase()}${nested.name.slice(1)}s`), takenJsonTags);
9255
9395
  lines.push(` ${nested.name}s []${elemType} \`json:"${jsonTag}"\``);
@@ -9260,7 +9400,7 @@ ${goFields.join(`
9260
9400
  lines.push(` ${child.fieldName} ${child.name}Props \`json:"-"\``);
9261
9401
  }
9262
9402
  for (const slot of spreadSlots) {
9263
- const jsonTag = this.claimJsonTag(this.toJsonTag(slot.slotId), takenJsonTags);
9403
+ const jsonTag = "-";
9264
9404
  lines.push(` ${slot.slotId} map[string]any \`json:"${jsonTag}"\``);
9265
9405
  }
9266
9406
  }
@@ -9573,7 +9713,7 @@ ${goFields.join(`
9573
9713
  }
9574
9714
  const propTypeOverrides = buildPropTypeOverrides(this.emitCtx, ir);
9575
9715
  for (const signal of ir.metadata.signals) {
9576
- const match = this.extractPropFallback(signal.initialValue, signal.parsed);
9716
+ const match = this.extractPropFallback(signal.initialValue, this.resolvedSignalParsed(signal));
9577
9717
  if (!match)
9578
9718
  continue;
9579
9719
  if (result.has(match.propName))
@@ -9617,6 +9757,9 @@ ${goFields.join(`
9617
9757
  }
9618
9758
  return result;
9619
9759
  }
9760
+ resolvedSignalParsed(signal) {
9761
+ return resolveSignalParsedThroughSeedPlan(this.state, signal);
9762
+ }
9620
9763
  extractPropFallback(initialValue, preParsed) {
9621
9764
  const structural = preParsed ? this.extractPropFallbackFromParsed(preParsed) : null;
9622
9765
  if (structural)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/go-template",
3
- "version": "0.31.8",
3
+ "version": "0.31.10",
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.31.8"
52
+ "@barefootjs/shared": "0.31.10"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "@barefootjs/jsx": ">=0.2.0",
@@ -67,9 +67,9 @@
67
67
  },
68
68
  "devDependencies": {
69
69
  "@barefootjs/adapter-tests": "0.1.0",
70
- "@barefootjs/client": "0.31.8",
71
- "@barefootjs/jsx": "0.31.8",
72
- "@barefootjs/vite": "0.31.8",
70
+ "@barefootjs/client": "0.31.10",
71
+ "@barefootjs/jsx": "0.31.10",
72
+ "@barefootjs/vite": "0.31.10",
73
73
  "vite": "^6.0.0"
74
74
  }
75
75
  }