@barefootjs/go-template 0.7.0 → 0.8.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.
@@ -123,6 +123,20 @@ export declare class GoTemplateAdapter extends BaseAdapter implements ParsedExpr
123
123
  * indexed lookups / memos / signals are deliberately excluded.
124
124
  */
125
125
  private moduleStringConsts;
126
+ /**
127
+ * Set of prop NAMES whose resolved Go struct-field type is exactly
128
+ * `interface{}` — i.e. nillable. Populated at `generate()` entry from
129
+ * the SAME per-prop Go-type computation `generatePropsStruct` /
130
+ * `generateInputStruct` use (`propTypeOverrides` + `typeInfoToGo`), so
131
+ * it can't drift from the actual field types. Used by
132
+ * `elementAttrEmitter.emitExpression` to omit a dynamic attribute whose
133
+ * value is a bare reference to a nillable prop when that prop is nil
134
+ * (Hono-style nullish-attribute omission: an `undefined`-valued
135
+ * attribute is dropped rather than rendered as `attr=""`). Concrete
136
+ * (`string`/`int`/`bool`) fields are never in this set and always emit
137
+ * unconditionally, matching Hono's `value=""` / `data-count="0"`.
138
+ */
139
+ private nillablePropNames;
126
140
  constructor(options?: GoTemplateAdapterOptions);
127
141
  /**
128
142
  * Generate template output for a component.
@@ -233,6 +247,24 @@ export declare class GoTemplateAdapter extends BaseAdapter implements ParsedExpr
233
247
  * the signal's type annotation may be more specific than the prop's TypeInfo.
234
248
  */
235
249
  private buildPropTypeOverrides;
250
+ /**
251
+ * Resolve a prop param's Go struct-field type using the SAME logic
252
+ * `generatePropsStruct` / `generateInputStruct` use for the field
253
+ * declaration: a `propTypeOverrides` entry (signal-inferred override)
254
+ * wins, otherwise `typeInfoToGo(param.type, param.defaultValue)`.
255
+ * Factored out so the nillable-field set (`collectNillablePropNames`)
256
+ * can't drift from the actual emitted field types.
257
+ */
258
+ private resolvePropGoType;
259
+ /**
260
+ * Build the set of prop NAMES whose resolved Go field type is exactly
261
+ * `interface{}` (nillable). Uses the same `propTypeOverrides` +
262
+ * `resolvePropGoType` pipeline as the struct generators, so a prop
263
+ * that ends up `interface{}` on the Props struct — and only such a
264
+ * prop — is treated as nillable for Hono-style attribute omission.
265
+ * Concrete (`string`/`int`/`bool`/`[]T`/struct) types are excluded.
266
+ */
267
+ private collectNillablePropNames;
236
268
  /**
237
269
  * Generate Input struct for a component
238
270
  */
@@ -354,6 +386,54 @@ export declare class GoTemplateAdapter extends BaseAdapter implements ParsedExpr
354
386
  * narrowed BF101 with the offending expression.
355
387
  */
356
388
  private buildSpreadInitializer;
389
+ /**
390
+ * Lower a conditional inline-object spread bag value:
391
+ * `(COND ? { 'aria-describedby': describedBy } : {})`
392
+ * into an immediately-invoked Go func literal that conditionally
393
+ * builds the map (so the falsy branch OMITS the key rather than
394
+ * rendering it as an empty string, which `SpreadAttrs` does not
395
+ * filter):
396
+ *
397
+ * func() map[string]any {
398
+ * if in.DescribedBy != nil && in.DescribedBy != "" {
399
+ * return map[string]any{"aria-describedby": in.DescribedBy}
400
+ * }
401
+ * return map[string]any{}
402
+ * }()
403
+ *
404
+ * Returns:
405
+ * - `undefined` when the expression is NOT a parenthesized ternary
406
+ * of object literals — the caller falls through to other shapes.
407
+ * - `null` when it IS that shape but a part can't be faithfully
408
+ * converted (non-static key, unsupported condition, …) — the
409
+ * caller raises BF101.
410
+ * - the Go IIFE string when fully convertible.
411
+ */
412
+ private buildConditionalSpreadInitializer;
413
+ /** Strip redundant parenthesised wrappers off a TS expression. */
414
+ private unwrapParens;
415
+ /**
416
+ * Convert a conditional-spread condition expression to a Go bool in
417
+ * the `in.` context. Supports a bare prop identifier (`describedBy`)
418
+ * and its negation (`!describedBy`), type-aware on the prop:
419
+ * string → `in.X != ""`
420
+ * boolean → `in.X`
421
+ * number → `in.X != 0`
422
+ * unknown / interface{} → `in.X != nil && in.X != ""`
423
+ * (faithful JS string-truthiness for an interface holding a
424
+ * string — textarea's `describedBy` resolves to interface{}).
425
+ * Returns null for any other shape (caller → BF101).
426
+ */
427
+ private conditionToGoBool;
428
+ /**
429
+ * Convert a static object literal (`{ 'aria-describedby': describedBy }`)
430
+ * into a Go `map[string]any{...}` literal for a conditional spread.
431
+ * Only static string/identifier keys are allowed; values resolve
432
+ * prop-identifier references to `in.FieldName` and string literals to
433
+ * Go string literals. Returns null for any computed/spread/dynamic
434
+ * key or unsupported value (caller → BF101). Empty object → `map[string]any{}`.
435
+ */
436
+ private objectLiteralToGoSpreadMap;
357
437
  /**
358
438
  * Convert JavaScript initial value to Go value for NewXxxProps function.
359
439
  * References to props params are converted to in.FieldName format.
@@ -1 +1 @@
1
- {"version":3,"file":"go-template-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/go-template-adapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"go-template-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/go-template-adapter.ts"],"names":[],"mappings":"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"}
@@ -118,6 +118,7 @@ class GoTemplateAdapter extends BaseAdapter {
118
118
  synthStructTypes = new Map;
119
119
  usesHtmlTemplate = false;
120
120
  moduleStringConsts = new Map;
121
+ nillablePropNames = new Set;
121
122
  constructor(options = {}) {
122
123
  super();
123
124
  this.options = {
@@ -133,6 +134,7 @@ class GoTemplateAdapter extends BaseAdapter {
133
134
  this.propsObjectName = ir.metadata.propsObjectName;
134
135
  this.restPropsName = ir.metadata.restPropsName ?? null;
135
136
  this.moduleStringConsts = this.collectModuleStringConsts(ir.metadata.localConstants);
137
+ this.nillablePropNames = this.collectNillablePropNames(ir);
136
138
  if (!options?.siblingTemplatesRegistered) {
137
139
  this.checkImportedLoopChildComponents(ir);
138
140
  }
@@ -568,6 +570,19 @@ ${goFields.join(`
568
570
  }
569
571
  return overrides;
570
572
  }
573
+ resolvePropGoType(param, propTypeOverrides) {
574
+ return propTypeOverrides.get(param.name) ?? this.typeInfoToGo(param.type, param.defaultValue);
575
+ }
576
+ collectNillablePropNames(ir) {
577
+ const propTypeOverrides = this.buildPropTypeOverrides(ir);
578
+ const nillable = new Set;
579
+ for (const param of ir.metadata.propsParams) {
580
+ if (this.resolvePropGoType(param, propTypeOverrides) === "interface{}") {
581
+ nillable.add(param.name);
582
+ }
583
+ }
584
+ return nillable;
585
+ }
571
586
  generateInputStruct(lines, ir, componentName, nestedComponents, propTypeOverrides, spreadSlots) {
572
587
  const inputTypeName = `${componentName}Input`;
573
588
  lines.push(`// ${inputTypeName} is the user-facing input type.`);
@@ -581,7 +596,7 @@ ${goFields.join(`
581
596
  const fieldName = this.capitalizeFieldName(param.name);
582
597
  if (nestedArrayFields.has(fieldName))
583
598
  continue;
584
- const goType = propTypeOverrides.get(param.name) ?? this.typeInfoToGo(param.type, param.defaultValue);
599
+ const goType = this.resolvePropGoType(param, propTypeOverrides);
585
600
  lines.push(` ${fieldName} ${goType}`);
586
601
  }
587
602
  for (const nested of inputNested) {
@@ -620,7 +635,7 @@ ${goFields.join(`
620
635
  const fieldName = this.capitalizeFieldName(param.name);
621
636
  if (nestedArrayFields.has(fieldName))
622
637
  continue;
623
- const goType = propTypeOverrides.get(param.name) ?? this.typeInfoToGo(param.type, param.defaultValue);
638
+ const goType = this.resolvePropGoType(param, propTypeOverrides);
624
639
  const jsonTag = this.toJsonTag(param.name);
625
640
  lines.push(` ${fieldName} ${goType} \`json:"${jsonTag}"\``);
626
641
  propFieldNames.add(fieldName);
@@ -1094,6 +1109,9 @@ ${goFields.join(`
1094
1109
  }
1095
1110
  buildSpreadInitializer(spreadExpr, ir) {
1096
1111
  const trimmed = spreadExpr.trim();
1112
+ const conditional = this.buildConditionalSpreadInitializer(trimmed, ir);
1113
+ if (conditional !== undefined)
1114
+ return conditional;
1097
1115
  const callMatch = /^([a-zA-Z_][a-zA-Z0-9_]*)\s*\(\s*\)$/.exec(trimmed);
1098
1116
  if (callMatch) {
1099
1117
  const getterName = callMatch[1];
@@ -1120,6 +1138,98 @@ ${goFields.join(`
1120
1138
  }
1121
1139
  return null;
1122
1140
  }
1141
+ buildConditionalSpreadInitializer(spreadExpr, ir) {
1142
+ const expr = this.parseLiteralExpression(spreadExpr);
1143
+ if (!expr || !ts.isConditionalExpression(expr))
1144
+ return;
1145
+ const whenTrue = this.unwrapParens(expr.whenTrue);
1146
+ const whenFalse = this.unwrapParens(expr.whenFalse);
1147
+ if (!ts.isObjectLiteralExpression(whenTrue) || !ts.isObjectLiteralExpression(whenFalse)) {
1148
+ return;
1149
+ }
1150
+ const goCond = this.conditionToGoBool(expr.condition, ir);
1151
+ if (goCond === null)
1152
+ return null;
1153
+ const trueMap = this.objectLiteralToGoSpreadMap(whenTrue, ir);
1154
+ const falseMap = this.objectLiteralToGoSpreadMap(whenFalse, ir);
1155
+ if (trueMap === null || falseMap === null)
1156
+ return null;
1157
+ return `func() map[string]any {
1158
+ ` + ` if ${goCond} {
1159
+ ` + ` return ${trueMap}
1160
+ ` + ` }
1161
+ ` + ` return ${falseMap}
1162
+ ` + ` }()`;
1163
+ }
1164
+ unwrapParens(node) {
1165
+ let e = node;
1166
+ while (ts.isParenthesizedExpression(e))
1167
+ e = e.expression;
1168
+ return e;
1169
+ }
1170
+ conditionToGoBool(condition, ir) {
1171
+ let node = this.unwrapParens(condition);
1172
+ let negate = false;
1173
+ if (ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.ExclamationToken) {
1174
+ negate = true;
1175
+ node = this.unwrapParens(node.operand);
1176
+ }
1177
+ if (!ts.isIdentifier(node))
1178
+ return null;
1179
+ const param = ir.metadata.propsParams.find((p) => p.name === node.text);
1180
+ if (!param)
1181
+ return null;
1182
+ const field = `in.${this.capitalizeFieldName(param.name)}`;
1183
+ const prim = param.type.kind === "primitive" ? param.type.primitive : undefined;
1184
+ let truthy;
1185
+ if (prim === "boolean") {
1186
+ truthy = field;
1187
+ } else if (prim === "number") {
1188
+ truthy = `${field} != 0`;
1189
+ } else if (prim === "string") {
1190
+ truthy = `${field} != ""`;
1191
+ } else {
1192
+ truthy = `bf.Truthy(${field})`;
1193
+ }
1194
+ if (!negate)
1195
+ return truthy;
1196
+ if (prim === "boolean")
1197
+ return `!${field}`;
1198
+ if (prim === "number")
1199
+ return `${field} == 0`;
1200
+ if (prim === "string")
1201
+ return `${field} == ""`;
1202
+ return `!bf.Truthy(${field})`;
1203
+ }
1204
+ objectLiteralToGoSpreadMap(obj, ir) {
1205
+ const entries = [];
1206
+ for (const prop of obj.properties) {
1207
+ if (!ts.isPropertyAssignment(prop))
1208
+ return null;
1209
+ let key;
1210
+ if (ts.isIdentifier(prop.name)) {
1211
+ key = prop.name.text;
1212
+ } else if (ts.isStringLiteral(prop.name) || ts.isNoSubstitutionTemplateLiteral(prop.name)) {
1213
+ key = prop.name.text;
1214
+ } else {
1215
+ return null;
1216
+ }
1217
+ const val = this.unwrapParens(prop.initializer);
1218
+ let goVal;
1219
+ if (ts.isStringLiteral(val) || ts.isNoSubstitutionTemplateLiteral(val)) {
1220
+ goVal = JSON.stringify(val.text);
1221
+ } else if (ts.isIdentifier(val)) {
1222
+ const param = ir.metadata.propsParams.find((p) => p.name === val.text);
1223
+ if (!param)
1224
+ return null;
1225
+ goVal = `in.${this.capitalizeFieldName(param.name)}`;
1226
+ } else {
1227
+ return null;
1228
+ }
1229
+ entries.push(`${JSON.stringify(key)}: ${goVal}`);
1230
+ }
1231
+ return `map[string]any{${entries.join(", ")}}`;
1232
+ }
1123
1233
  convertInitialValue(value, typeInfo, propsParams) {
1124
1234
  if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(value)) {
1125
1235
  if (propsParams?.some((p) => p.name === value)) {
@@ -2968,6 +3078,11 @@ ${children}`;
2968
3078
  if (parsed.kind === "conditional" || parsed.kind === "template-literal") {
2969
3079
  return `${name}="${this.renderParsedExpr(parsed)}"`;
2970
3080
  }
3081
+ const bareId = value.expr.trim();
3082
+ if (this.nillablePropNames.has(bareId)) {
3083
+ const field = `.${this.capitalizeFieldName(bareId)}`;
3084
+ return `{{if ne ${field} nil}}${name}="{{${this.convertExpressionToGo(value.expr)}}}"{{end}}`;
3085
+ }
2971
3086
  return `${name}="{{${this.convertExpressionToGo(value.expr)}}}"`;
2972
3087
  },
2973
3088
  emitBooleanAttr: (_value, name) => name,
package/dist/build.js CHANGED
@@ -458,6 +458,7 @@ class GoTemplateAdapter extends BaseAdapter {
458
458
  synthStructTypes = new Map;
459
459
  usesHtmlTemplate = false;
460
460
  moduleStringConsts = new Map;
461
+ nillablePropNames = new Set;
461
462
  constructor(options = {}) {
462
463
  super();
463
464
  this.options = {
@@ -473,6 +474,7 @@ class GoTemplateAdapter extends BaseAdapter {
473
474
  this.propsObjectName = ir.metadata.propsObjectName;
474
475
  this.restPropsName = ir.metadata.restPropsName ?? null;
475
476
  this.moduleStringConsts = this.collectModuleStringConsts(ir.metadata.localConstants);
477
+ this.nillablePropNames = this.collectNillablePropNames(ir);
476
478
  if (!options?.siblingTemplatesRegistered) {
477
479
  this.checkImportedLoopChildComponents(ir);
478
480
  }
@@ -908,6 +910,19 @@ ${goFields.join(`
908
910
  }
909
911
  return overrides;
910
912
  }
913
+ resolvePropGoType(param, propTypeOverrides) {
914
+ return propTypeOverrides.get(param.name) ?? this.typeInfoToGo(param.type, param.defaultValue);
915
+ }
916
+ collectNillablePropNames(ir) {
917
+ const propTypeOverrides = this.buildPropTypeOverrides(ir);
918
+ const nillable = new Set;
919
+ for (const param of ir.metadata.propsParams) {
920
+ if (this.resolvePropGoType(param, propTypeOverrides) === "interface{}") {
921
+ nillable.add(param.name);
922
+ }
923
+ }
924
+ return nillable;
925
+ }
911
926
  generateInputStruct(lines, ir, componentName, nestedComponents, propTypeOverrides, spreadSlots) {
912
927
  const inputTypeName = `${componentName}Input`;
913
928
  lines.push(`// ${inputTypeName} is the user-facing input type.`);
@@ -921,7 +936,7 @@ ${goFields.join(`
921
936
  const fieldName = this.capitalizeFieldName(param.name);
922
937
  if (nestedArrayFields.has(fieldName))
923
938
  continue;
924
- const goType = propTypeOverrides.get(param.name) ?? this.typeInfoToGo(param.type, param.defaultValue);
939
+ const goType = this.resolvePropGoType(param, propTypeOverrides);
925
940
  lines.push(` ${fieldName} ${goType}`);
926
941
  }
927
942
  for (const nested of inputNested) {
@@ -960,7 +975,7 @@ ${goFields.join(`
960
975
  const fieldName = this.capitalizeFieldName(param.name);
961
976
  if (nestedArrayFields.has(fieldName))
962
977
  continue;
963
- const goType = propTypeOverrides.get(param.name) ?? this.typeInfoToGo(param.type, param.defaultValue);
978
+ const goType = this.resolvePropGoType(param, propTypeOverrides);
964
979
  const jsonTag = this.toJsonTag(param.name);
965
980
  lines.push(` ${fieldName} ${goType} \`json:"${jsonTag}"\``);
966
981
  propFieldNames.add(fieldName);
@@ -1434,6 +1449,9 @@ ${goFields.join(`
1434
1449
  }
1435
1450
  buildSpreadInitializer(spreadExpr, ir) {
1436
1451
  const trimmed = spreadExpr.trim();
1452
+ const conditional = this.buildConditionalSpreadInitializer(trimmed, ir);
1453
+ if (conditional !== undefined)
1454
+ return conditional;
1437
1455
  const callMatch = /^([a-zA-Z_][a-zA-Z0-9_]*)\s*\(\s*\)$/.exec(trimmed);
1438
1456
  if (callMatch) {
1439
1457
  const getterName = callMatch[1];
@@ -1460,6 +1478,98 @@ ${goFields.join(`
1460
1478
  }
1461
1479
  return null;
1462
1480
  }
1481
+ buildConditionalSpreadInitializer(spreadExpr, ir) {
1482
+ const expr = this.parseLiteralExpression(spreadExpr);
1483
+ if (!expr || !ts.isConditionalExpression(expr))
1484
+ return;
1485
+ const whenTrue = this.unwrapParens(expr.whenTrue);
1486
+ const whenFalse = this.unwrapParens(expr.whenFalse);
1487
+ if (!ts.isObjectLiteralExpression(whenTrue) || !ts.isObjectLiteralExpression(whenFalse)) {
1488
+ return;
1489
+ }
1490
+ const goCond = this.conditionToGoBool(expr.condition, ir);
1491
+ if (goCond === null)
1492
+ return null;
1493
+ const trueMap = this.objectLiteralToGoSpreadMap(whenTrue, ir);
1494
+ const falseMap = this.objectLiteralToGoSpreadMap(whenFalse, ir);
1495
+ if (trueMap === null || falseMap === null)
1496
+ return null;
1497
+ return `func() map[string]any {
1498
+ ` + ` if ${goCond} {
1499
+ ` + ` return ${trueMap}
1500
+ ` + ` }
1501
+ ` + ` return ${falseMap}
1502
+ ` + ` }()`;
1503
+ }
1504
+ unwrapParens(node) {
1505
+ let e = node;
1506
+ while (ts.isParenthesizedExpression(e))
1507
+ e = e.expression;
1508
+ return e;
1509
+ }
1510
+ conditionToGoBool(condition, ir) {
1511
+ let node = this.unwrapParens(condition);
1512
+ let negate = false;
1513
+ if (ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.ExclamationToken) {
1514
+ negate = true;
1515
+ node = this.unwrapParens(node.operand);
1516
+ }
1517
+ if (!ts.isIdentifier(node))
1518
+ return null;
1519
+ const param = ir.metadata.propsParams.find((p) => p.name === node.text);
1520
+ if (!param)
1521
+ return null;
1522
+ const field = `in.${this.capitalizeFieldName(param.name)}`;
1523
+ const prim = param.type.kind === "primitive" ? param.type.primitive : undefined;
1524
+ let truthy;
1525
+ if (prim === "boolean") {
1526
+ truthy = field;
1527
+ } else if (prim === "number") {
1528
+ truthy = `${field} != 0`;
1529
+ } else if (prim === "string") {
1530
+ truthy = `${field} != ""`;
1531
+ } else {
1532
+ truthy = `bf.Truthy(${field})`;
1533
+ }
1534
+ if (!negate)
1535
+ return truthy;
1536
+ if (prim === "boolean")
1537
+ return `!${field}`;
1538
+ if (prim === "number")
1539
+ return `${field} == 0`;
1540
+ if (prim === "string")
1541
+ return `${field} == ""`;
1542
+ return `!bf.Truthy(${field})`;
1543
+ }
1544
+ objectLiteralToGoSpreadMap(obj, ir) {
1545
+ const entries = [];
1546
+ for (const prop of obj.properties) {
1547
+ if (!ts.isPropertyAssignment(prop))
1548
+ return null;
1549
+ let key;
1550
+ if (ts.isIdentifier(prop.name)) {
1551
+ key = prop.name.text;
1552
+ } else if (ts.isStringLiteral(prop.name) || ts.isNoSubstitutionTemplateLiteral(prop.name)) {
1553
+ key = prop.name.text;
1554
+ } else {
1555
+ return null;
1556
+ }
1557
+ const val = this.unwrapParens(prop.initializer);
1558
+ let goVal;
1559
+ if (ts.isStringLiteral(val) || ts.isNoSubstitutionTemplateLiteral(val)) {
1560
+ goVal = JSON.stringify(val.text);
1561
+ } else if (ts.isIdentifier(val)) {
1562
+ const param = ir.metadata.propsParams.find((p) => p.name === val.text);
1563
+ if (!param)
1564
+ return null;
1565
+ goVal = `in.${this.capitalizeFieldName(param.name)}`;
1566
+ } else {
1567
+ return null;
1568
+ }
1569
+ entries.push(`${JSON.stringify(key)}: ${goVal}`);
1570
+ }
1571
+ return `map[string]any{${entries.join(", ")}}`;
1572
+ }
1463
1573
  convertInitialValue(value, typeInfo, propsParams) {
1464
1574
  if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(value)) {
1465
1575
  if (propsParams?.some((p) => p.name === value)) {
@@ -3308,6 +3418,11 @@ ${children}`;
3308
3418
  if (parsed.kind === "conditional" || parsed.kind === "template-literal") {
3309
3419
  return `${name}="${this.renderParsedExpr(parsed)}"`;
3310
3420
  }
3421
+ const bareId = value.expr.trim();
3422
+ if (this.nillablePropNames.has(bareId)) {
3423
+ const field = `.${this.capitalizeFieldName(bareId)}`;
3424
+ return `{{if ne ${field} nil}}${name}="{{${this.convertExpressionToGo(value.expr)}}}"{{end}}`;
3425
+ }
3311
3426
  return `${name}="{{${this.convertExpressionToGo(value.expr)}}}"`;
3312
3427
  },
3313
3428
  emitBooleanAttr: (_value, name) => name,
package/dist/index.js CHANGED
@@ -118,6 +118,7 @@ class GoTemplateAdapter extends BaseAdapter {
118
118
  synthStructTypes = new Map;
119
119
  usesHtmlTemplate = false;
120
120
  moduleStringConsts = new Map;
121
+ nillablePropNames = new Set;
121
122
  constructor(options = {}) {
122
123
  super();
123
124
  this.options = {
@@ -133,6 +134,7 @@ class GoTemplateAdapter extends BaseAdapter {
133
134
  this.propsObjectName = ir.metadata.propsObjectName;
134
135
  this.restPropsName = ir.metadata.restPropsName ?? null;
135
136
  this.moduleStringConsts = this.collectModuleStringConsts(ir.metadata.localConstants);
137
+ this.nillablePropNames = this.collectNillablePropNames(ir);
136
138
  if (!options?.siblingTemplatesRegistered) {
137
139
  this.checkImportedLoopChildComponents(ir);
138
140
  }
@@ -568,6 +570,19 @@ ${goFields.join(`
568
570
  }
569
571
  return overrides;
570
572
  }
573
+ resolvePropGoType(param, propTypeOverrides) {
574
+ return propTypeOverrides.get(param.name) ?? this.typeInfoToGo(param.type, param.defaultValue);
575
+ }
576
+ collectNillablePropNames(ir) {
577
+ const propTypeOverrides = this.buildPropTypeOverrides(ir);
578
+ const nillable = new Set;
579
+ for (const param of ir.metadata.propsParams) {
580
+ if (this.resolvePropGoType(param, propTypeOverrides) === "interface{}") {
581
+ nillable.add(param.name);
582
+ }
583
+ }
584
+ return nillable;
585
+ }
571
586
  generateInputStruct(lines, ir, componentName, nestedComponents, propTypeOverrides, spreadSlots) {
572
587
  const inputTypeName = `${componentName}Input`;
573
588
  lines.push(`// ${inputTypeName} is the user-facing input type.`);
@@ -581,7 +596,7 @@ ${goFields.join(`
581
596
  const fieldName = this.capitalizeFieldName(param.name);
582
597
  if (nestedArrayFields.has(fieldName))
583
598
  continue;
584
- const goType = propTypeOverrides.get(param.name) ?? this.typeInfoToGo(param.type, param.defaultValue);
599
+ const goType = this.resolvePropGoType(param, propTypeOverrides);
585
600
  lines.push(` ${fieldName} ${goType}`);
586
601
  }
587
602
  for (const nested of inputNested) {
@@ -620,7 +635,7 @@ ${goFields.join(`
620
635
  const fieldName = this.capitalizeFieldName(param.name);
621
636
  if (nestedArrayFields.has(fieldName))
622
637
  continue;
623
- const goType = propTypeOverrides.get(param.name) ?? this.typeInfoToGo(param.type, param.defaultValue);
638
+ const goType = this.resolvePropGoType(param, propTypeOverrides);
624
639
  const jsonTag = this.toJsonTag(param.name);
625
640
  lines.push(` ${fieldName} ${goType} \`json:"${jsonTag}"\``);
626
641
  propFieldNames.add(fieldName);
@@ -1094,6 +1109,9 @@ ${goFields.join(`
1094
1109
  }
1095
1110
  buildSpreadInitializer(spreadExpr, ir) {
1096
1111
  const trimmed = spreadExpr.trim();
1112
+ const conditional = this.buildConditionalSpreadInitializer(trimmed, ir);
1113
+ if (conditional !== undefined)
1114
+ return conditional;
1097
1115
  const callMatch = /^([a-zA-Z_][a-zA-Z0-9_]*)\s*\(\s*\)$/.exec(trimmed);
1098
1116
  if (callMatch) {
1099
1117
  const getterName = callMatch[1];
@@ -1120,6 +1138,98 @@ ${goFields.join(`
1120
1138
  }
1121
1139
  return null;
1122
1140
  }
1141
+ buildConditionalSpreadInitializer(spreadExpr, ir) {
1142
+ const expr = this.parseLiteralExpression(spreadExpr);
1143
+ if (!expr || !ts.isConditionalExpression(expr))
1144
+ return;
1145
+ const whenTrue = this.unwrapParens(expr.whenTrue);
1146
+ const whenFalse = this.unwrapParens(expr.whenFalse);
1147
+ if (!ts.isObjectLiteralExpression(whenTrue) || !ts.isObjectLiteralExpression(whenFalse)) {
1148
+ return;
1149
+ }
1150
+ const goCond = this.conditionToGoBool(expr.condition, ir);
1151
+ if (goCond === null)
1152
+ return null;
1153
+ const trueMap = this.objectLiteralToGoSpreadMap(whenTrue, ir);
1154
+ const falseMap = this.objectLiteralToGoSpreadMap(whenFalse, ir);
1155
+ if (trueMap === null || falseMap === null)
1156
+ return null;
1157
+ return `func() map[string]any {
1158
+ ` + ` if ${goCond} {
1159
+ ` + ` return ${trueMap}
1160
+ ` + ` }
1161
+ ` + ` return ${falseMap}
1162
+ ` + ` }()`;
1163
+ }
1164
+ unwrapParens(node) {
1165
+ let e = node;
1166
+ while (ts.isParenthesizedExpression(e))
1167
+ e = e.expression;
1168
+ return e;
1169
+ }
1170
+ conditionToGoBool(condition, ir) {
1171
+ let node = this.unwrapParens(condition);
1172
+ let negate = false;
1173
+ if (ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.ExclamationToken) {
1174
+ negate = true;
1175
+ node = this.unwrapParens(node.operand);
1176
+ }
1177
+ if (!ts.isIdentifier(node))
1178
+ return null;
1179
+ const param = ir.metadata.propsParams.find((p) => p.name === node.text);
1180
+ if (!param)
1181
+ return null;
1182
+ const field = `in.${this.capitalizeFieldName(param.name)}`;
1183
+ const prim = param.type.kind === "primitive" ? param.type.primitive : undefined;
1184
+ let truthy;
1185
+ if (prim === "boolean") {
1186
+ truthy = field;
1187
+ } else if (prim === "number") {
1188
+ truthy = `${field} != 0`;
1189
+ } else if (prim === "string") {
1190
+ truthy = `${field} != ""`;
1191
+ } else {
1192
+ truthy = `bf.Truthy(${field})`;
1193
+ }
1194
+ if (!negate)
1195
+ return truthy;
1196
+ if (prim === "boolean")
1197
+ return `!${field}`;
1198
+ if (prim === "number")
1199
+ return `${field} == 0`;
1200
+ if (prim === "string")
1201
+ return `${field} == ""`;
1202
+ return `!bf.Truthy(${field})`;
1203
+ }
1204
+ objectLiteralToGoSpreadMap(obj, ir) {
1205
+ const entries = [];
1206
+ for (const prop of obj.properties) {
1207
+ if (!ts.isPropertyAssignment(prop))
1208
+ return null;
1209
+ let key;
1210
+ if (ts.isIdentifier(prop.name)) {
1211
+ key = prop.name.text;
1212
+ } else if (ts.isStringLiteral(prop.name) || ts.isNoSubstitutionTemplateLiteral(prop.name)) {
1213
+ key = prop.name.text;
1214
+ } else {
1215
+ return null;
1216
+ }
1217
+ const val = this.unwrapParens(prop.initializer);
1218
+ let goVal;
1219
+ if (ts.isStringLiteral(val) || ts.isNoSubstitutionTemplateLiteral(val)) {
1220
+ goVal = JSON.stringify(val.text);
1221
+ } else if (ts.isIdentifier(val)) {
1222
+ const param = ir.metadata.propsParams.find((p) => p.name === val.text);
1223
+ if (!param)
1224
+ return null;
1225
+ goVal = `in.${this.capitalizeFieldName(param.name)}`;
1226
+ } else {
1227
+ return null;
1228
+ }
1229
+ entries.push(`${JSON.stringify(key)}: ${goVal}`);
1230
+ }
1231
+ return `map[string]any{${entries.join(", ")}}`;
1232
+ }
1123
1233
  convertInitialValue(value, typeInfo, propsParams) {
1124
1234
  if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(value)) {
1125
1235
  if (propsParams?.some((p) => p.name === value)) {
@@ -2968,6 +3078,11 @@ ${children}`;
2968
3078
  if (parsed.kind === "conditional" || parsed.kind === "template-literal") {
2969
3079
  return `${name}="${this.renderParsedExpr(parsed)}"`;
2970
3080
  }
3081
+ const bareId = value.expr.trim();
3082
+ if (this.nillablePropNames.has(bareId)) {
3083
+ const field = `.${this.capitalizeFieldName(bareId)}`;
3084
+ return `{{if ne ${field} nil}}${name}="{{${this.convertExpressionToGo(value.expr)}}}"{{end}}`;
3085
+ }
2971
3086
  return `${name}="{{${this.convertExpressionToGo(value.expr)}}}"`;
2972
3087
  },
2973
3088
  emitBooleanAttr: (_value, name) => name,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/go-template",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
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",
@@ -54,6 +54,6 @@
54
54
  },
55
55
  "devDependencies": {
56
56
  "@barefootjs/adapter-tests": "0.1.0",
57
- "@barefootjs/jsx": "0.7.0"
57
+ "@barefootjs/jsx": "0.8.0"
58
58
  }
59
59
  }
@@ -80,12 +80,19 @@ runAdapterConformanceTests({
80
80
  // parity for the `site/ui` corpus is Phase 3, so these participate only
81
81
  // in Hono SSR conformance + the fixture-hydrate runtime layer for now.
82
82
  // (`label` and `kbd` are static helpers; `toggle` / `switch` /
83
- // `checkbox` carry uncontrolled state; `input` / `textarea` are
84
- // pass-through native controls.)
83
+ // `checkbox` carry uncontrolled state; `input` is a pass-through
84
+ // native control.)
85
+ //
86
+ // `textarea` now participates: its conditional inline-object spread
87
+ // (`{...(describedBy ? {...} : {})}`) lowers via
88
+ // `buildConditionalSpreadInitializer`, and its optional
89
+ // `rows={rows}` attribute is omitted when nil via the nillable-field
90
+ // guard in `elementAttrEmitter.emitExpression`
91
+ // (`{{if ne .Rows nil}}rows="{{.Rows}}"{{end}}`), matching Hono's
92
+ // nullish-attribute omission.
85
93
  'toggle',
86
94
  'switch',
87
95
  'checkbox',
88
- 'textarea',
89
96
  'kbd',
90
97
  ],
91
98
  // Per-fixture build-time contracts for shapes the Go template
@@ -818,6 +825,90 @@ export function List() {
818
825
  })
819
826
  })
820
827
 
828
+ describe('conditional inline-object spread (textarea aria-describedby)', () => {
829
+ // `{...(cond ? { 'aria-describedby': cond } : {})}` lowers to an
830
+ // IIFE-of-maps in `NewXxxProps` so the falsy branch OMITS the key
831
+ // (SpreadAttrs does not filter empty strings). The fixture only
832
+ // exercises the falsy branch; this pins the TRUTHY branch.
833
+ test('lowers to a conditional map IIFE and keeps the {{bf_spread_attrs}} template', () => {
834
+ const source = `
835
+ function Box({ describedBy }: { describedBy?: string }) {
836
+ return <div {...(describedBy ? { 'aria-describedby': describedBy } : {})} />
837
+ }
838
+ `
839
+ const { template, types } = compileAndGenerate(source)
840
+ // Template emission is unchanged from the proven {...props} path.
841
+ expect(template).toContain('{{bf_spread_attrs .Spread_0}}')
842
+ // The bag value is a conditional map built in NewBoxProps. The
843
+ // prop type is unresolved (interface{}), so the condition routes
844
+ // through `bf.Truthy` for a faithful JS `Boolean(x)` test.
845
+ expect(types).toContain('Spread_0: func() map[string]any {')
846
+ expect(types).toContain('if bf.Truthy(in.DescribedBy) {')
847
+ expect(types).toContain('return map[string]any{"aria-describedby": in.DescribedBy}')
848
+ expect(types).toContain('return map[string]any{}')
849
+ })
850
+
851
+ test('resolves the object value reference and key for a second prop', () => {
852
+ const source = `
853
+ function Box({ label }: { label: string }) {
854
+ return <div {...(label ? { 'data-label': label } : {})} />
855
+ }
856
+ `
857
+ const { types } = compileAndGenerate(source)
858
+ // The condition prop and the value reference resolve to `in.<Field>`,
859
+ // the static key is preserved. (The analyzer surfaces these
860
+ // destructured props as `unknown`/`interface{}`, so the condition
861
+ // routes through `bf.Truthy` for a faithful JS truthiness test.)
862
+ expect(types).toContain('if bf.Truthy(in.Label) {')
863
+ expect(types).toContain('return map[string]any{"data-label": in.Label}')
864
+ })
865
+
866
+ test('refuses a non-identifier condition with BF101 (out-of-shape fallback)', () => {
867
+ const adapter = new GoTemplateAdapter()
868
+ const source = `
869
+ function Box({ a, b }: { a?: string; b?: string }) {
870
+ return <div {...(a === b ? { 'data-x': a } : {})} />
871
+ }
872
+ `
873
+ const ir = compileToIR(source, adapter)
874
+ adapter.generate(ir)
875
+ const errs = (adapter as unknown as { errors: { code: string }[] }).errors
876
+ expect(errs.some(e => e.code === 'BF101')).toBe(true)
877
+ })
878
+ })
879
+
880
+ describe('nullish optional-attribute omission (textarea rows)', () => {
881
+ // An optional, no-default prop whose Go field type resolves to
882
+ // `interface{}` (nillable) is emitted with a `ne .X nil` guard so an
883
+ // unset value DROPS the attribute instead of rendering `attr=""` —
884
+ // matching Hono's nullish-attribute omission. Concrete/defaulted
885
+ // props are never nil and stay unconditional.
886
+ test('guards a nillable optional attr with {{if ne .X nil}}', () => {
887
+ const source = `
888
+ function C({ rows }: { rows?: number }) {
889
+ return <textarea rows={rows} />
890
+ }
891
+ `
892
+ const { template } = compileAndGenerate(source)
893
+ expect(template).toContain('{{if ne .Rows nil}}rows="{{.Rows}}"{{end}}')
894
+ // Must NOT emit the bare unconditional form.
895
+ expect(template).not.toMatch(/(?<!if ne \.Rows nil}})rows="\{\{\.Rows\}\}"/)
896
+ })
897
+
898
+ test('leaves a concrete/defaulted attr unconditional (scope did not widen)', () => {
899
+ const source = `
900
+ function C({ value = '' }: { value?: string }) {
901
+ return <textarea value={value} />
902
+ }
903
+ `
904
+ const { template } = compileAndGenerate(source)
905
+ // `value` has a destructure default → concrete `string` field →
906
+ // never nil → emitted unconditionally, exactly like Hono's value="".
907
+ expect(template).toContain('value="{{.Value}}"')
908
+ expect(template).not.toContain('if ne .Value nil')
909
+ })
910
+ })
911
+
821
912
  describe('loop body outer-scope references (#1677)', () => {
822
913
  test('references an outer signal inside a loop via $ root scope, not the element', () => {
823
914
  // Inside `{{range $_, $t := .Items}}` the dot is rebound to the loop
@@ -434,6 +434,21 @@ export class GoTemplateAdapter extends BaseAdapter implements ParsedExprEmitter,
434
434
  */
435
435
  private moduleStringConsts: Map<string, string> = new Map()
436
436
 
437
+ /**
438
+ * Set of prop NAMES whose resolved Go struct-field type is exactly
439
+ * `interface{}` — i.e. nillable. Populated at `generate()` entry from
440
+ * the SAME per-prop Go-type computation `generatePropsStruct` /
441
+ * `generateInputStruct` use (`propTypeOverrides` + `typeInfoToGo`), so
442
+ * it can't drift from the actual field types. Used by
443
+ * `elementAttrEmitter.emitExpression` to omit a dynamic attribute whose
444
+ * value is a bare reference to a nillable prop when that prop is nil
445
+ * (Hono-style nullish-attribute omission: an `undefined`-valued
446
+ * attribute is dropped rather than rendered as `attr=""`). Concrete
447
+ * (`string`/`int`/`bool`) fields are never in this set and always emit
448
+ * unconditionally, matching Hono's `value=""` / `data-count="0"`.
449
+ */
450
+ private nillablePropNames: Set<string> = new Set()
451
+
437
452
  constructor(options: GoTemplateAdapterOptions = {}) {
438
453
  super()
439
454
  this.options = {
@@ -455,6 +470,7 @@ export class GoTemplateAdapter extends BaseAdapter implements ParsedExprEmitter,
455
470
  this.propsObjectName = ir.metadata.propsObjectName
456
471
  this.restPropsName = ir.metadata.restPropsName ?? null
457
472
  this.moduleStringConsts = this.collectModuleStringConsts(ir.metadata.localConstants)
473
+ this.nillablePropNames = this.collectNillablePropNames(ir)
458
474
 
459
475
  // Surface loop-body usages of components imported from sibling
460
476
  // .tsx files. The adapter emits `{{template "X" .}}` for these,
@@ -1065,6 +1081,40 @@ export class GoTemplateAdapter extends BaseAdapter implements ParsedExprEmitter,
1065
1081
  return overrides
1066
1082
  }
1067
1083
 
1084
+ /**
1085
+ * Resolve a prop param's Go struct-field type using the SAME logic
1086
+ * `generatePropsStruct` / `generateInputStruct` use for the field
1087
+ * declaration: a `propTypeOverrides` entry (signal-inferred override)
1088
+ * wins, otherwise `typeInfoToGo(param.type, param.defaultValue)`.
1089
+ * Factored out so the nillable-field set (`collectNillablePropNames`)
1090
+ * can't drift from the actual emitted field types.
1091
+ */
1092
+ private resolvePropGoType(
1093
+ param: IRMetadata['propsParams'][number],
1094
+ propTypeOverrides: Map<string, string>,
1095
+ ): string {
1096
+ return propTypeOverrides.get(param.name) ?? this.typeInfoToGo(param.type, param.defaultValue)
1097
+ }
1098
+
1099
+ /**
1100
+ * Build the set of prop NAMES whose resolved Go field type is exactly
1101
+ * `interface{}` (nillable). Uses the same `propTypeOverrides` +
1102
+ * `resolvePropGoType` pipeline as the struct generators, so a prop
1103
+ * that ends up `interface{}` on the Props struct — and only such a
1104
+ * prop — is treated as nillable for Hono-style attribute omission.
1105
+ * Concrete (`string`/`int`/`bool`/`[]T`/struct) types are excluded.
1106
+ */
1107
+ private collectNillablePropNames(ir: ComponentIR): Set<string> {
1108
+ const propTypeOverrides = this.buildPropTypeOverrides(ir)
1109
+ const nillable = new Set<string>()
1110
+ for (const param of ir.metadata.propsParams) {
1111
+ if (this.resolvePropGoType(param, propTypeOverrides) === 'interface{}') {
1112
+ nillable.add(param.name)
1113
+ }
1114
+ }
1115
+ return nillable
1116
+ }
1117
+
1068
1118
  /**
1069
1119
  * Generate Input struct for a component
1070
1120
  */
@@ -1096,7 +1146,7 @@ export class GoTemplateAdapter extends BaseAdapter implements ParsedExprEmitter,
1096
1146
  for (const param of ir.metadata.propsParams) {
1097
1147
  const fieldName = this.capitalizeFieldName(param.name)
1098
1148
  if (nestedArrayFields.has(fieldName)) continue
1099
- const goType = propTypeOverrides.get(param.name) ?? this.typeInfoToGo(param.type, param.defaultValue)
1149
+ const goType = this.resolvePropGoType(param, propTypeOverrides)
1100
1150
  lines.push(`\t${fieldName} ${goType}`)
1101
1151
  }
1102
1152
 
@@ -1169,7 +1219,7 @@ export class GoTemplateAdapter extends BaseAdapter implements ParsedExprEmitter,
1169
1219
  const fieldName = this.capitalizeFieldName(param.name)
1170
1220
  // Skip if this field will be replaced by a typed array for nested components
1171
1221
  if (nestedArrayFields.has(fieldName)) continue
1172
- const goType = propTypeOverrides.get(param.name) ?? this.typeInfoToGo(param.type, param.defaultValue)
1222
+ const goType = this.resolvePropGoType(param, propTypeOverrides)
1173
1223
  const jsonTag = this.toJsonTag(param.name)
1174
1224
  lines.push(`\t${fieldName} ${goType} \`json:"${jsonTag}"\``)
1175
1225
  propFieldNames.add(fieldName)
@@ -1922,6 +1972,15 @@ export class GoTemplateAdapter extends BaseAdapter implements ParsedExprEmitter,
1922
1972
  ir: ComponentIR,
1923
1973
  ): string | null {
1924
1974
  const trimmed = spreadExpr.trim()
1975
+ // Conditional inline-object spread:
1976
+ // `{...(COND ? { 'k': v } : {})}` (either branch possibly `{}`).
1977
+ // Lower to an immediately-invoked func literal that conditionally
1978
+ // builds the bag, so the falsy branch yields an empty map (the key
1979
+ // is OMITTED rather than rendered as `k=""` — `SpreadAttrs` does
1980
+ // NOT filter empty strings). Returns null for any shape it can't
1981
+ // faithfully convert so the caller falls back to BF101 (#textarea).
1982
+ const conditional = this.buildConditionalSpreadInitializer(trimmed, ir)
1983
+ if (conditional !== undefined) return conditional
1925
1984
  // Signal-getter call: `attrs()` — pluck the signal's initialValue
1926
1985
  // and translate the JS object literal to a Go map literal.
1927
1986
  const callMatch = /^([a-zA-Z_][a-zA-Z0-9_]*)\s*\(\s*\)$/.exec(trimmed)
@@ -1974,6 +2033,152 @@ export class GoTemplateAdapter extends BaseAdapter implements ParsedExprEmitter,
1974
2033
  return null
1975
2034
  }
1976
2035
 
2036
+ /**
2037
+ * Lower a conditional inline-object spread bag value:
2038
+ * `(COND ? { 'aria-describedby': describedBy } : {})`
2039
+ * into an immediately-invoked Go func literal that conditionally
2040
+ * builds the map (so the falsy branch OMITS the key rather than
2041
+ * rendering it as an empty string, which `SpreadAttrs` does not
2042
+ * filter):
2043
+ *
2044
+ * func() map[string]any {
2045
+ * if in.DescribedBy != nil && in.DescribedBy != "" {
2046
+ * return map[string]any{"aria-describedby": in.DescribedBy}
2047
+ * }
2048
+ * return map[string]any{}
2049
+ * }()
2050
+ *
2051
+ * Returns:
2052
+ * - `undefined` when the expression is NOT a parenthesized ternary
2053
+ * of object literals — the caller falls through to other shapes.
2054
+ * - `null` when it IS that shape but a part can't be faithfully
2055
+ * converted (non-static key, unsupported condition, …) — the
2056
+ * caller raises BF101.
2057
+ * - the Go IIFE string when fully convertible.
2058
+ */
2059
+ private buildConditionalSpreadInitializer(
2060
+ spreadExpr: string,
2061
+ ir: ComponentIR,
2062
+ ): string | null | undefined {
2063
+ const expr = this.parseLiteralExpression(spreadExpr)
2064
+ if (!expr || !ts.isConditionalExpression(expr)) return undefined
2065
+ const whenTrue = this.unwrapParens(expr.whenTrue)
2066
+ const whenFalse = this.unwrapParens(expr.whenFalse)
2067
+ if (!ts.isObjectLiteralExpression(whenTrue) || !ts.isObjectLiteralExpression(whenFalse)) {
2068
+ return undefined
2069
+ }
2070
+ // Condition → Go bool against `in.`, type-aware on the prop.
2071
+ const goCond = this.conditionToGoBool(expr.condition, ir)
2072
+ if (goCond === null) return null
2073
+ const trueMap = this.objectLiteralToGoSpreadMap(whenTrue, ir)
2074
+ const falseMap = this.objectLiteralToGoSpreadMap(whenFalse, ir)
2075
+ if (trueMap === null || falseMap === null) return null
2076
+ return (
2077
+ `func() map[string]any {\n` +
2078
+ `\t\tif ${goCond} {\n` +
2079
+ `\t\t\treturn ${trueMap}\n` +
2080
+ `\t\t}\n` +
2081
+ `\t\treturn ${falseMap}\n` +
2082
+ `\t}()`
2083
+ )
2084
+ }
2085
+
2086
+ /** Strip redundant parenthesised wrappers off a TS expression. */
2087
+ private unwrapParens(node: ts.Expression): ts.Expression {
2088
+ let e = node
2089
+ while (ts.isParenthesizedExpression(e)) e = e.expression
2090
+ return e
2091
+ }
2092
+
2093
+ /**
2094
+ * Convert a conditional-spread condition expression to a Go bool in
2095
+ * the `in.` context. Supports a bare prop identifier (`describedBy`)
2096
+ * and its negation (`!describedBy`), type-aware on the prop:
2097
+ * string → `in.X != ""`
2098
+ * boolean → `in.X`
2099
+ * number → `in.X != 0`
2100
+ * unknown / interface{} → `in.X != nil && in.X != ""`
2101
+ * (faithful JS string-truthiness for an interface holding a
2102
+ * string — textarea's `describedBy` resolves to interface{}).
2103
+ * Returns null for any other shape (caller → BF101).
2104
+ */
2105
+ private conditionToGoBool(
2106
+ condition: ts.Expression,
2107
+ ir: ComponentIR,
2108
+ ): string | null {
2109
+ let node = this.unwrapParens(condition)
2110
+ let negate = false
2111
+ if (ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.ExclamationToken) {
2112
+ negate = true
2113
+ node = this.unwrapParens(node.operand)
2114
+ }
2115
+ if (!ts.isIdentifier(node)) return null
2116
+ const param = ir.metadata.propsParams.find(p => p.name === node.text)
2117
+ if (!param) return null
2118
+ const field = `in.${this.capitalizeFieldName(param.name)}`
2119
+ const prim = param.type.kind === 'primitive' ? param.type.primitive : undefined
2120
+ let truthy: string
2121
+ if (prim === 'boolean') {
2122
+ truthy = field
2123
+ } else if (prim === 'number') {
2124
+ truthy = `${field} != 0`
2125
+ } else if (prim === 'string') {
2126
+ truthy = `${field} != ""`
2127
+ } else {
2128
+ // unknown / interface{}: the runtime value may be a string, number,
2129
+ // bool, etc., so a string-biased `!= ""` test would diverge from JS
2130
+ // truthiness (e.g. an `interface{}` holding `0` or `false` is falsy in
2131
+ // JS but `!= ""` reads true). Route through `bf.Truthy`, the exported
2132
+ // `Boolean(x)` equivalent, for a faithful check (Copilot review #1752).
2133
+ truthy = `bf.Truthy(${field})`
2134
+ }
2135
+ if (!negate) return truthy
2136
+ // Negation: wrap so `!` applies to the whole truthiness test.
2137
+ if (prim === 'boolean') return `!${field}`
2138
+ if (prim === 'number') return `${field} == 0`
2139
+ if (prim === 'string') return `${field} == ""`
2140
+ return `!bf.Truthy(${field})`
2141
+ }
2142
+
2143
+ /**
2144
+ * Convert a static object literal (`{ 'aria-describedby': describedBy }`)
2145
+ * into a Go `map[string]any{...}` literal for a conditional spread.
2146
+ * Only static string/identifier keys are allowed; values resolve
2147
+ * prop-identifier references to `in.FieldName` and string literals to
2148
+ * Go string literals. Returns null for any computed/spread/dynamic
2149
+ * key or unsupported value (caller → BF101). Empty object → `map[string]any{}`.
2150
+ */
2151
+ private objectLiteralToGoSpreadMap(
2152
+ obj: ts.ObjectLiteralExpression,
2153
+ ir: ComponentIR,
2154
+ ): string | null {
2155
+ const entries: string[] = []
2156
+ for (const prop of obj.properties) {
2157
+ if (!ts.isPropertyAssignment(prop)) return null
2158
+ let key: string
2159
+ if (ts.isIdentifier(prop.name)) {
2160
+ key = prop.name.text
2161
+ } else if (ts.isStringLiteral(prop.name) || ts.isNoSubstitutionTemplateLiteral(prop.name)) {
2162
+ key = prop.name.text
2163
+ } else {
2164
+ return null
2165
+ }
2166
+ const val = this.unwrapParens(prop.initializer)
2167
+ let goVal: string
2168
+ if (ts.isStringLiteral(val) || ts.isNoSubstitutionTemplateLiteral(val)) {
2169
+ goVal = JSON.stringify(val.text)
2170
+ } else if (ts.isIdentifier(val)) {
2171
+ const param = ir.metadata.propsParams.find(p => p.name === val.text)
2172
+ if (!param) return null
2173
+ goVal = `in.${this.capitalizeFieldName(param.name)}`
2174
+ } else {
2175
+ return null
2176
+ }
2177
+ entries.push(`${JSON.stringify(key)}: ${goVal}`)
2178
+ }
2179
+ return `map[string]any{${entries.join(', ')}}`
2180
+ }
2181
+
1977
2182
  /**
1978
2183
  * Convert JavaScript initial value to Go value for NewXxxProps function.
1979
2184
  * References to props params are converted to in.FieldName format.
@@ -4886,6 +5091,20 @@ export class GoTemplateAdapter extends BaseAdapter implements ParsedExprEmitter,
4886
5091
  // Inline Go template syntax with embedded `{{...}}` actions.
4887
5092
  return `${name}="${this.renderParsedExpr(parsed)}"`
4888
5093
  }
5094
+ // Hono-style nullish-attribute omission (#textarea rows): when the
5095
+ // attribute value is a BARE reference to a nillable (`interface{}`)
5096
+ // prop field, guard emission on `ne .X nil` so an unset optional
5097
+ // prop drops the attribute entirely instead of rendering `attr=""`.
5098
+ // Hono omits `undefined`/`null`-valued attributes; this restores
5099
+ // parity. Scope is deliberately narrow — bare identifiers only — so
5100
+ // member exprs, calls, ternaries, template literals, and
5101
+ // concrete-typed props (which are never nil) are unaffected and
5102
+ // still emit `attr=""` / `attr="0"` exactly as Hono does.
5103
+ const bareId = value.expr.trim()
5104
+ if (this.nillablePropNames.has(bareId)) {
5105
+ const field = `.${this.capitalizeFieldName(bareId)}`
5106
+ return `{{if ne ${field} nil}}${name}="{{${this.convertExpressionToGo(value.expr)}}}"{{end}}`
5107
+ }
4889
5108
  return `${name}="{{${this.convertExpressionToGo(value.expr)}}}"`
4890
5109
  },
4891
5110
  emitBooleanAttr: (_value, name) => name,