@barefootjs/hono 0.31.0 → 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.
- package/dist/adapter/hono-adapter.d.ts +67 -2
- package/dist/adapter/hono-adapter.d.ts.map +1 -1
- package/dist/adapter/index.js +46 -187398
- package/dist/app.js +0 -71
- package/dist/async.js +0 -71
- package/dist/client-shim.js +0 -71
- package/dist/dev-worker.js +0 -71
- package/dist/dialog-context.js +0 -71
- package/dist/index.js +46 -187398
- package/dist/jsx/jsx-dev-runtime/index.d.ts +3 -1
- package/dist/jsx/jsx-dev-runtime/index.d.ts.map +1 -1
- package/dist/jsx/jsx-dev-runtime/index.js +14 -69
- package/dist/jsx/jsx-runtime/index.d.ts +4 -1
- package/dist/jsx/jsx-runtime/index.d.ts.map +1 -1
- package/dist/jsx/jsx-runtime/index.js +24 -69
- package/dist/jsx/resolve-dangerously-set-inner-html.d.ts +2 -0
- package/dist/jsx/resolve-dangerously-set-inner-html.d.ts.map +1 -0
- package/dist/portal-ssr.js +0 -71
- package/dist/portals.js +0 -71
- package/dist/preload.js +0 -71
- package/dist/render.js +0 -71
- package/dist/request-env.js +0 -71
- package/dist/scripts.d.ts +3 -2
- package/dist/scripts.d.ts.map +1 -1
- package/dist/scripts.js +0 -71
- package/dist/utils.js +0 -71
- package/dist/vite.js +313 -142
- package/package.json +2 -2
- package/src/__tests__/aliased-destructured-prop.test.ts +8 -7
- package/src/__tests__/consumer-typecheck.test.ts +403 -0
- package/src/__tests__/corpus-typecheck.test.ts +130 -0
- package/src/__tests__/dangerously-set-inner-html.test.ts +70 -0
- package/src/__tests__/nested-ternary-bare-branch.test.ts +70 -0
- package/src/adapter/hono-adapter.ts +123 -166
- package/src/jsx/jsx-dev-runtime/index.ts +13 -1
- package/src/jsx/jsx-runtime/index.ts +24 -1
- package/src/jsx/resolve-dangerously-set-inner-html.ts +34 -0
- package/src/scripts.tsx +3 -2
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
|
|
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
|
|
321
|
+
import ts8 from "typescript";
|
|
265
322
|
|
|
266
323
|
// ../jsx/src/strip-types.ts
|
|
267
|
-
import
|
|
324
|
+
import ts7 from "typescript";
|
|
268
325
|
|
|
269
326
|
// ../jsx/src/analyzer-context.ts
|
|
270
|
-
var _typePrinter =
|
|
271
|
-
var _blankTypeSourceFile =
|
|
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
|
|
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
|
|
682
|
+
import ts10 from "typescript";
|
|
576
683
|
|
|
577
684
|
// ../jsx/src/free-refs.ts
|
|
578
|
-
import
|
|
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
|
|
1099
|
+
import ts13 from "typescript";
|
|
993
1100
|
|
|
994
1101
|
// ../jsx/src/value-references.ts
|
|
995
|
-
import
|
|
1102
|
+
import ts14 from "typescript";
|
|
996
1103
|
|
|
997
1104
|
// ../jsx/src/relocate.ts
|
|
998
|
-
import
|
|
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
|
|
1284
|
+
import ts16 from "typescript";
|
|
1178
1285
|
|
|
1179
1286
|
// ../jsx/src/ir-to-client-js/control-flow/plan/lazy-preamble.ts
|
|
1180
|
-
import
|
|
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
|
|
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
|
|
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
|
|
1443
|
+
import ts20 from "typescript";
|
|
1337
1444
|
|
|
1338
1445
|
// ../jsx/src/ssr-defaults.ts
|
|
1339
|
-
import
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
2178
|
+
import ts25 from "typescript";
|
|
1944
2179
|
// ../jsx/src/debug.ts
|
|
1945
|
-
import
|
|
2180
|
+
import ts26 from "typescript";
|
|
1946
2181
|
// ../jsx/src/profiler.ts
|
|
1947
|
-
import
|
|
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
|
|
2012
|
-
const
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
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}={(${
|
|
2764
|
+
return `${name}={(${expr}) || undefined}`;
|
|
2583
2765
|
}
|
|
2584
|
-
return `${name}={${
|
|
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
|
|
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
|
-
|
|
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;
|