@barefootjs/hono 0.31.1 → 0.31.2

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.
Files changed (35) hide show
  1. package/dist/adapter/hono-adapter.d.ts +67 -2
  2. package/dist/adapter/hono-adapter.d.ts.map +1 -1
  3. package/dist/adapter/index.js +46 -187398
  4. package/dist/app.js +0 -71
  5. package/dist/async.js +0 -71
  6. package/dist/client-shim.js +0 -71
  7. package/dist/dev-worker.js +0 -71
  8. package/dist/dialog-context.js +0 -71
  9. package/dist/index.js +46 -187398
  10. package/dist/jsx/jsx-dev-runtime/index.d.ts +3 -1
  11. package/dist/jsx/jsx-dev-runtime/index.d.ts.map +1 -1
  12. package/dist/jsx/jsx-dev-runtime/index.js +14 -69
  13. package/dist/jsx/jsx-runtime/index.d.ts +4 -1
  14. package/dist/jsx/jsx-runtime/index.d.ts.map +1 -1
  15. package/dist/jsx/jsx-runtime/index.js +24 -69
  16. package/dist/jsx/resolve-dangerously-set-inner-html.d.ts +2 -0
  17. package/dist/jsx/resolve-dangerously-set-inner-html.d.ts.map +1 -0
  18. package/dist/portal-ssr.js +0 -71
  19. package/dist/portals.js +0 -71
  20. package/dist/preload.js +0 -71
  21. package/dist/render.js +0 -71
  22. package/dist/request-env.js +0 -71
  23. package/dist/scripts.js +0 -71
  24. package/dist/utils.js +0 -71
  25. package/dist/vite.js +313 -142
  26. package/package.json +2 -2
  27. package/src/__tests__/aliased-destructured-prop.test.ts +8 -7
  28. package/src/__tests__/consumer-typecheck.test.ts +358 -51
  29. package/src/__tests__/corpus-typecheck.test.ts +130 -0
  30. package/src/__tests__/dangerously-set-inner-html.test.ts +70 -0
  31. package/src/__tests__/nested-ternary-bare-branch.test.ts +70 -0
  32. package/src/adapter/hono-adapter.ts +123 -166
  33. package/src/jsx/jsx-dev-runtime/index.ts +13 -1
  34. package/src/jsx/jsx-runtime/index.ts +24 -1
  35. package/src/jsx/resolve-dangerously-set-inner-html.ts +34 -0
package/dist/vite.js CHANGED
@@ -4,8 +4,11 @@ import { dirname, resolve } from "node:path";
4
4
  import { barefoot as coreBarefoot } from "@barefootjs/vite";
5
5
  import { devModuleUrl, loadManifest, resolveDevOrigin, resolveScriptAssets, toPosixRelative } from "@barefootjs/vite";
6
6
 
7
+ // ../jsx/src/compiler.ts
8
+ import ts23 from "typescript";
9
+
7
10
  // ../jsx/src/analyzer.ts
8
- import ts8 from "typescript";
11
+ import ts9 from "typescript";
9
12
 
10
13
  // ../jsx/src/expression-parser.ts
11
14
  import ts from "typescript";
@@ -98,6 +101,29 @@ function buildLoopChainExpr(opts) {
98
101
  return `${opts.base}${sortExpr}${filterExpr}`;
99
102
  }
100
103
 
104
+ // ../jsx/src/template-parts.ts
105
+ function lookupPartToJsExpr(part, opts) {
106
+ const key = opts?.useTemplate && part.templateKey ? part.templateKey : part.key;
107
+ const obj = "{" + Object.entries(part.cases).map(([k, v]) => `${JSON.stringify(k)}: ${JSON.stringify(v)}`).join(", ") + "}";
108
+ const typed = opts?.typed ? " as Record<string, string>" : "";
109
+ return `(${obj}${typed})[${key}]`;
110
+ }
111
+ function templatePartsToJsExpr(parts, opts) {
112
+ let result = "`";
113
+ for (const part of parts) {
114
+ if (part.type === "string") {
115
+ result += opts?.useTemplate && part.templateValue ? part.templateValue : part.value;
116
+ } else if (part.type === "ternary") {
117
+ const cond = opts?.useTemplate && part.templateCondition ? part.templateCondition : part.condition;
118
+ result += `\${${cond} ? '${part.whenTrue}' : '${part.whenFalse}'}`;
119
+ } else if (part.type === "lookup") {
120
+ result += `\${${lookupPartToJsExpr(part, opts)}}`;
121
+ }
122
+ }
123
+ result += "`";
124
+ return result;
125
+ }
126
+
101
127
  // ../jsx/src/scanner/js-scanner.ts
102
128
  import ts2 from "typescript";
103
129
 
@@ -203,6 +229,16 @@ function escapeHtml(text) {
203
229
  }
204
230
  // ../jsx/src/ir-to-client-js/csr-substitute.ts
205
231
  import ts4 from "typescript";
232
+ function extractFreeIdentifiersFromText(text) {
233
+ if (!text || text.trim().length === 0)
234
+ return new Set;
235
+ const sf = ts4.createSourceFile("__free_ids__.ts", `(${text});`, ts4.ScriptTarget.Latest, true, ts4.ScriptKind.TS);
236
+ const stmt = sf.statements[0];
237
+ if (!stmt || !ts4.isExpressionStatement(stmt))
238
+ return new Set;
239
+ const expr = ts4.isParenthesizedExpression(stmt.expression) ? stmt.expression.expression : stmt.expression;
240
+ return extractFreeIdentifiersFromNode(expr);
241
+ }
206
242
 
207
243
  // ../jsx/src/ir-to-client-js/html-template.ts
208
244
  var VOID_ELEMENTS = new Set([
@@ -248,6 +284,27 @@ var SKELETON_PATH_FORCE_CLOSE_GROUPS = [
248
284
  new Set(["li"])
249
285
  ];
250
286
 
287
+ // ../jsx/src/props-binding.ts
288
+ import ts6 from "typescript";
289
+ function isIdentifierName(key) {
290
+ if (key.length === 0)
291
+ return false;
292
+ for (let i = 0;i < key.length; ) {
293
+ const cp = key.codePointAt(i);
294
+ const ok = i === 0 ? ts6.isIdentifierStart(cp, ts6.ScriptTarget.Latest) : ts6.isIdentifierPart(cp, ts6.ScriptTarget.Latest);
295
+ if (!ok)
296
+ return false;
297
+ i += cp > 65535 ? 2 : 1;
298
+ }
299
+ return true;
300
+ }
301
+ function propsDestructureBinding(p) {
302
+ const callerKey = p.sourceName ?? p.name;
303
+ const localName = p.name;
304
+ const binding = callerKey === localName ? localName : `${isIdentifierName(callerKey) ? callerKey : JSON.stringify(callerKey)}: ${localName}`;
305
+ return p.defaultValue ? `${binding} = ${p.defaultValue}` : binding;
306
+ }
307
+
251
308
  // ../jsx/src/instrumentation.ts
252
309
  var _counters = freshCounters();
253
310
  function freshCounters() {
@@ -261,14 +318,14 @@ function freshCounters() {
261
318
  }
262
319
 
263
320
  // ../jsx/src/analyzer-context.ts
264
- import ts7 from "typescript";
321
+ import ts8 from "typescript";
265
322
 
266
323
  // ../jsx/src/strip-types.ts
267
- import ts6 from "typescript";
324
+ import ts7 from "typescript";
268
325
 
269
326
  // ../jsx/src/analyzer-context.ts
270
- var _typePrinter = ts7.createPrinter({ removeComments: true, omitTrailingSemicolon: true });
271
- var _blankTypeSourceFile = ts7.createSourceFile("__bf_types__.ts", "", ts7.ScriptTarget.Latest);
327
+ var _typePrinter = ts8.createPrinter({ removeComments: true, omitTrailingSemicolon: true });
328
+ var _blankTypeSourceFile = ts8.createSourceFile("__bf_types__.ts", "", ts8.ScriptTarget.Latest);
272
329
 
273
330
  // ../jsx/src/errors.ts
274
331
  var ErrorCodes = {
@@ -284,6 +341,7 @@ var ErrorCodes = {
284
341
  JSX_IN_LOCAL_FUNCTION: "BF045",
285
342
  COMPONENT_REQUIRED_PROP_MISSING: "BF046",
286
343
  JSX_BRANCH_LOCAL_IN_CALLBACK: "BF047",
344
+ SIBLING_COMPONENT_NOT_COMPILED: "BF048",
287
345
  SHARED_PROGRAM_REQUIRED: "BF050",
288
346
  WRONG_PACKAGE_IMPORT: "BF051",
289
347
  BUILTIN_REQUIRES_IMPORT: "BF054",
@@ -313,6 +371,7 @@ var errorMessages = {
313
371
  [ErrorCodes.JSX_IN_LOCAL_FUNCTION]: "Local function returns JSX but cannot be inlined. Extract it as a top-level PascalCase component or use a single return statement.",
314
372
  [ErrorCodes.COMPONENT_REQUIRED_PROP_MISSING]: "Built-in component is missing a required prop.",
315
373
  [ErrorCodes.JSX_BRANCH_LOCAL_IN_CALLBACK]: "JSX-typed local declared inside an `if`-block cannot be referenced from a callback body (ref / event handler). " + "Render it as a child instead: `<div ref={...}>{local}</div>`.",
374
+ [ErrorCodes.SIBLING_COMPONENT_NOT_COMPILED]: "Referenced component did not compile to a template, so this reference would throw " + "`ReferenceError` at render time. Multi-return JSX dispatch (a `switch` or `if`/`else` " + "chain across multiple JSX-returning branches) cannot compile as a component in a " + `'use client' file. Extract it to a separate non-"use client" file (where it is preserved ` + "verbatim, see #932), or rewrite it as a single-return ternary/conditional chain so the " + "component pipeline can compile it.",
316
375
  [ErrorCodes.SHARED_PROGRAM_REQUIRED]: "Shared ts.Program required for type-based reactivity classification. This source imports a Reactive<T>-branded library (e.g. @barefootjs/form) whose getters cannot be classified by regex alone. Pass `options.program` (built via `createProgramForCorpus`) so the analyzer can resolve the brand through the TypeChecker.",
317
376
  [ErrorCodes.WRONG_PACKAGE_IMPORT]: "Import from wrong package.",
318
377
  [ErrorCodes.BUILTIN_REQUIRES_IMPORT]: "Built-in <Async> / <Region> must be imported from '@barefootjs/client'. " + "The compiler recognises these tags by their import (not by tag name), " + "so an unimported tag with this name is treated as an undeclared component.",
@@ -486,6 +545,54 @@ var CLIENT_EXPORTS = new Set([
486
545
  "Async",
487
546
  "Region"
488
547
  ]);
548
+ function extractFreeIdentifiersFromNode(node) {
549
+ const ids = new Set;
550
+ const boundNames = new Set;
551
+ function addBindingNames(name, out) {
552
+ if (ts9.isIdentifier(name))
553
+ out.push(name.text);
554
+ else if (ts9.isObjectBindingPattern(name))
555
+ name.elements.forEach((e) => addBindingNames(e.name, out));
556
+ else if (ts9.isArrayBindingPattern(name))
557
+ name.elements.forEach((e) => {
558
+ if (!ts9.isOmittedExpression(e))
559
+ addBindingNames(e.name, out);
560
+ });
561
+ }
562
+ function visit(n) {
563
+ if (ts9.isTypeNode(n))
564
+ return;
565
+ if (ts9.isIdentifier(n)) {
566
+ const parent = n.parent;
567
+ if (parent && ts9.isPropertyAccessExpression(parent) && parent.name === n)
568
+ return;
569
+ if (parent && ts9.isPropertyAssignment(parent) && parent.name === n)
570
+ return;
571
+ if (parent && ts9.isParameter(parent) && parent.name === n)
572
+ return;
573
+ if (parent && ts9.isVariableDeclaration(parent) && parent.name === n)
574
+ return;
575
+ if (boundNames.has(n.text))
576
+ return;
577
+ ids.add(n.text);
578
+ return;
579
+ }
580
+ if (ts9.isArrowFunction(n)) {
581
+ const params = [];
582
+ for (const p of n.parameters)
583
+ addBindingNames(p.name, params);
584
+ for (const name of params)
585
+ boundNames.add(name);
586
+ ts9.forEachChild(n, visit);
587
+ for (const name of params)
588
+ boundNames.delete(name);
589
+ return;
590
+ }
591
+ ts9.forEachChild(n, visit);
592
+ }
593
+ visit(node);
594
+ return ids;
595
+ }
489
596
  var BROWSER_ONLY_CLIENT_APIS = new Set([
490
597
  "useContext",
491
598
  "provideContext",
@@ -504,7 +611,7 @@ var REACTIVE_PRIMITIVES = new Set([
504
611
  ]);
505
612
 
506
613
  // ../jsx/src/jsx-to-ir.ts
507
- import ts11 from "typescript";
614
+ import ts12 from "typescript";
508
615
 
509
616
  // ../jsx/src/types.ts
510
617
  var SCOPE_FORBIDDEN = {
@@ -572,10 +679,10 @@ function findReachableNames(primaryRefs, declarations) {
572
679
  }
573
680
 
574
681
  // ../jsx/src/reactivity-checker.ts
575
- import ts9 from "typescript";
682
+ import ts10 from "typescript";
576
683
 
577
684
  // ../jsx/src/free-refs.ts
578
- import ts10 from "typescript";
685
+ import ts11 from "typescript";
579
686
  var _bindingMapCache = new WeakMap;
580
687
 
581
688
  // ../jsx/src/to-locale-date-lowering.ts
@@ -989,13 +1096,13 @@ var KEYWORDS_AND_GLOBALS = new Set([
989
1096
  ]);
990
1097
 
991
1098
  // ../jsx/src/ir-to-client-js/walk-prop-accesses.ts
992
- import ts12 from "typescript";
1099
+ import ts13 from "typescript";
993
1100
 
994
1101
  // ../jsx/src/value-references.ts
995
- import ts13 from "typescript";
1102
+ import ts14 from "typescript";
996
1103
 
997
1104
  // ../jsx/src/relocate.ts
998
- import ts14 from "typescript";
1105
+ import ts15 from "typescript";
999
1106
 
1000
1107
  // ../jsx/src/lowering-registry.ts
1001
1108
  var plugins = [];
@@ -1174,10 +1281,10 @@ function formatDateLocalNames(metadata) {
1174
1281
  }
1175
1282
 
1176
1283
  // ../jsx/src/ir-to-client-js/prune-unused-prop-extractions.ts
1177
- import ts15 from "typescript";
1284
+ import ts16 from "typescript";
1178
1285
 
1179
1286
  // ../jsx/src/ir-to-client-js/control-flow/plan/lazy-preamble.ts
1180
- import ts16 from "typescript";
1287
+ import ts17 from "typescript";
1181
1288
  var NO_PREAMBLE = {
1182
1289
  lazySafe: true,
1183
1290
  facts: { declaredNames: new Set, freeNames: new Set }
@@ -1227,7 +1334,7 @@ var INERT_BINDING_GLOBALS = new Set([
1227
1334
  ]);
1228
1335
 
1229
1336
  // ../jsx/src/ir-to-client-js/emit-reactive.ts
1230
- import ts17 from "typescript";
1337
+ import ts18 from "typescript";
1231
1338
 
1232
1339
  // ../jsx/src/ir-to-client-js/control-flow/stringify/event-delegation.ts
1233
1340
  var NON_BUBBLING_EVENTS = new Set([
@@ -1242,7 +1349,7 @@ var NON_BUBBLING_EVENTS = new Set([
1242
1349
  ]);
1243
1350
 
1244
1351
  // ../jsx/src/ir-to-client-js/rewrite-props-object.ts
1245
- import ts18 from "typescript";
1352
+ import ts19 from "typescript";
1246
1353
 
1247
1354
  // ../jsx/src/ir-to-client-js/source-map.ts
1248
1355
  var BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -1333,20 +1440,20 @@ class SourceMapGenerator {
1333
1440
  }
1334
1441
 
1335
1442
  // ../jsx/src/preprocess-inline-jsx-callbacks.ts
1336
- import ts19 from "typescript";
1443
+ import ts20 from "typescript";
1337
1444
 
1338
1445
  // ../jsx/src/ssr-defaults.ts
1339
- import ts20 from "typescript";
1446
+ import ts21 from "typescript";
1340
1447
  var UNRESOLVED = Symbol("unresolved");
1341
1448
  var NO_RETURN = Symbol("no-return");
1342
1449
 
1343
1450
  // ../jsx/src/augment-inherited-props.ts
1344
- import ts21 from "typescript";
1451
+ import ts22 from "typescript";
1345
1452
 
1346
1453
  // ../jsx/src/rich-type-refusal.ts
1347
1454
  var EMPTY_BINDINGS2 = new Map;
1348
1455
  // ../jsx/src/shared-program.ts
1349
- import ts22 from "typescript";
1456
+ import ts24 from "typescript";
1350
1457
  // ../jsx/src/adapters/interface.ts
1351
1458
  class BaseAdapter {
1352
1459
  renderChildren(children) {
@@ -1422,7 +1529,7 @@ class JsxAdapter extends BaseAdapter {
1422
1529
  }
1423
1530
  const rawInitialValue = preserveTypes ? signal.typedInitialValue ?? signal.initialValue : signal.initialValue;
1424
1531
  const initialValue = rawInitialValue.trim().startsWith("{") ? `(${rawInitialValue})` : rawInitialValue;
1425
- const needsTypeAssertion = preserveTypes && !signal.typedInitialValue && signal.type.kind !== "unknown" && signal.type.kind !== "primitive";
1532
+ const needsTypeAssertion = preserveTypes && !signal.typedInitialValue && signal.type.kind !== "unknown" && signal.type.kind !== "primitive" && signal.type.raw !== "object";
1426
1533
  if (needsTypeAssertion) {
1427
1534
  lines.push(` const ${signal.getter} = () => ${initialValue} as ${signal.type.raw}`);
1428
1535
  } else {
@@ -1441,12 +1548,16 @@ class JsxAdapter extends BaseAdapter {
1441
1548
  const computation = preserveTypes ? memo.typedComputation ?? memo.computation : memo.computation;
1442
1549
  lines.push(` const ${memo.name} = ${computation}`);
1443
1550
  }
1551
+ const moduleScopeNames = this.moduleScopeDeclarationNames(ir);
1444
1552
  for (const constant of ir.metadata.localConstants) {
1445
1553
  if (constant.isExported)
1446
1554
  continue;
1555
+ if (moduleScopeNames.has(constant.name))
1556
+ continue;
1447
1557
  const keyword = constant.declarationKind ?? "const";
1448
1558
  if (!constant.value) {
1449
- lines.push(` ${keyword} ${constant.name}`);
1559
+ const typeAnnotation = preserveTypes && constant.type ? `: ${constant.type.raw}` : "";
1560
+ lines.push(` ${keyword} ${constant.name}${typeAnnotation}`);
1450
1561
  continue;
1451
1562
  }
1452
1563
  const value = constant.value.trim();
@@ -1458,6 +1569,8 @@ class JsxAdapter extends BaseAdapter {
1458
1569
  lines.push(` ${keyword} ${constant.name} = ${constValue}`);
1459
1570
  }
1460
1571
  for (const func of localFunctions) {
1572
+ if (moduleScopeNames.has(func.name))
1573
+ continue;
1461
1574
  if (!reachable.has(func.name))
1462
1575
  continue;
1463
1576
  const params = preserveTypes && func.typedParams !== undefined ? func.typedParams : func.params.map(formatParamWithType).join(", ");
@@ -1467,6 +1580,125 @@ class JsxAdapter extends BaseAdapter {
1467
1580
  lines.push(` ${asyncKw}function ${func.name}(${params})${returnAnnotation} ${body}`);
1468
1581
  }
1469
1582
  return lines.join(`
1583
+ `);
1584
+ }
1585
+ moduleScopeNamesCache = new WeakMap;
1586
+ moduleScopeDeclarationNames(ir) {
1587
+ const cached = this.moduleScopeNamesCache.get(ir);
1588
+ if (cached)
1589
+ return cached;
1590
+ const componentScope = new Set;
1591
+ for (const sig of ir.metadata.signals) {
1592
+ if (sig.isModule)
1593
+ continue;
1594
+ componentScope.add(sig.getter);
1595
+ if (sig.setter)
1596
+ componentScope.add(sig.setter);
1597
+ }
1598
+ for (const memo of ir.metadata.memos) {
1599
+ if (!memo.isModule)
1600
+ componentScope.add(memo.name);
1601
+ }
1602
+ for (const p of ir.metadata.propsParams)
1603
+ componentScope.add(p.name);
1604
+ if (ir.metadata.propsObjectName)
1605
+ componentScope.add(ir.metadata.propsObjectName);
1606
+ if (ir.metadata.restPropsName)
1607
+ componentScope.add(ir.metadata.restPropsName);
1608
+ for (const c of ir.metadata.localConstants) {
1609
+ if (!c.isModule)
1610
+ componentScope.add(c.name);
1611
+ }
1612
+ for (const f of ir.metadata.localFunctions) {
1613
+ if (!f.isModule)
1614
+ componentScope.add(f.name);
1615
+ }
1616
+ const exported = new Set;
1617
+ const candidates = new Map;
1618
+ for (const c of ir.metadata.localConstants) {
1619
+ if (!c.isModule)
1620
+ continue;
1621
+ if (c.isJsx || c.isJsxFunction)
1622
+ continue;
1623
+ if (c.isExported) {
1624
+ exported.add(c.name);
1625
+ continue;
1626
+ }
1627
+ candidates.set(c.name, c.freeIdentifiers ?? extractFreeIdentifiersFromText(c.value ?? ""));
1628
+ }
1629
+ for (const f of ir.metadata.localFunctions) {
1630
+ if (!f.isModule)
1631
+ continue;
1632
+ if (f.isJsxFunction || f.isMultiReturnJsxHelper)
1633
+ continue;
1634
+ if (f.isExported) {
1635
+ exported.add(f.name);
1636
+ continue;
1637
+ }
1638
+ const params = f.typedParams !== undefined ? f.typedParams : f.params.map(formatParamWithType).join(", ");
1639
+ candidates.set(f.name, extractFreeIdentifiersFromText(`(${params}) => ${f.body}`));
1640
+ }
1641
+ const referencesAny = (refs, names) => {
1642
+ for (const ref of refs) {
1643
+ if (names.has(ref))
1644
+ return true;
1645
+ }
1646
+ return false;
1647
+ };
1648
+ let changed = true;
1649
+ while (changed) {
1650
+ changed = false;
1651
+ for (const [name, refs] of candidates) {
1652
+ if (referencesAny(refs, componentScope)) {
1653
+ candidates.delete(name);
1654
+ componentScope.add(name);
1655
+ changed = true;
1656
+ }
1657
+ }
1658
+ }
1659
+ const result = new Set([...exported, ...candidates.keys()]);
1660
+ this.moduleScopeNamesCache.set(ir, result);
1661
+ return result;
1662
+ }
1663
+ generateModuleScopeDeclarations(ir) {
1664
+ const { preserveTypes } = this.jsxConfig;
1665
+ const moduleNames = this.moduleScopeDeclarationNames(ir);
1666
+ const entries = [];
1667
+ for (const t of ir.metadata.typeDefinitions) {
1668
+ entries.push({ line: t.loc.start.line, text: t.definition });
1669
+ }
1670
+ for (const c of ir.metadata.localConstants) {
1671
+ if (!c.isModule || !moduleNames.has(c.name))
1672
+ continue;
1673
+ const keyword = c.declarationKind ?? "const";
1674
+ const exportKw = c.isExported ? "export " : "";
1675
+ if (!c.value) {
1676
+ entries.push({ line: c.loc.start.line, text: `${exportKw}${keyword} ${c.name}` });
1677
+ continue;
1678
+ }
1679
+ const trimmed = c.value.trim();
1680
+ if (/^new WeakMap\b/.test(trimmed))
1681
+ continue;
1682
+ if (c.isExported && /^createContext\b/.test(trimmed))
1683
+ continue;
1684
+ const value = preserveTypes ? c.typedValue ?? c.value : c.value;
1685
+ entries.push({ line: c.loc.start.line, text: `${exportKw}${keyword} ${c.name} = ${value}` });
1686
+ }
1687
+ for (const f of ir.metadata.localFunctions) {
1688
+ if (!f.isModule || !moduleNames.has(f.name))
1689
+ continue;
1690
+ const params = preserveTypes && f.typedParams !== undefined ? f.typedParams : f.params.map(formatParamWithType).join(", ");
1691
+ const returnAnnotation = preserveTypes && f.typedReturnType ? `: ${f.typedReturnType}` : "";
1692
+ const body = preserveTypes ? f.typedBody ?? f.body : f.body;
1693
+ const asyncKw = f.isAsync ? "async " : "";
1694
+ const exportKw = f.isExported ? "export " : "";
1695
+ entries.push({
1696
+ line: f.loc.start.line,
1697
+ text: `${exportKw}${asyncKw}function ${f.name}(${params})${returnAnnotation} ${body}`
1698
+ });
1699
+ }
1700
+ entries.sort((a, b) => a.line - b.line);
1701
+ return entries.map((e) => e.text).join(`
1470
1702
  `);
1471
1703
  }
1472
1704
  renderNodeRaw(node) {
@@ -1478,6 +1710,15 @@ class JsxAdapter extends BaseAdapter {
1478
1710
  }
1479
1711
  return this.renderNode(node);
1480
1712
  }
1713
+ renderTemplatePartsAsJs(parts) {
1714
+ return templatePartsToJsExpr(parts, { typed: this.jsxConfig.preserveTypes });
1715
+ }
1716
+ expressionValueToJs(value) {
1717
+ if (this.jsxConfig.preserveTypes && value.parts && value.expr === templatePartsToJsExpr(value.parts)) {
1718
+ return this.renderTemplatePartsAsJs(value.parts);
1719
+ }
1720
+ return value.expr;
1721
+ }
1481
1722
  renderScopeMarker(instanceIdExpr) {
1482
1723
  return `${BF_SCOPE}={${instanceIdExpr}}`;
1483
1724
  }
@@ -1545,6 +1786,7 @@ class TestAdapter extends JsxAdapter {
1545
1786
  generate(ir) {
1546
1787
  this.componentName = ir.metadata.componentName;
1547
1788
  const imports = this.generateImports(ir);
1789
+ const moduleConstants = this.generateModuleScopeDeclarations(ir);
1548
1790
  const types = this.generateTypes(ir);
1549
1791
  const component = this.generateComponent(ir);
1550
1792
  const defaultExport = ir.metadata.hasDefaultExport ? `
@@ -1553,9 +1795,11 @@ export default ${this.componentName}` : "";
1553
1795
  imports,
1554
1796
  types: types || "",
1555
1797
  component,
1556
- defaultExport
1798
+ defaultExport,
1799
+ moduleConstants,
1800
+ moduleConstantsIncludeExports: true
1557
1801
  };
1558
- const template = [imports, types, component].filter(Boolean).join(`
1802
+ const template = [imports, moduleConstants, types, component].filter(Boolean).join(`
1559
1803
 
1560
1804
  `) + defaultExport;
1561
1805
  return {
@@ -1586,9 +1830,6 @@ export default ${this.componentName}` : "";
1586
1830
  }
1587
1831
  generateTypes(ir) {
1588
1832
  const lines = [];
1589
- for (const typeDef of ir.metadata.typeDefinitions) {
1590
- lines.push(typeDef.definition);
1591
- }
1592
1833
  const propsTypeName = ir.metadata.propsType?.raw;
1593
1834
  if (propsTypeName && !ir.metadata.propsObjectName) {
1594
1835
  lines.push("");
@@ -1611,7 +1852,7 @@ export default ${this.componentName}` : "";
1611
1852
  const bodyRefText = [jsxBody, signalInits, scopeIdLine].join(`
1612
1853
  `);
1613
1854
  const bfScopeAlias = /\b__bfScope\b/.test(bodyRefText) ? "__bfScope" : "__bfScope: _bfScope";
1614
- const propsParams = ir.metadata.propsParams.map((p) => p.defaultValue ? `${p.name} = ${p.defaultValue}` : p.name).join(", ");
1855
+ const propsParams = ir.metadata.propsParams.map((p) => propsDestructureBinding(p)).join(", ");
1615
1856
  const restPropsName = ir.metadata.restPropsName;
1616
1857
  const hydrationProps = `__instanceId, ${bfScopeAlias}`;
1617
1858
  const parts = [];
@@ -1758,13 +1999,7 @@ export default ${this.componentName}` : "";
1758
1999
  }
1759
2000
  flattenTemplate(value) {
1760
2001
  const v = value;
1761
- return "`" + v.parts.map((p) => {
1762
- if (p.type === "string")
1763
- return p.value;
1764
- if (p.type === "ternary")
1765
- return `\${${p.condition} ? '${p.whenTrue}' : '${p.whenFalse}'}`;
1766
- return `\${(${JSON.stringify(p.cases)})[${p.key}]}`;
1767
- }).join("") + "`";
2002
+ return this.renderTemplatePartsAsJs(v.parts);
1768
2003
  }
1769
2004
  renderComponentProps(comp) {
1770
2005
  const parts = [];
@@ -1940,17 +2175,16 @@ function emitAttrValue(value, emitter, name) {
1940
2175
  }
1941
2176
  }
1942
2177
  // ../jsx/src/combine-client-js.ts
1943
- import ts23 from "typescript";
2178
+ import ts25 from "typescript";
1944
2179
  // ../jsx/src/debug.ts
1945
- import ts24 from "typescript";
2180
+ import ts26 from "typescript";
1946
2181
  // ../jsx/src/profiler.ts
1947
- import ts25 from "typescript";
2182
+ import ts27 from "typescript";
1948
2183
 
1949
2184
  // ../jsx/src/index.ts
1950
2185
  registerBuiltinLoweringPlugins();
1951
2186
 
1952
2187
  // src/adapter/hono-adapter.ts
1953
- import ts26 from "typescript";
1954
2188
  function applyHonoLoopChain(loop) {
1955
2189
  return buildLoopChainExpr({
1956
2190
  base: loop.array,
@@ -1959,18 +2193,6 @@ function applyHonoLoopChain(loop) {
1959
2193
  chainOrder: loop.chainOrder
1960
2194
  });
1961
2195
  }
1962
- function isIdentifierName(key) {
1963
- if (key.length === 0)
1964
- return false;
1965
- for (let i = 0;i < key.length; ) {
1966
- const cp = key.codePointAt(i);
1967
- const ok = i === 0 ? ts26.isIdentifierStart(cp, ts26.ScriptTarget.Latest) : ts26.isIdentifierPart(cp, ts26.ScriptTarget.Latest);
1968
- if (!ok)
1969
- return false;
1970
- i += cp > 65535 ? 2 : 1;
1971
- }
1972
- return true;
1973
- }
1974
2196
 
1975
2197
  class HonoAdapter extends JsxAdapter {
1976
2198
  name = "hono";
@@ -2008,11 +2230,11 @@ class HonoAdapter extends JsxAdapter {
2008
2230
  this.preloadAssets = options?.preloadAssets;
2009
2231
  }
2010
2232
  const component = this.generateComponent(ir);
2011
- const types = this.generateTypes(ir, component);
2012
- const componentCode = [types, component].filter(Boolean).join(`
2233
+ const types = this.generateTypes(ir);
2234
+ const moduleConstants = this.generateModuleScopeDeclarations(ir);
2235
+ const componentCode = [moduleConstants, types, component].filter(Boolean).join(`
2013
2236
  `);
2014
2237
  const imports = this.generateImports(ir, componentCode);
2015
- const moduleConstants = this.generateModuleLevelContextBindings(ir);
2016
2238
  const defaultExport = ir.metadata.hasDefaultExport ? `
2017
2239
  export default ${this.componentName}` : "";
2018
2240
  const sections = {
@@ -2020,7 +2242,8 @@ export default ${this.componentName}` : "";
2020
2242
  types: types || "",
2021
2243
  component,
2022
2244
  defaultExport,
2023
- moduleConstants
2245
+ moduleConstants,
2246
+ moduleConstantsIncludeExports: true
2024
2247
  };
2025
2248
  const template = [imports, moduleConstants, types, component].filter(Boolean).join(`
2026
2249
 
@@ -2042,24 +2265,6 @@ export default ${this.componentName}` : "";
2042
2265
  hasPreloadAssets() {
2043
2266
  return this.hasScriptAssets() && !!this.preloadAssets && this.preloadAssets.length > 0;
2044
2267
  }
2045
- generateModuleLevelContextBindings(ir) {
2046
- const lines = [];
2047
- for (const c of ir.metadata.localConstants) {
2048
- if (!c.isModule)
2049
- continue;
2050
- if (c.isExported)
2051
- continue;
2052
- if (c.systemConstructKind !== "createContext")
2053
- continue;
2054
- if (!c.value)
2055
- continue;
2056
- const keyword = c.declarationKind ?? "const";
2057
- const value = this.jsxConfig.preserveTypes ? c.typedValue ?? c.value : c.value;
2058
- lines.push(`${keyword} ${c.name} = ${value}`);
2059
- }
2060
- return lines.join(`
2061
- `);
2062
- }
2063
2268
  generateImports(ir, componentCode) {
2064
2269
  const lines = [];
2065
2270
  const utilImports = [];
@@ -2101,50 +2306,10 @@ export default ${this.componentName}` : "";
2101
2306
  return lines.join(`
2102
2307
  `);
2103
2308
  }
2104
- generateTypes(ir, componentBody) {
2309
+ generateTypes(ir) {
2105
2310
  const lines = [];
2106
- if (componentBody && ir.metadata.typeDefinitions.length > 0) {
2107
- const propsTypeName2 = this.getPropsTypeName(ir);
2108
- const seedText = [
2109
- componentBody,
2110
- propsTypeName2 && !ir.metadata.propsObjectName ? propsTypeName2 : "",
2111
- ...ir.metadata.namedExports.filter((block) => block.source === null).flatMap((block) => block.specifiers.map((s) => s.name))
2112
- ].filter(Boolean).join(`
2113
- `);
2114
- const included = new Set;
2115
- for (const typeDef of ir.metadata.typeDefinitions) {
2116
- if (new RegExp(`\\b${typeDef.name}\\b`).test(seedText)) {
2117
- included.add(typeDef.name);
2118
- }
2119
- }
2120
- let changed = true;
2121
- while (changed) {
2122
- changed = false;
2123
- for (const typeDef of ir.metadata.typeDefinitions) {
2124
- if (included.has(typeDef.name))
2125
- continue;
2126
- for (const name of included) {
2127
- const includedDef = ir.metadata.typeDefinitions.find((t) => t.name === name);
2128
- if (includedDef && new RegExp(`\\b${typeDef.name}\\b`).test(includedDef.definition)) {
2129
- included.add(typeDef.name);
2130
- changed = true;
2131
- break;
2132
- }
2133
- }
2134
- }
2135
- }
2136
- for (const typeDef of ir.metadata.typeDefinitions) {
2137
- if (included.has(typeDef.name))
2138
- lines.push(typeDef.definition);
2139
- }
2140
- } else {
2141
- for (const typeDef of ir.metadata.typeDefinitions) {
2142
- lines.push(typeDef.definition);
2143
- }
2144
- }
2145
2311
  const propsTypeName = this.getPropsTypeName(ir);
2146
2312
  if (propsTypeName && !ir.metadata.propsObjectName) {
2147
- lines.push("");
2148
2313
  lines.push(`type ${this.componentName}PropsWithHydration = ${propsTypeName} & {`);
2149
2314
  lines.push(" __instanceId?: string");
2150
2315
  lines.push(" __bfScope?: string");
@@ -2224,12 +2389,7 @@ export default ${this.componentName}` : "";
2224
2389
  } else {
2225
2390
  const hydrationProps = `__instanceId, ${bfScopeAlias}, ${bfChildAlias}, ${bfParentPropsAlias}, ${bfParentAlias}, ${bfMountAlias}, ${dataKeyAlias}`;
2226
2391
  const parts = [];
2227
- const propsParams = ir.metadata.propsParams.map((p) => {
2228
- const callerKey = p.sourceName ?? p.name;
2229
- const localName = p.name;
2230
- const binding = callerKey === localName ? localName : `${isIdentifierName(callerKey) ? callerKey : JSON.stringify(callerKey)}: ${localName}`;
2231
- return p.defaultValue ? `${binding} = ${p.defaultValue}` : binding;
2232
- }).join(", ");
2392
+ const propsParams = ir.metadata.propsParams.map((p) => propsDestructureBinding(p)).join(", ");
2233
2393
  if (propsParams) {
2234
2394
  parts.push(propsParams);
2235
2395
  }
@@ -2270,7 +2430,8 @@ export default ${this.componentName}` : "";
2270
2430
  lines.push(` const __hydrateProps: Record<string, unknown> = {}`);
2271
2431
  for (const p of propsToSerialize) {
2272
2432
  const propAccess = propsObjectName ? `${propsObjectName}.${p.name}` : p.name;
2273
- lines.push(` if (typeof ${propAccess} !== 'function' && !(typeof ${propAccess} === 'object' && ${propAccess} !== null && 'isEscaped' in ${propAccess})) __hydrateProps['${p.name}'] = ${propAccess}`);
2433
+ const callerKey = p.sourceName ?? p.name;
2434
+ lines.push(` if (typeof ${propAccess} !== 'function' && !(typeof ${propAccess} === 'object' && ${propAccess} !== null && 'isEscaped' in ${propAccess})) __hydrateProps['${callerKey}'] = ${propAccess}`);
2274
2435
  }
2275
2436
  lines.push(` const __bfPropsJson = __bfParentProps || (Object.keys(__hydrateProps).length > 0 ? JSON.stringify(__hydrateProps) : undefined)`);
2276
2437
  } else if (hasClientInteractivity && isRootComponent) {
@@ -2335,6 +2496,7 @@ export default ${this.componentName}` : "";
2335
2496
  case "literal":
2336
2497
  return JSON.stringify(v.value);
2337
2498
  case "expression":
2499
+ return this.expressionValueToJs(v);
2338
2500
  case "spread":
2339
2501
  return v.expr;
2340
2502
  case "template":
@@ -2406,18 +2568,26 @@ export default ${this.componentName}` : "";
2406
2568
  if (cond.clientOnly && cond.slotId) {
2407
2569
  return `{bfComment("cond-start:${cond.slotId}")}{bfComment("cond-end:${cond.slotId}")}`;
2408
2570
  }
2571
+ return `{${this.renderConditionalBody(cond, ctx)}}`;
2572
+ }
2573
+ renderConditionalBody(cond, ctx) {
2409
2574
  const branchCtx = ctx?.isLoopItemRoot ? { isLoopItemRoot: true } : undefined;
2575
+ if (!cond.slotId) {
2576
+ const whenTrue2 = this.renderBareBranch(cond.whenTrue, branchCtx);
2577
+ let whenFalse2 = this.renderBareBranch(cond.whenFalse, branchCtx);
2578
+ if (!whenFalse2 || whenFalse2 === "" || whenFalse2 === "null") {
2579
+ whenFalse2 = "null";
2580
+ }
2581
+ return `${cond.condition} ? ${whenTrue2} : ${whenFalse2}`;
2582
+ }
2410
2583
  const whenTrue = this.renderNodeRawCtx(cond.whenTrue, branchCtx);
2411
2584
  let whenFalse = this.renderNodeRawCtx(cond.whenFalse, branchCtx);
2412
2585
  if (!whenFalse || whenFalse === "" || whenFalse === "null") {
2413
2586
  whenFalse = "null";
2414
2587
  }
2415
- if (cond.slotId) {
2416
- const trueWithMarker = this.wrapWithCondMarker(cond.whenTrue, whenTrue, cond.slotId);
2417
- const falseWithMarker = cond.whenFalse.type === "expression" && cond.whenFalse.expr === "null" ? `<>{bfComment("cond-start:${cond.slotId}")}{bfComment("cond-end:${cond.slotId}")}</>` : this.wrapWithCondMarker(cond.whenFalse, whenFalse, cond.slotId);
2418
- return `{${cond.condition} ? ${trueWithMarker} : ${falseWithMarker}}`;
2419
- }
2420
- return `{${cond.condition} ? ${whenTrue} : ${whenFalse}}`;
2588
+ const trueWithMarker = this.wrapWithCondMarker(cond.whenTrue, whenTrue, cond.slotId);
2589
+ const falseWithMarker = cond.whenFalse.type === "expression" && cond.whenFalse.expr === "null" ? `<>{bfComment("cond-start:${cond.slotId}")}{bfComment("cond-end:${cond.slotId}")}</>` : this.wrapWithCondMarker(cond.whenFalse, whenFalse, cond.slotId);
2590
+ return `${cond.condition} ? ${trueWithMarker} : ${falseWithMarker}`;
2421
2591
  }
2422
2592
  renderNodeRawCtx(node, ctx) {
2423
2593
  if (node.type === "expression") {
@@ -2427,6 +2597,17 @@ export default ${this.componentName}` : "";
2427
2597
  }
2428
2598
  return this.renderNode(node, ctx);
2429
2599
  }
2600
+ renderBareBranch(node, ctx) {
2601
+ if (node.type === "expression") {
2602
+ if (node.expr === "null" || node.expr === "undefined")
2603
+ return "null";
2604
+ return node.expr;
2605
+ }
2606
+ if (node.type === "conditional" && !(node.clientOnly && node.slotId)) {
2607
+ return this.renderConditionalBody(node, ctx);
2608
+ }
2609
+ return this.renderNode(node, ctx);
2610
+ }
2430
2611
  wrapWithCondMarker(node, content, condId) {
2431
2612
  if (node.type === "component") {
2432
2613
  return `<>{bfComment("cond-start:${condId}")}${content}{bfComment("cond-end:${condId}")}</>`;
@@ -2578,10 +2759,11 @@ export default ${this.componentName}` : "";
2578
2759
  elementAttrEmitter = {
2579
2760
  emitLiteral: (value, name) => `${name}="${escapeHtml(value.value)}"`,
2580
2761
  emitExpression: (value, name) => {
2762
+ const expr = this.expressionValueToJs(value);
2581
2763
  if (isBooleanAttr(name) || value.presenceOrUndefined) {
2582
- return `${name}={(${value.expr}) || undefined}`;
2764
+ return `${name}={(${expr}) || undefined}`;
2583
2765
  }
2584
- return `${name}={${value.expr}}`;
2766
+ return `${name}={${expr}}`;
2585
2767
  },
2586
2768
  emitBooleanAttr: (_value, name) => name,
2587
2769
  emitBooleanShorthand: () => "",
@@ -2591,7 +2773,7 @@ export default ${this.componentName}` : "";
2591
2773
  };
2592
2774
  componentPropEmitter = {
2593
2775
  emitLiteral: (value, name) => `${name}="${escapeHtml(value.value)}"`,
2594
- emitExpression: (value, name) => `${name}={${value.expr}}`,
2776
+ emitExpression: (value, name) => `${name}={${this.expressionValueToJs(value)}}`,
2595
2777
  emitBooleanAttr: (_value, name) => name,
2596
2778
  emitBooleanShorthand: (_value, name) => name,
2597
2779
  emitTemplate: (value, name) => `${name}={${this.renderTemplateLiteralParts(value.parts)}}`,
@@ -2639,6 +2821,7 @@ export default ${this.componentName}` : "";
2639
2821
  case "literal":
2640
2822
  return JSON.stringify(value.value);
2641
2823
  case "expression":
2824
+ return this.expressionValueToJs(value);
2642
2825
  case "spread":
2643
2826
  return value.expr;
2644
2827
  case "template":
@@ -2651,19 +2834,7 @@ export default ${this.componentName}` : "";
2651
2834
  }
2652
2835
  }
2653
2836
  renderTemplateLiteralParts(parts) {
2654
- let output = "`";
2655
- for (const part of parts) {
2656
- if (part.type === "string") {
2657
- output += part.value;
2658
- } else if (part.type === "ternary") {
2659
- output += `\${${part.condition} ? '${part.whenTrue}' : '${part.whenFalse}'}`;
2660
- } else if (part.type === "lookup") {
2661
- const obj = "{" + Object.entries(part.cases).map(([k, v]) => `${JSON.stringify(k)}: ${JSON.stringify(v)}`).join(", ") + "}";
2662
- output += `\${(${obj})[${part.key}]}`;
2663
- }
2664
- }
2665
- output += "`";
2666
- return output;
2837
+ return this.renderTemplatePartsAsJs(parts);
2667
2838
  }
2668
2839
  }
2669
2840
  var honoAdapter = new HonoAdapter;