@barefootjs/hono 0.5.0 → 0.5.1

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.
@@ -78,7 +78,7 @@ export declare class HonoAdapter extends JsxAdapter implements IRNodeEmitter<Hon
78
78
  emitElement(node: IRElement, ctx: HonoRenderCtx, _emit: EmitIRNode<HonoRenderCtx>): string;
79
79
  emitText(node: IRText): string;
80
80
  emitExpression(node: IRExpression): string;
81
- emitConditional(node: IRConditional, _ctx: HonoRenderCtx, _emit: EmitIRNode<HonoRenderCtx>): string;
81
+ emitConditional(node: IRConditional, ctx: HonoRenderCtx, _emit: EmitIRNode<HonoRenderCtx>): string;
82
82
  emitLoop(node: IRLoop, _ctx: HonoRenderCtx, _emit: EmitIRNode<HonoRenderCtx>): string;
83
83
  emitComponent(node: IRComponent, ctx: HonoRenderCtx, _emit: EmitIRNode<HonoRenderCtx>): string;
84
84
  emitFragment(node: IRFragment, _ctx: HonoRenderCtx, _emit: EmitIRNode<HonoRenderCtx>): string;
@@ -91,7 +91,14 @@ export declare class HonoAdapter extends JsxAdapter implements IRNodeEmitter<Hon
91
91
  }): string;
92
92
  private renderText;
93
93
  renderExpression(expr: IRExpression): string;
94
- renderConditional(cond: IRConditional): string;
94
+ renderConditional(cond: IRConditional, ctx?: HonoRenderCtx): string;
95
+ /**
96
+ * Like the base `renderNodeRaw`, but threads a render ctx through to
97
+ * `renderNode` so a conditional branch can mark its element as a loop item
98
+ * root (#1665). The `null` / `undefined` expression branch carries no
99
+ * element, so it short-circuits exactly as the base helper does.
100
+ */
101
+ private renderNodeRawCtx;
95
102
  private wrapWithCondMarker;
96
103
  renderLoop(loop: IRLoop): string;
97
104
  private renderChildrenInLoop;
@@ -1 +1 @@
1
- {"version":3,"file":"hono-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/hono-adapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hono-adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/hono-adapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,MAAM,EACX,KAAK,SAAS,EACd,KAAK,MAAM,EACX,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,MAAM,EACX,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,MAAM,EAIX,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAElB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,UAAU,EAEf,UAAU,EAMX,MAAM,iBAAiB,CAAA;AAExB;;;;;GAKG;AACH,KAAK,aAAa,GAAG;IACnB,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB,CAAA;AAGD,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAEzB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IAEvB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAEzB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAuBD,qBAAa,WAAY,SAAQ,UAAW,YAAW,aAAa,CAAC,aAAa,CAAC;IACjF,IAAI,SAAS;IACb,SAAS,SAAS;IAClB,gBAAgB,SAAiC;IAGjD,kBAAkB,EAAG,WAAW,CAAS;IAmBzC,mBAAmB,QAAO,OAAO,CAAQ;IAEzC,SAAS,CAAC,SAAS,EAAE,gBAAgB,CAA0B;IAE/D,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,iBAAiB,CAAiB;IAC1C,OAAO,CAAC,sBAAsB,CAAiB;IAC/C,OAAO,CAAC,wBAAwB,CAAiB;IACjD;;;;;;;OAOG;IACH,OAAO,CAAC,qBAAqB,CAAC,CAAgC;IAC9D,uFAAuF;IACvF,OAAO,CAAC,YAAY,CAAmD;IAEvE,YAAY,OAAO,GAAE,kBAAuB,EAQ3C;IAED,QAAQ,CAAC,EAAE,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,aAAa,CAyCzE;IAED,OAAO,CAAC,kCAAkC;IAkB1C,OAAO,CAAC,eAAe;IAyDvB,aAAa,CAAC,EAAE,EAAE,WAAW,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA+EpE;IAED,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,iBAAiB;IAoOzB;;;;OAIG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,aAAa,GAAG,MAAM,CAEpD;IAMD,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAEzF;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7B;IAED,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAEzC;IAED,eAAe,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAEjG;IAED,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAEpF;IAED,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAE7F;IAED,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAE5F;IAED,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE9B;IAED,eAAe,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAKnG;IAED,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAwB5F;IAED,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,GAAG,MAAM,CAEtF;IAED,aAAa,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,MAAM,CAwC5E;IAED,OAAO,CAAC,UAAU;IAIlB,gBAAgB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAgB3C;IAED,iBAAiB,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,CAAC,EAAE,aAAa,GAAG,MAAM,CAiClE;IAED;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,kBAAkB;IA2B1B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAyF/B;IAED,OAAO,CAAC,oBAAoB;IAI5B;;;OAGG;IACH,iBAAiB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,CAAC,EAAE;QAAE,uBAAuB,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,MAAM,CA4C5F;IAED,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAIjC;IAED,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE;QAAE,uBAAuB,CAAC,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAC;QAAC,cAAc,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,MAAM,CAiDxI;IAED,OAAO,CAAC,cAAc;IAQtB;;;;;;OAMG;IACH,OAAO,CAAC,oBAAoB;IAY5B;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAmBlC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAepC;IAED,OAAO,CAAC,gBAAgB;IAiBxB,OAAO,CAAC,oBAAoB;IAyB5B,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,0BAA0B;CAwBnC;AAGD,eAAO,MAAM,WAAW,aAAoB,CAAA"}
@@ -260,9 +260,13 @@ export default ${this.componentName}` : "";
260
260
  }
261
261
  fullPropsDestructure = `{ ${parts.join(", ")} }`;
262
262
  }
263
+ const hasRequiredProps = ir.metadata.propsParams.some((p) => !p.optional && p.defaultValue === undefined && !p.isRest);
264
+ const wantsNoArgDefault = propsObjectName ? !propsTypeName : !hasRequiredProps;
265
+ const propsTypeExpr = typeAnnotation.replace(/^:\s*/, "");
266
+ const noArgDefault = wantsNoArgDefault ? ` = {} as ${propsTypeExpr}` : "";
263
267
  const lines = [];
264
268
  const exportPrefix = ir.metadata.isExported === false ? "" : "export ";
265
- lines.push(`${exportPrefix}function ${name}(${fullPropsDestructure}${typeAnnotation}) {`);
269
+ lines.push(`${exportPrefix}function ${name}(${fullPropsDestructure}${typeAnnotation}${noArgDefault}) {`);
266
270
  if (propsExtraction) {
267
271
  lines.push(propsExtraction);
268
272
  }
@@ -313,8 +317,8 @@ export default ${this.componentName}` : "";
313
317
  emitExpression(node) {
314
318
  return this.renderExpression(node);
315
319
  }
316
- emitConditional(node, _ctx, _emit) {
317
- return this.renderConditional(node);
320
+ emitConditional(node, ctx, _emit) {
321
+ return this.renderConditional(node, ctx);
318
322
  }
319
323
  emitLoop(node, _ctx, _emit) {
320
324
  return this.renderLoop(node);
@@ -401,12 +405,13 @@ export default ${this.componentName}` : "";
401
405
  }
402
406
  return `{${expr.expr}}`;
403
407
  }
404
- renderConditional(cond) {
408
+ renderConditional(cond, ctx) {
405
409
  if (cond.clientOnly && cond.slotId) {
406
410
  return `{bfComment("cond-start:${cond.slotId}")}{bfComment("cond-end:${cond.slotId}")}`;
407
411
  }
408
- const whenTrue = this.renderNodeRaw(cond.whenTrue);
409
- let whenFalse = this.renderNodeRaw(cond.whenFalse);
412
+ const branchCtx = ctx?.isLoopItemRoot ? { isLoopItemRoot: true } : undefined;
413
+ const whenTrue = this.renderNodeRawCtx(cond.whenTrue, branchCtx);
414
+ let whenFalse = this.renderNodeRawCtx(cond.whenFalse, branchCtx);
410
415
  if (!whenFalse || whenFalse === "" || whenFalse === "null") {
411
416
  whenFalse = "null";
412
417
  }
@@ -417,6 +422,14 @@ export default ${this.componentName}` : "";
417
422
  }
418
423
  return `{${cond.condition} ? ${whenTrue} : ${whenFalse}}`;
419
424
  }
425
+ renderNodeRawCtx(node, ctx) {
426
+ if (node.type === "expression") {
427
+ if (node.expr === "null" || node.expr === "undefined")
428
+ return "null";
429
+ return node.expr;
430
+ }
431
+ return this.renderNode(node, ctx);
432
+ }
420
433
  wrapWithCondMarker(node, content, condId) {
421
434
  if (node.type === "component") {
422
435
  return `<>{bfComment("cond-start:${condId}")}${content}{bfComment("cond-end:${condId}")}</>`;
@@ -447,6 +460,8 @@ export default ${this.componentName}` : "";
447
460
  let safeChildren = children.startsWith("{") ? `<>${children}</>` : children;
448
461
  if (loop.bodyIsMultiRoot) {
449
462
  safeChildren = `<>{bfComment('bf-loop-i')}${children}</>`;
463
+ } else if (loop.bodyIsItemConditional && loop.key) {
464
+ safeChildren = `<>{bfComment('loop-i:' + String(${loop.key}))}${children}</>`;
450
465
  }
451
466
  let chainedArray = applyHonoLoopChain(loop);
452
467
  const iterMethod = loop.method ?? "map";
package/dist/build.js CHANGED
@@ -260,9 +260,13 @@ export default ${this.componentName}` : "";
260
260
  }
261
261
  fullPropsDestructure = `{ ${parts.join(", ")} }`;
262
262
  }
263
+ const hasRequiredProps = ir.metadata.propsParams.some((p) => !p.optional && p.defaultValue === undefined && !p.isRest);
264
+ const wantsNoArgDefault = propsObjectName ? !propsTypeName : !hasRequiredProps;
265
+ const propsTypeExpr = typeAnnotation.replace(/^:\s*/, "");
266
+ const noArgDefault = wantsNoArgDefault ? ` = {} as ${propsTypeExpr}` : "";
263
267
  const lines = [];
264
268
  const exportPrefix = ir.metadata.isExported === false ? "" : "export ";
265
- lines.push(`${exportPrefix}function ${name}(${fullPropsDestructure}${typeAnnotation}) {`);
269
+ lines.push(`${exportPrefix}function ${name}(${fullPropsDestructure}${typeAnnotation}${noArgDefault}) {`);
266
270
  if (propsExtraction) {
267
271
  lines.push(propsExtraction);
268
272
  }
@@ -313,8 +317,8 @@ export default ${this.componentName}` : "";
313
317
  emitExpression(node) {
314
318
  return this.renderExpression(node);
315
319
  }
316
- emitConditional(node, _ctx, _emit) {
317
- return this.renderConditional(node);
320
+ emitConditional(node, ctx, _emit) {
321
+ return this.renderConditional(node, ctx);
318
322
  }
319
323
  emitLoop(node, _ctx, _emit) {
320
324
  return this.renderLoop(node);
@@ -401,12 +405,13 @@ export default ${this.componentName}` : "";
401
405
  }
402
406
  return `{${expr.expr}}`;
403
407
  }
404
- renderConditional(cond) {
408
+ renderConditional(cond, ctx) {
405
409
  if (cond.clientOnly && cond.slotId) {
406
410
  return `{bfComment("cond-start:${cond.slotId}")}{bfComment("cond-end:${cond.slotId}")}`;
407
411
  }
408
- const whenTrue = this.renderNodeRaw(cond.whenTrue);
409
- let whenFalse = this.renderNodeRaw(cond.whenFalse);
412
+ const branchCtx = ctx?.isLoopItemRoot ? { isLoopItemRoot: true } : undefined;
413
+ const whenTrue = this.renderNodeRawCtx(cond.whenTrue, branchCtx);
414
+ let whenFalse = this.renderNodeRawCtx(cond.whenFalse, branchCtx);
410
415
  if (!whenFalse || whenFalse === "" || whenFalse === "null") {
411
416
  whenFalse = "null";
412
417
  }
@@ -417,6 +422,14 @@ export default ${this.componentName}` : "";
417
422
  }
418
423
  return `{${cond.condition} ? ${whenTrue} : ${whenFalse}}`;
419
424
  }
425
+ renderNodeRawCtx(node, ctx) {
426
+ if (node.type === "expression") {
427
+ if (node.expr === "null" || node.expr === "undefined")
428
+ return "null";
429
+ return node.expr;
430
+ }
431
+ return this.renderNode(node, ctx);
432
+ }
420
433
  wrapWithCondMarker(node, content, condId) {
421
434
  if (node.type === "component") {
422
435
  return `<>{bfComment("cond-start:${condId}")}${content}{bfComment("cond-end:${condId}")}</>`;
@@ -447,6 +460,8 @@ export default ${this.componentName}` : "";
447
460
  let safeChildren = children.startsWith("{") ? `<>${children}</>` : children;
448
461
  if (loop.bodyIsMultiRoot) {
449
462
  safeChildren = `<>{bfComment('bf-loop-i')}${children}</>`;
463
+ } else if (loop.bodyIsItemConditional && loop.key) {
464
+ safeChildren = `<>{bfComment('loop-i:' + String(${loop.key}))}${children}</>`;
450
465
  }
451
466
  let chainedArray = applyHonoLoopChain(loop);
452
467
  const iterMethod = loop.method ?? "map";
package/dist/index.js CHANGED
@@ -260,9 +260,13 @@ export default ${this.componentName}` : "";
260
260
  }
261
261
  fullPropsDestructure = `{ ${parts.join(", ")} }`;
262
262
  }
263
+ const hasRequiredProps = ir.metadata.propsParams.some((p) => !p.optional && p.defaultValue === undefined && !p.isRest);
264
+ const wantsNoArgDefault = propsObjectName ? !propsTypeName : !hasRequiredProps;
265
+ const propsTypeExpr = typeAnnotation.replace(/^:\s*/, "");
266
+ const noArgDefault = wantsNoArgDefault ? ` = {} as ${propsTypeExpr}` : "";
263
267
  const lines = [];
264
268
  const exportPrefix = ir.metadata.isExported === false ? "" : "export ";
265
- lines.push(`${exportPrefix}function ${name}(${fullPropsDestructure}${typeAnnotation}) {`);
269
+ lines.push(`${exportPrefix}function ${name}(${fullPropsDestructure}${typeAnnotation}${noArgDefault}) {`);
266
270
  if (propsExtraction) {
267
271
  lines.push(propsExtraction);
268
272
  }
@@ -313,8 +317,8 @@ export default ${this.componentName}` : "";
313
317
  emitExpression(node) {
314
318
  return this.renderExpression(node);
315
319
  }
316
- emitConditional(node, _ctx, _emit) {
317
- return this.renderConditional(node);
320
+ emitConditional(node, ctx, _emit) {
321
+ return this.renderConditional(node, ctx);
318
322
  }
319
323
  emitLoop(node, _ctx, _emit) {
320
324
  return this.renderLoop(node);
@@ -401,12 +405,13 @@ export default ${this.componentName}` : "";
401
405
  }
402
406
  return `{${expr.expr}}`;
403
407
  }
404
- renderConditional(cond) {
408
+ renderConditional(cond, ctx) {
405
409
  if (cond.clientOnly && cond.slotId) {
406
410
  return `{bfComment("cond-start:${cond.slotId}")}{bfComment("cond-end:${cond.slotId}")}`;
407
411
  }
408
- const whenTrue = this.renderNodeRaw(cond.whenTrue);
409
- let whenFalse = this.renderNodeRaw(cond.whenFalse);
412
+ const branchCtx = ctx?.isLoopItemRoot ? { isLoopItemRoot: true } : undefined;
413
+ const whenTrue = this.renderNodeRawCtx(cond.whenTrue, branchCtx);
414
+ let whenFalse = this.renderNodeRawCtx(cond.whenFalse, branchCtx);
410
415
  if (!whenFalse || whenFalse === "" || whenFalse === "null") {
411
416
  whenFalse = "null";
412
417
  }
@@ -417,6 +422,14 @@ export default ${this.componentName}` : "";
417
422
  }
418
423
  return `{${cond.condition} ? ${whenTrue} : ${whenFalse}}`;
419
424
  }
425
+ renderNodeRawCtx(node, ctx) {
426
+ if (node.type === "expression") {
427
+ if (node.expr === "null" || node.expr === "undefined")
428
+ return "null";
429
+ return node.expr;
430
+ }
431
+ return this.renderNode(node, ctx);
432
+ }
420
433
  wrapWithCondMarker(node, content, condId) {
421
434
  if (node.type === "component") {
422
435
  return `<>{bfComment("cond-start:${condId}")}${content}{bfComment("cond-end:${condId}")}</>`;
@@ -447,6 +460,8 @@ export default ${this.componentName}` : "";
447
460
  let safeChildren = children.startsWith("{") ? `<>${children}</>` : children;
448
461
  if (loop.bodyIsMultiRoot) {
449
462
  safeChildren = `<>{bfComment('bf-loop-i')}${children}</>`;
463
+ } else if (loop.bodyIsItemConditional && loop.key) {
464
+ safeChildren = `<>{bfComment('loop-i:' + String(${loop.key}))}${children}</>`;
450
465
  }
451
466
  let chainedArray = applyHonoLoopChain(loop);
452
467
  const iterMethod = loop.method ?? "map";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/hono",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Hono integration for BarefootJS",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -510,11 +510,28 @@ export class HonoAdapter extends JsxAdapter implements IRNodeEmitter<HonoRenderC
510
510
  fullPropsDestructure = `{ ${parts.join(', ')} }`
511
511
  }
512
512
 
513
+ // Default the props param to `{}` when the component has no required
514
+ // props, so a bare no-arg call (`Foo()`) doesn't crash on destructuring
515
+ // `undefined`. This makes a JSX-returning arrow hoisted from an
516
+ // object-literal value (e.g. `THEME_LOGOS[id]()`) renderable at SSR
517
+ // (#1663). `hasRequiredProps` ignores props that carry a destructuring
518
+ // default, but the declared props type may still mark that field
519
+ // required — so a bare `= {}` would fail `tsc`. Assert the default to the
520
+ // param's own annotated type (`{} as T`); the destructuring defaults
521
+ // supply the values at runtime. The SolidJS-style (`propsObjectName`)
522
+ // branch opts in whenever the annotation is satisfiable by `{} as T`.
523
+ const hasRequiredProps = ir.metadata.propsParams.some(
524
+ (p: ParamInfo) => !p.optional && p.defaultValue === undefined && !p.isRest,
525
+ )
526
+ const wantsNoArgDefault = propsObjectName ? !propsTypeName : !hasRequiredProps
527
+ const propsTypeExpr = typeAnnotation.replace(/^:\s*/, '')
528
+ const noArgDefault = wantsNoArgDefault ? ` = {} as ${propsTypeExpr}` : ''
529
+
513
530
  const lines: string[] = []
514
531
  // Module-export keyword belongs to the adapter: it knows the target language
515
532
  // and whether the source declared the component as exported.
516
533
  const exportPrefix = ir.metadata.isExported === false ? '' : 'export '
517
- lines.push(`${exportPrefix}function ${name}(${fullPropsDestructure}${typeAnnotation}) {`)
534
+ lines.push(`${exportPrefix}function ${name}(${fullPropsDestructure}${typeAnnotation}${noArgDefault}) {`)
518
535
 
519
536
  // Add props extraction for SolidJS-style pattern
520
537
  if (propsExtraction) {
@@ -600,8 +617,8 @@ export class HonoAdapter extends JsxAdapter implements IRNodeEmitter<HonoRenderC
600
617
  return this.renderExpression(node)
601
618
  }
602
619
 
603
- emitConditional(node: IRConditional, _ctx: HonoRenderCtx, _emit: EmitIRNode<HonoRenderCtx>): string {
604
- return this.renderConditional(node)
620
+ emitConditional(node: IRConditional, ctx: HonoRenderCtx, _emit: EmitIRNode<HonoRenderCtx>): string {
621
+ return this.renderConditional(node, ctx)
605
622
  }
606
623
 
607
624
  emitLoop(node: IRLoop, _ctx: HonoRenderCtx, _emit: EmitIRNode<HonoRenderCtx>): string {
@@ -721,14 +738,21 @@ export class HonoAdapter extends JsxAdapter implements IRNodeEmitter<HonoRenderC
721
738
  return `{${expr.expr}}`
722
739
  }
723
740
 
724
- renderConditional(cond: IRConditional): string {
741
+ renderConditional(cond: IRConditional, ctx?: HonoRenderCtx): string {
725
742
  // Handle @client directive - render comment markers for client-side evaluation
726
743
  if (cond.clientOnly && cond.slotId) {
727
744
  return `{bfComment("cond-start:${cond.slotId}")}{bfComment("cond-end:${cond.slotId}")}`
728
745
  }
729
746
 
730
- const whenTrue = this.renderNodeRaw(cond.whenTrue)
731
- let whenFalse = this.renderNodeRaw(cond.whenFalse)
747
+ // A conditional that is itself a loop item root (#1665 whole-item
748
+ // conditional: `arr.map(t => cond && <li/>)`) makes its branch element the
749
+ // loop item's root, so the `data-key` that reconciliation/hydration expect
750
+ // belongs on that element — exactly like a non-conditional loop root. Pass
751
+ // the flag through so `renderElement` emits `data-key`, matching the Go /
752
+ // CSR adapters' generic `key`→`data-key` rewrite.
753
+ const branchCtx: HonoRenderCtx | undefined = ctx?.isLoopItemRoot ? { isLoopItemRoot: true } : undefined
754
+ const whenTrue = this.renderNodeRawCtx(cond.whenTrue, branchCtx)
755
+ let whenFalse = this.renderNodeRawCtx(cond.whenFalse, branchCtx)
732
756
 
733
757
  // Handle empty/null whenFalse
734
758
  if (!whenFalse || whenFalse === '' || whenFalse === 'null') {
@@ -749,6 +773,20 @@ export class HonoAdapter extends JsxAdapter implements IRNodeEmitter<HonoRenderC
749
773
  return `{${cond.condition} ? ${whenTrue} : ${whenFalse}}`
750
774
  }
751
775
 
776
+ /**
777
+ * Like the base `renderNodeRaw`, but threads a render ctx through to
778
+ * `renderNode` so a conditional branch can mark its element as a loop item
779
+ * root (#1665). The `null` / `undefined` expression branch carries no
780
+ * element, so it short-circuits exactly as the base helper does.
781
+ */
782
+ private renderNodeRawCtx(node: IRNode, ctx?: HonoRenderCtx): string {
783
+ if (node.type === 'expression') {
784
+ if (node.expr === 'null' || node.expr === 'undefined') return 'null'
785
+ return node.expr
786
+ }
787
+ return this.renderNode(node, ctx)
788
+ }
789
+
752
790
  private wrapWithCondMarker(node: IRNode, content: string, condId: string): string {
753
791
  // Components don't reliably forward bf-c to their root element.
754
792
  // Use comment markers so insert() can find them via TreeWalker.
@@ -816,6 +854,14 @@ export class HonoAdapter extends JsxAdapter implements IRNodeEmitter<HonoRenderC
816
854
  // literal here to match the adapter's existing convention of
817
855
  // emitting comment-marker strings directly.
818
856
  safeChildren = `<>{bfComment('bf-loop-i')}${children}</>`
857
+ } else if (loop.bodyIsItemConditional && loop.key) {
858
+ // Whole-item conditional (#1665): a per-item `<!--bf-loop-i:KEY-->`
859
+ // anchor that is ALWAYS present (even when the item's conditional
860
+ // renders nothing), carrying the key so the client's
861
+ // `mapArrayAnchored` can hydrate every SSR-rendered item by its anchor.
862
+ // `bfComment(k)` emits `<!--bf-${k}-->`, so the `loop-i:` argument
863
+ // yields `<!--bf-loop-i:KEY-->`.
864
+ safeChildren = `<>{bfComment('loop-i:' + String(${loop.key}))}${children}</>`
819
865
  }
820
866
  // Apply chained `.sort()` / `.filter()` extracted to
821
867
  // `loop.sortComparator` / `loop.filterPredicate` (#1448 Tier B).