@barefootjs/jsx 0.32.0 → 0.33.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.
Files changed (72) hide show
  1. package/dist/adapters/dangerous-inner-html.d.ts.map +1 -1
  2. package/dist/adapters/parsed-expr-emitter.d.ts +22 -0
  3. package/dist/adapters/parsed-expr-emitter.d.ts.map +1 -1
  4. package/dist/analyzer.d.ts.map +1 -1
  5. package/dist/errors.d.ts +1 -0
  6. package/dist/errors.d.ts.map +1 -1
  7. package/dist/expression-parser.d.ts +29 -6
  8. package/dist/expression-parser.d.ts.map +1 -1
  9. package/dist/index.d.ts +2 -2
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +274 -80
  12. package/dist/ir-to-client-js/collect-elements.d.ts.map +1 -1
  13. package/dist/ir-to-client-js/control-flow/plan/build-inner-loop.d.ts.map +1 -1
  14. package/dist/ir-to-client-js/control-flow/plan/build-loop-child-arm.d.ts +8 -0
  15. package/dist/ir-to-client-js/control-flow/plan/build-loop-child-arm.d.ts.map +1 -1
  16. package/dist/ir-to-client-js/control-flow/plan/build-reactive-effects.d.ts.map +1 -1
  17. package/dist/ir-to-client-js/control-flow/plan/inner-loop.d.ts +12 -0
  18. package/dist/ir-to-client-js/control-flow/plan/inner-loop.d.ts.map +1 -1
  19. package/dist/ir-to-client-js/control-flow/stringify/inner-loop.d.ts +1 -0
  20. package/dist/ir-to-client-js/control-flow/stringify/inner-loop.d.ts.map +1 -1
  21. package/dist/ir-to-client-js/control-flow/stringify/lazy-row.d.ts.map +1 -1
  22. package/dist/ir-to-client-js/element-refs.d.ts.map +1 -1
  23. package/dist/ir-to-client-js/emit-reactive.d.ts.map +1 -1
  24. package/dist/ir-to-client-js/imports.d.ts +2 -2
  25. package/dist/ir-to-client-js/imports.d.ts.map +1 -1
  26. package/dist/ir-to-client-js/phases/provider-and-child-inits.d.ts.map +1 -1
  27. package/dist/ir-to-client-js/types.d.ts +21 -0
  28. package/dist/ir-to-client-js/types.d.ts.map +1 -1
  29. package/dist/query-href-lowering.d.ts.map +1 -1
  30. package/dist/ssr-seed-plan.d.ts.map +1 -1
  31. package/dist/static-literal.d.ts.map +1 -1
  32. package/dist/to-locale-date-lowering.d.ts.map +1 -1
  33. package/package.json +2 -2
  34. package/src/__tests__/__snapshots__/doc-examples.test.ts.snap +2 -4
  35. package/src/__tests__/child-components-in-map.test.ts +11 -3
  36. package/src/__tests__/client-js-generation.test.ts +37 -1
  37. package/src/__tests__/expression-parser.test.ts +43 -6
  38. package/src/__tests__/inline-jsx-callback.test.ts +55 -0
  39. package/src/__tests__/ir-jsx-props.test.ts +148 -0
  40. package/src/__tests__/issue-2705-branch-inner-loop-container.test.ts +91 -0
  41. package/src/__tests__/markup-prop-brand.test.ts +49 -0
  42. package/src/__tests__/nested-loop-conditional.test.ts +20 -11
  43. package/src/__tests__/return-through-local-var.test.ts +269 -0
  44. package/src/__tests__/serialize-parsed-expr.test.ts +17 -3
  45. package/src/__tests__/ssr-defaults.test.ts +41 -0
  46. package/src/__tests__/ssr-seed-plan.test.ts +12 -2
  47. package/src/adapters/dangerous-inner-html.ts +1 -0
  48. package/src/adapters/parsed-expr-emitter.ts +49 -3
  49. package/src/analyzer.ts +71 -0
  50. package/src/errors.ts +17 -1
  51. package/src/expression-parser.ts +200 -89
  52. package/src/index.ts +2 -2
  53. package/src/ir-to-client-js/collect-elements.ts +31 -20
  54. package/src/ir-to-client-js/control-flow/plan/build-inner-loop.ts +19 -0
  55. package/src/ir-to-client-js/control-flow/plan/build-loop-child-arm.ts +22 -3
  56. package/src/ir-to-client-js/control-flow/plan/build-reactive-effects.ts +5 -2
  57. package/src/ir-to-client-js/control-flow/plan/inner-loop.ts +12 -0
  58. package/src/ir-to-client-js/control-flow/stringify/inner-loop.ts +9 -0
  59. package/src/ir-to-client-js/control-flow/stringify/lazy-row.ts +7 -1
  60. package/src/ir-to-client-js/element-refs.ts +8 -0
  61. package/src/ir-to-client-js/emit-reactive.ts +91 -23
  62. package/src/ir-to-client-js/imports.ts +5 -0
  63. package/src/ir-to-client-js/index.ts +4 -0
  64. package/src/ir-to-client-js/phases/provider-and-child-inits.ts +5 -1
  65. package/src/ir-to-client-js/types.ts +21 -0
  66. package/src/jsx-to-ir.ts +161 -9
  67. package/src/query-href-lowering.ts +4 -0
  68. package/src/rich-type-refusal.ts +1 -1
  69. package/src/ssr-defaults.ts +51 -2
  70. package/src/ssr-seed-plan.ts +20 -3
  71. package/src/static-literal.ts +15 -1
  72. package/src/to-locale-date-lowering.ts +4 -0
package/dist/index.js CHANGED
@@ -523,7 +523,7 @@ function convertNode(node, raw) {
523
523
  }
524
524
  if (n === undefined || Number.isNaN(n)) {
525
525
  const parsedDepth = convertNode(depthNode, raw);
526
- if (checkSupport(parsedDepth).supported) {
526
+ if (checkSupport(parsedDepth, "rendered").supported) {
527
527
  depthExpr = parsedDepth;
528
528
  flatDepth = 1;
529
529
  } else {
@@ -617,10 +617,12 @@ function convertNode(node, raw) {
617
617
  const k = objectLiteralKeyName(prop.name);
618
618
  if (k === null)
619
619
  return { kind: "unsupported", raw, reason: `Unsupported syntax: ${ts2.SyntaxKind[node.kind]}` };
620
- properties.push({ key: k.key, keyKind: k.keyKind, shorthand: false, value: convertNode(prop.initializer, raw) });
620
+ properties.push({ kind: "prop", key: k.key, keyKind: k.keyKind, shorthand: false, value: convertNode(prop.initializer, raw) });
621
621
  } else if (ts2.isShorthandPropertyAssignment(prop)) {
622
622
  const key = prop.name.text;
623
- properties.push({ key, keyKind: "identifier", shorthand: true, value: { kind: "identifier", name: key } });
623
+ properties.push({ kind: "prop", key, keyKind: "identifier", shorthand: true, value: { kind: "identifier", name: key } });
624
+ } else if (ts2.isSpreadAssignment(prop)) {
625
+ properties.push({ kind: "spread", expr: convertNode(prop.expression, raw) });
624
626
  } else {
625
627
  return { kind: "unsupported", raw, reason: `Unsupported syntax: ${ts2.SyntaxKind[node.kind]}` };
626
628
  }
@@ -1300,14 +1302,26 @@ function getUnaryOperatorString(op) {
1300
1302
  }
1301
1303
  }
1302
1304
  function isSupported(expr) {
1303
- return checkSupport(expr);
1305
+ return checkSupport(expr, "rendered");
1304
1306
  }
1305
- function checkSupport(expr) {
1307
+ function isSupportedValue(expr) {
1308
+ return checkSupport(expr, "value");
1309
+ }
1310
+ function checkSupport(expr, pos) {
1306
1311
  switch (expr.kind) {
1307
1312
  case "unsupported":
1308
1313
  return { supported: false, reason: expr.reason };
1309
- case "object-literal":
1310
- return { supported: false, reason: "Unsupported syntax: ObjectLiteralExpression" };
1314
+ case "object-literal": {
1315
+ if (pos !== "value") {
1316
+ return { supported: false, reason: "Unsupported syntax: ObjectLiteralExpression" };
1317
+ }
1318
+ for (const prop of expr.properties) {
1319
+ const propSupport = checkSupport(prop.kind === "spread" ? prop.expr : prop.value, pos);
1320
+ if (!propSupport.supported)
1321
+ return propSupport;
1322
+ }
1323
+ return { supported: true, level: "L2" };
1324
+ }
1311
1325
  case "identifier":
1312
1326
  return { supported: true, level: "L1" };
1313
1327
  case "literal":
@@ -1317,7 +1331,7 @@ function checkSupport(expr) {
1317
1331
  return { supported: false, reason: "Standalone arrow functions / regex literals are not supported" };
1318
1332
  case "array-literal": {
1319
1333
  for (const el of expr.elements) {
1320
- const elSupport = checkSupport(el);
1334
+ const elSupport = checkSupport(el, pos);
1321
1335
  if (!elSupport.supported)
1322
1336
  return elSupport;
1323
1337
  }
@@ -1330,16 +1344,16 @@ function checkSupport(expr) {
1330
1344
  reason: `String.prototype.${expr.method} supports only a string pattern + string replacement (the regex form is deferred); use a string pattern or wrap the expression in /* @client */`
1331
1345
  };
1332
1346
  }
1333
- const objSupport = checkSupport(expr.object);
1347
+ const objSupport = checkSupport(expr.object, pos);
1334
1348
  if (!objSupport.supported)
1335
1349
  return objSupport;
1336
1350
  for (const arg of expr.args) {
1337
- const argSupport = checkSupport(arg);
1351
+ const argSupport = checkSupport(arg, pos);
1338
1352
  if (!argSupport.supported)
1339
1353
  return argSupport;
1340
1354
  }
1341
1355
  if (expr.method === "flat" && expr.depthExpr) {
1342
- const depthSupport = checkSupport(expr.depthExpr);
1356
+ const depthSupport = checkSupport(expr.depthExpr, pos);
1343
1357
  if (!depthSupport.supported)
1344
1358
  return depthSupport;
1345
1359
  }
@@ -1348,10 +1362,10 @@ function checkSupport(expr) {
1348
1362
  case "call": {
1349
1363
  const cb = asCallbackMethodCall(expr);
1350
1364
  if (cb) {
1351
- const objSupport = checkSupport(cb.object);
1365
+ const objSupport = checkSupport(cb.object, pos);
1352
1366
  if (!objSupport.supported)
1353
1367
  return objSupport;
1354
- const bodySupport = checkSupport(cb.arrow.body);
1368
+ const bodySupport = checkSupport(cb.arrow.body, pos);
1355
1369
  if (!bodySupport.supported) {
1356
1370
  return {
1357
1371
  supported: false,
@@ -1360,13 +1374,13 @@ function checkSupport(expr) {
1360
1374
  };
1361
1375
  }
1362
1376
  for (const rest of cb.args) {
1363
- const restSupport = checkSupport(rest);
1377
+ const restSupport = checkSupport(rest, pos);
1364
1378
  if (!restSupport.supported)
1365
1379
  return restSupport;
1366
1380
  }
1367
1381
  return { supported: true, level: "L5" };
1368
1382
  }
1369
- const calleeSupport = checkSupport(expr.callee);
1383
+ const calleeSupport = checkSupport(expr.callee, pos);
1370
1384
  if (!calleeSupport.supported) {
1371
1385
  return calleeSupport;
1372
1386
  }
@@ -1385,7 +1399,7 @@ function checkSupport(expr) {
1385
1399
  return { supported: true, level: "L1" };
1386
1400
  }
1387
1401
  for (const arg of expr.args) {
1388
- const argSupport = checkSupport(arg);
1402
+ const argSupport = checkSupport(arg, pos);
1389
1403
  if (!argSupport.supported) {
1390
1404
  return argSupport;
1391
1405
  }
@@ -1393,7 +1407,7 @@ function checkSupport(expr) {
1393
1407
  return { supported: true, level: "L2" };
1394
1408
  }
1395
1409
  case "member": {
1396
- const objSupport = checkSupport(expr.object);
1410
+ const objSupport = checkSupport(expr.object, pos);
1397
1411
  if (!objSupport.supported) {
1398
1412
  return objSupport;
1399
1413
  }
@@ -1403,19 +1417,19 @@ function checkSupport(expr) {
1403
1417
  return { supported: true, level: "L2" };
1404
1418
  }
1405
1419
  case "index-access": {
1406
- const objSupport = checkSupport(expr.object);
1420
+ const objSupport = checkSupport(expr.object, pos);
1407
1421
  if (!objSupport.supported)
1408
1422
  return objSupport;
1409
- const indexSupport = checkSupport(expr.index);
1423
+ const indexSupport = checkSupport(expr.index, pos);
1410
1424
  if (!indexSupport.supported)
1411
1425
  return indexSupport;
1412
1426
  return { supported: true, level: "L2" };
1413
1427
  }
1414
1428
  case "binary": {
1415
- const leftSupport = checkSupport(expr.left);
1429
+ const leftSupport = checkSupport(expr.left, pos);
1416
1430
  if (!leftSupport.supported)
1417
1431
  return leftSupport;
1418
- const rightSupport = checkSupport(expr.right);
1432
+ const rightSupport = checkSupport(expr.right, pos);
1419
1433
  if (!rightSupport.supported)
1420
1434
  return rightSupport;
1421
1435
  if (["===", "==", "!==", "!=", ">", "<", ">=", "<="].includes(expr.op)) {
@@ -1427,7 +1441,7 @@ function checkSupport(expr) {
1427
1441
  return { supported: false, reason: `Unknown operator: ${expr.op}` };
1428
1442
  }
1429
1443
  case "unary": {
1430
- const argSupport = checkSupport(expr.argument);
1444
+ const argSupport = checkSupport(expr.argument, pos);
1431
1445
  if (!argSupport.supported)
1432
1446
  return argSupport;
1433
1447
  if (expr.op === "!") {
@@ -1439,25 +1453,25 @@ function checkSupport(expr) {
1439
1453
  return { supported: false, reason: `Unsupported unary operator: ${expr.op}` };
1440
1454
  }
1441
1455
  case "logical": {
1442
- const leftSupport = checkSupport(expr.left);
1456
+ const leftSupport = checkSupport(expr.left, pos);
1443
1457
  if (!leftSupport.supported)
1444
1458
  return leftSupport;
1445
1459
  if (expr.op === "??" && expr.right.kind === "object-literal" && expr.right.properties.length === 0) {
1446
1460
  return { supported: true, level: "L4" };
1447
1461
  }
1448
- const rightSupport = checkSupport(expr.right);
1462
+ const rightSupport = checkSupport(expr.right, pos);
1449
1463
  if (!rightSupport.supported)
1450
1464
  return rightSupport;
1451
1465
  return { supported: true, level: "L4" };
1452
1466
  }
1453
1467
  case "conditional": {
1454
- const testSupport = checkSupport(expr.test);
1468
+ const testSupport = checkSupport(expr.test, pos);
1455
1469
  if (!testSupport.supported)
1456
1470
  return testSupport;
1457
- const consSupport = checkSupport(expr.consequent);
1471
+ const consSupport = checkSupport(expr.consequent, pos);
1458
1472
  if (!consSupport.supported)
1459
1473
  return consSupport;
1460
- const altSupport = checkSupport(expr.alternate);
1474
+ const altSupport = checkSupport(expr.alternate, pos);
1461
1475
  if (!altSupport.supported)
1462
1476
  return altSupport;
1463
1477
  return { supported: true, level: "L4" };
@@ -1465,7 +1479,7 @@ function checkSupport(expr) {
1465
1479
  case "template-literal": {
1466
1480
  for (const part of expr.parts) {
1467
1481
  if (part.type === "expression") {
1468
- const partSupport = checkSupport(part.expr);
1482
+ const partSupport = checkSupport(part.expr, pos);
1469
1483
  if (!partSupport.supported)
1470
1484
  return partSupport;
1471
1485
  }
@@ -1618,7 +1632,7 @@ function isPureInit(e, pureCallNames) {
1618
1632
  case "array-literal":
1619
1633
  return e.elements.every(pure);
1620
1634
  case "object-literal":
1621
- return e.properties.every((p) => pure(p.value));
1635
+ return e.properties.every((p) => pure(p.kind === "spread" ? p.expr : p.value));
1622
1636
  case "call":
1623
1637
  return e.callee.kind === "identifier" && e.args.length === 0 && pureCallNames !== undefined && pureCallNames.has(e.callee.name);
1624
1638
  case "array-method":
@@ -1672,7 +1686,7 @@ function usesPerPath(name, expr) {
1672
1686
  }
1673
1687
  return add(walk(e.object), sum(e.args));
1674
1688
  case "object-literal":
1675
- return sum(e.properties.map((p) => p.value));
1689
+ return sum(e.properties.map((p) => p.kind === "spread" ? p.expr : p.value));
1676
1690
  case "arrow":
1677
1691
  return walk(e.body).max > 0 ? { min: 0, max: Number.POSITIVE_INFINITY } : { min: 0, max: 0 };
1678
1692
  }
@@ -1738,7 +1752,7 @@ function inlineBinding(expr, name, value) {
1738
1752
  case "object-literal":
1739
1753
  return {
1740
1754
  kind: "object-literal",
1741
- properties: e.properties.map((p) => ({ ...p, value: walk(p.value, enclosing) })),
1755
+ properties: e.properties.map((p) => p.kind === "spread" ? { ...p, expr: walk(p.expr, enclosing) } : { ...p, value: walk(p.value, enclosing) }),
1742
1756
  raw: e.raw
1743
1757
  };
1744
1758
  case "literal":
@@ -1971,7 +1985,7 @@ function materializeGetterCalls(expr, names) {
1971
1985
  return {
1972
1986
  kind: "object-literal",
1973
1987
  raw: expr.raw,
1974
- properties: expr.properties.map((p) => ({ ...p, value: rw(p.value) }))
1988
+ properties: expr.properties.map((p) => p.kind === "spread" ? { ...p, expr: rw(p.expr) } : { ...p, value: rw(p.value) })
1975
1989
  };
1976
1990
  case "arrow":
1977
1991
  return { kind: "arrow", params: expr.params, body: rw(expr.body) };
@@ -2029,7 +2043,7 @@ function freeVarsInBody(body, params) {
2029
2043
  return;
2030
2044
  case "object-literal":
2031
2045
  for (const p of e.properties)
2032
- visit(p.value, bound);
2046
+ visit(p.kind === "spread" ? p.expr : p.value, bound);
2033
2047
  return;
2034
2048
  case "array-method":
2035
2049
  if (e.method === "includes" || e.method === "join") {
@@ -2104,7 +2118,7 @@ function freeIdentifiers(expr) {
2104
2118
  return true;
2105
2119
  case "object-literal":
2106
2120
  for (const p of e.properties)
2107
- if (!visit(p.value, bound))
2121
+ if (!visit(p.kind === "spread" ? p.expr : p.value, bound))
2108
2122
  return false;
2109
2123
  return true;
2110
2124
  case "arrow": {
@@ -2251,10 +2265,17 @@ function toEvalNode(e) {
2251
2265
  case "object-literal": {
2252
2266
  const properties = [];
2253
2267
  for (const p of e.properties) {
2268
+ if (p.kind === "spread") {
2269
+ const spreadExpr = toEvalNode(p.expr);
2270
+ if (!spreadExpr)
2271
+ return null;
2272
+ properties.push({ kind: "spread", expr: spreadExpr });
2273
+ continue;
2274
+ }
2254
2275
  const value = toEvalNode(p.value);
2255
2276
  if (!value)
2256
2277
  return null;
2257
- properties.push({ key: p.key, value });
2278
+ properties.push({ kind: "prop", key: p.key, value });
2258
2279
  }
2259
2280
  return { kind: "object-literal", properties };
2260
2281
  }
@@ -5613,6 +5634,7 @@ var ErrorCodes = {
5613
5634
  MISSING_KEY_IN_LIST: "BF023",
5614
5635
  MISSING_KEY_IN_NESTED_LIST: "BF024",
5615
5636
  UNSUPPORTED_DESTRUCTURE_REST: "BF025",
5637
+ RETURN_VALUE_NOT_JSX: "BF027",
5616
5638
  PROPS_DESTRUCTURING: "BF043",
5617
5639
  SIGNAL_GETTER_NOT_CALLED: "BF044",
5618
5640
  JSX_IN_LOCAL_FUNCTION: "BF045",
@@ -5644,6 +5666,7 @@ var errorMessages = {
5644
5666
  [ErrorCodes.MISSING_KEY_IN_LIST]: "Missing key attribute in list rendering. Add a key prop for efficient updates",
5645
5667
  [ErrorCodes.MISSING_KEY_IN_NESTED_LIST]: "Nested .map() loop requires key attribute for event delegation. Add a key prop to elements in the inner loop",
5646
5668
  [ErrorCodes.UNSUPPORTED_DESTRUCTURE_REST]: "Computed property key in .map() callback destructure is not supported. Rewrite the callback to destructure explicit bindings (e.g., `({ a, b }) => ...`) so the compiler can rewrite references to per-item signal accessors.",
5669
+ [ErrorCodes.RETURN_VALUE_NOT_JSX]: "Component's return value is not recognized as JSX — return the JSX expression directly instead of binding it to a local variable first.",
5647
5670
  [ErrorCodes.PROPS_DESTRUCTURING]: "Props destructuring in function parameters breaks reactivity. Use props object directly.",
5648
5671
  [ErrorCodes.SIGNAL_GETTER_NOT_CALLED]: "Signal/memo getter passed without calling it. Use getter() to read the value.",
5649
5672
  [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.",
@@ -6285,6 +6308,14 @@ function visitComponentBody(node, ctx) {
6285
6308
  }
6286
6309
  }
6287
6310
  if (isTopLevel && (ts9.isTryStatement(node) || ts9.isSwitchStatement(node) || ts9.isForStatement(node) || ts9.isForInStatement(node) || ts9.isForOfStatement(node) || ts9.isWhileStatement(node) || ts9.isDoStatement(node) || ts9.isThrowStatement(node) || ts9.isBlock(node) && node.parent === ctx.componentBodyBlock)) {
6311
+ if (ts9.isBlock(node)) {
6312
+ const returnedLocal = findBlockBodyReturnedJsxLocalName(node);
6313
+ if (returnedLocal) {
6314
+ ctx.errors.push(createError(ErrorCodes.RETURN_VALUE_NOT_JSX, getSourceLocation(node, ctx.sourceFile, ctx.filePath), {
6315
+ message: `Component '${ctx.componentName ?? "(unknown)"}' return value is not recognized ` + `as JSX — return the JSX expression directly instead of binding it to a local ` + `variable first (\`return ${returnedLocal}\` after \`const ${returnedLocal} = ` + `<jsx/>\` is not resolved at return position).`
6316
+ }));
6317
+ }
6318
+ }
6288
6319
  collectInitStatement(node, ctx);
6289
6320
  return;
6290
6321
  }
@@ -6320,6 +6351,31 @@ function unwrapJsxTransparent(expr) {
6320
6351
  }
6321
6352
  return current;
6322
6353
  }
6354
+ function findBlockBodyReturnedJsxLocalName(block) {
6355
+ const stmts = block.statements;
6356
+ const last = stmts[stmts.length - 1];
6357
+ if (!last || !ts9.isReturnStatement(last) || !last.expression)
6358
+ return null;
6359
+ const returned = unwrapJsxTransparent(last.expression);
6360
+ if (!ts9.isIdentifier(returned))
6361
+ return null;
6362
+ const name = returned.text;
6363
+ for (const stmt of stmts) {
6364
+ if (!ts9.isVariableStatement(stmt))
6365
+ continue;
6366
+ for (const decl of stmt.declarationList.declarations) {
6367
+ if (!ts9.isIdentifier(decl.name) || decl.name.text !== name || !decl.initializer)
6368
+ continue;
6369
+ let init = decl.initializer;
6370
+ while (ts9.isParenthesizedExpression(init))
6371
+ init = init.expression;
6372
+ if (ts9.isJsxElement(init) || ts9.isJsxSelfClosingElement(init) || ts9.isJsxFragment(init) || initializerShapeContainsJsx(init) || isMapLikeCallWithJsx(init)) {
6373
+ return name;
6374
+ }
6375
+ }
6376
+ }
6377
+ return null;
6378
+ }
6323
6379
  function extractJsxFromExpression(expr) {
6324
6380
  const inner = unwrapJsxTransparent(expr);
6325
6381
  if (ts9.isJsxElement(inner) || ts9.isJsxFragment(inner) || ts9.isJsxSelfClosingElement(inner)) {
@@ -10114,6 +10170,8 @@ function matchToLocaleDateStringCall(callee, args, metadata) {
10114
10170
  let tz = null;
10115
10171
  const probeOptions = {};
10116
10172
  for (const prop of options.properties) {
10173
+ if (prop.kind === "spread")
10174
+ return null;
10117
10175
  if (prop.value.kind !== "literal" || prop.value.literalType !== "string")
10118
10176
  return null;
10119
10177
  const value = String(prop.value.value);
@@ -10687,8 +10745,14 @@ function buildIRRoot(analyzer) {
10687
10745
  }
10688
10746
  ctx.isRoot = false;
10689
10747
  const ir = transformJsxExpression(jsxReturn, ctx);
10690
- if (ir === null)
10748
+ if (ir === null) {
10749
+ if (ts13.isIdentifier(jsxReturn) && (analyzer.jsxConstants.has(jsxReturn.text) || analyzer.inlineableJsxConsts.has(jsxReturn.text))) {
10750
+ analyzer.errors.push(createError(ErrorCodes.RETURN_VALUE_NOT_JSX, getSourceLocation(jsxReturn, analyzer.sourceFile, analyzer.filePath), {
10751
+ message: `Component '${analyzer.componentName ?? "(unknown)"}' return value is not recognized ` + `as JSX — return the JSX expression directly instead of binding it to a local variable ` + `first (\`return ${jsxReturn.text}\` after \`const ${jsxReturn.text} = <jsx/>\` is not ` + `resolved at return position).`
10752
+ }));
10753
+ }
10691
10754
  return null;
10755
+ }
10692
10756
  return wrapInScopeElement(ir);
10693
10757
  }
10694
10758
  function needsScopeWrapper(ir) {
@@ -11879,7 +11943,10 @@ function resolveCallbackMethodFunctionReferences(expr, analyzer, bound = EMPTY_B
11879
11943
  ...e.method === "flat" && e.depthExpr ? { depthExpr: visit2(e.depthExpr, bound2) } : {}
11880
11944
  };
11881
11945
  case "object-literal":
11882
- return { ...e, properties: e.properties.map((p) => ({ ...p, value: visit2(p.value, bound2) })) };
11946
+ return {
11947
+ ...e,
11948
+ properties: e.properties.map((p) => p.kind === "spread" ? { ...p, expr: visit2(p.expr, bound2) } : { ...p, value: visit2(p.value, bound2) })
11949
+ };
11883
11950
  case "arrow": {
11884
11951
  const inner = e.params.length === 0 ? bound2 : new Set([...bound2, ...e.params]);
11885
11952
  return { ...e, body: visit2(e.body, inner) };
@@ -13800,6 +13867,35 @@ function getStringValue(node) {
13800
13867
  }
13801
13868
  return null;
13802
13869
  }
13870
+ function unwrapTransparentTsWrappers(node) {
13871
+ let n = node;
13872
+ while (ts13.isParenthesizedExpression(n) || ts13.isAsExpression(n) || ts13.isSatisfiesExpression(n) || ts13.isNonNullExpression(n)) {
13873
+ n = n.expression;
13874
+ }
13875
+ return n;
13876
+ }
13877
+ function expressionWrapsJsx(node) {
13878
+ const n = unwrapTransparentTsWrappers(node);
13879
+ if (ts13.isJsxElement(n) || ts13.isJsxSelfClosingElement(n) || ts13.isJsxFragment(n))
13880
+ return true;
13881
+ if (ts13.isConditionalExpression(n)) {
13882
+ return expressionWrapsJsx(n.whenTrue) || expressionWrapsJsx(n.whenFalse);
13883
+ }
13884
+ if (ts13.isArrayLiteralExpression(n)) {
13885
+ return n.elements.some((el) => expressionWrapsJsx(ts13.isSpreadElement(el) ? el.expression : el));
13886
+ }
13887
+ return false;
13888
+ }
13889
+ function reportNakedJsxWrapperProp(ctx, attr, propName, jsxExpr) {
13890
+ const shape = ts13.isConditionalExpression(jsxExpr) ? "a ternary" : "an array literal";
13891
+ ctx.analyzer.errors.push(createError(ErrorCodes.UNSUPPORTED_JSX_PATTERN, getSourceLocation(attr, ctx.sourceFile, ctx.filePath), {
13892
+ message: `Prop '${propName}' is ${shape} wrapping JSX (${jsxExpr.getText(ctx.sourceFile)}). ` + `This shape is not compiled — only a JSX element/fragment given DIRECTLY as the prop value is.`,
13893
+ suggestion: {
13894
+ message: `Move the conditional/array out of the prop position: compute it in a local ` + `const and pass it as the component's children instead of a named prop ` + `(e.g. const ${propName} = ${jsxExpr.getText(ctx.sourceFile)}; <Comp>{${propName}}</Comp>). ` + `Wrapping the ternary/array in a fragment at the prop position ` + `(${propName}={<>{${jsxExpr.getText(ctx.sourceFile)}}</>}) is NOT a safe escape here: it compiles, ` + `but the child's own reactive prop getter receives the branch's HTML unbranded and re-escapes it as ` + `text on the child's very next reactive run, corrupting the DOM (a narrower gap #2651's door ` + `inventory left open — tracked separately).`,
13895
+ escape: [{ kind: "rewrite" }]
13896
+ }
13897
+ }));
13898
+ }
13803
13899
  function processComponentProps(attributes, ctx) {
13804
13900
  const props = [];
13805
13901
  for (const attr of attributes.properties) {
@@ -13811,10 +13907,7 @@ function processComponentProps(attributes, ctx) {
13811
13907
  continue;
13812
13908
  const name = attr.name.getText(ctx.sourceFile);
13813
13909
  if (attr.initializer && ts13.isJsxExpression(attr.initializer) && attr.initializer.expression) {
13814
- let jsxExpr = attr.initializer.expression;
13815
- while (ts13.isParenthesizedExpression(jsxExpr)) {
13816
- jsxExpr = jsxExpr.expression;
13817
- }
13910
+ const jsxExpr = unwrapTransparentTsWrappers(attr.initializer.expression);
13818
13911
  if (ts13.isJsxElement(jsxExpr) || ts13.isJsxSelfClosingElement(jsxExpr) || ts13.isJsxFragment(jsxExpr)) {
13819
13912
  const prevInsideComponentChildren = ctx.insideComponentChildren;
13820
13913
  ctx.insideComponentChildren = true;
@@ -13829,6 +13922,10 @@ function processComponentProps(attributes, ctx) {
13829
13922
  continue;
13830
13923
  }
13831
13924
  }
13925
+ if ((ts13.isConditionalExpression(jsxExpr) || ts13.isArrayLiteralExpression(jsxExpr)) && expressionWrapsJsx(jsxExpr)) {
13926
+ reportNakedJsxWrapperProp(ctx, attr, name, jsxExpr);
13927
+ continue;
13928
+ }
13832
13929
  }
13833
13930
  let value = getAttributeValue(attr, ctx);
13834
13931
  if (value.kind === "template") {
@@ -14910,10 +15007,11 @@ function collectInnerLoops(nodes, siblingOffsets, outerLoopParam, ctx, options)
14910
15007
  const innerPreambleNames = preambleNamesOf(n);
14911
15008
  if (ctx) {
14912
15009
  for (const child of n.children) {
14913
- bindings.reactiveTexts.push(...collectLoopChildReactiveTexts(child, ctx, n.param, n.paramBindings, false, innerPreambleNames, n.index));
14914
- bindings.reactiveAttrs.push(...collectLoopChildReactiveAttrs(child, ctx, n.param, n.paramBindings, false, innerPreambleNames, n.index));
15010
+ bindings.reactiveTexts.push(...collectLoopChildReactiveTexts(child, ctx, n.param, n.paramBindings, true, innerPreambleNames, n.index));
15011
+ bindings.reactiveAttrs.push(...collectLoopChildReactiveAttrs(child, ctx, n.param, n.paramBindings, true, innerPreambleNames, n.index));
14915
15012
  bindings.refs.push(...collectLoopChildRefs(child));
14916
15013
  }
15014
+ bindings.conditionals.push(...collectLoopChildConditionals({ type: "fragment", children: n.children, loc: n.loc }, ctx, siblingOffsets, n.param, n.paramBindings, innerPreambleNames, n.index));
14917
15015
  }
14918
15016
  let childComponents;
14919
15017
  if (collectBindings) {
@@ -14937,9 +15035,6 @@ function collectInnerLoops(nodes, siblingOffsets, outerLoopParam, ctx, options)
14937
15035
  for (const child of n.children) {
14938
15036
  bindings.events.push(...collectLoopChildEventsWithNesting(child));
14939
15037
  }
14940
- if (ctx) {
14941
- bindings.conditionals.push(...collectLoopChildConditionals({ type: "fragment", children: n.children, loc: n.loc }, ctx, siblingOffsets, n.param, n.paramBindings, innerPreambleNames, n.index));
14942
- }
14943
15038
  }
14944
15039
  result.push({
14945
15040
  kind: "nested",
@@ -16075,6 +16170,7 @@ var RUNTIME_IMPORT_CANDIDATES = [
16075
16170
  "mapArrayLazy",
16076
16171
  "patchLeaf",
16077
16172
  "createDisposableEffect",
16173
+ "findCondContainer",
16078
16174
  "createComponent",
16079
16175
  "renderChild",
16080
16176
  "registerComponent",
@@ -17974,7 +18070,8 @@ function emitProviderAndChildInits(lines, ctx) {
17974
18070
  lines.push(` upsertChild(__scope, '${registryName}', '${child.slotId}', ${child.propsExpr})`);
17975
18071
  continue;
17976
18072
  }
17977
- const scopeRef = child.slotId ? `_${varSlotId(child.slotId)}` : "__scope";
18073
+ const isCommentRoot = child.slotId !== null && child.slotId === ctx.commentScopeRootSlotId;
18074
+ const scopeRef = !child.slotId || isCommentRoot ? "__scope" : `_${varSlotId(child.slotId)}`;
17978
18075
  lines.push(` initChild('${registryName}', ${scopeRef}, ${child.propsExpr})`);
17979
18076
  }
17980
18077
  }
@@ -18626,6 +18723,7 @@ function buildBranchInnerLoopsPlan(args) {
18626
18723
  const {
18627
18724
  innerLoops,
18628
18725
  scopeVar,
18726
+ condSlotId,
18629
18727
  outerLoopParam,
18630
18728
  outerLoopParamBindings,
18631
18729
  wrapOuter
@@ -18640,7 +18738,7 @@ function buildBranchInnerLoopsPlan(args) {
18640
18738
  const wrapInner = (expr) => wrapLoopParamAsAccessor(expr, inner.param, inner.paramBindings);
18641
18739
  const wrapBoth = (expr) => wrapLoopParamAsAccessor(wrapOuter(expr), inner.param, inner.paramBindings);
18642
18740
  const csl = inner.containerSlotId;
18643
- const containerExpr = csl ? `(${scopeVar}.querySelector('[bf="${csl}"]') ?? ${scopeVar}.querySelector(\`[${BF_HOST2}="\${__scopeId}"][${BF_AT2}="${csl}"]\`) ?? ${scopeVar})` : scopeVar;
18741
+ const containerExpr = csl ? `(${scopeVar}.querySelector('[bf="${csl}"]') ?? ${scopeVar}.querySelector(\`[${BF_HOST2}="\${__scopeId}"][${BF_AT2}="${csl}"]\`) ?? ${scopeVar})` : `findCondContainer(${scopeVar}, '${condSlotId}')`;
18644
18742
  const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(inner.param, inner.paramBindings);
18645
18743
  const wrappedKey = inner.key ? wrapLoopParamAsAccessor(inner.key, inner.param, inner.paramBindings) : null;
18646
18744
  const wrapIRNode = (node) => {
@@ -18724,13 +18822,15 @@ function buildLoopChildConditionalsPlan(args) {
18724
18822
  branch: cond.whenTrue,
18725
18823
  wrap,
18726
18824
  loopParam,
18727
- loopParamBindings
18825
+ loopParamBindings,
18826
+ condId: cond.slotId
18728
18827
  }),
18729
18828
  whenFalseArm: buildLoopChildArmPlan({
18730
18829
  branch: cond.whenFalse,
18731
18830
  wrap,
18732
18831
  loopParam,
18733
- loopParamBindings
18832
+ loopParamBindings,
18833
+ condId: cond.slotId
18734
18834
  })
18735
18835
  });
18736
18836
  }
@@ -18770,7 +18870,7 @@ function buildArmTextsPlan(texts, wrap) {
18770
18870
  }));
18771
18871
  }
18772
18872
  function buildLoopChildArmPlan(args) {
18773
- const { branch, wrap, loopParam, loopParamBindings } = args;
18873
+ const { branch, wrap, loopParam, loopParamBindings, condId } = args;
18774
18874
  return {
18775
18875
  events: buildBranchEventBindingsPlan({
18776
18876
  events: branch.events,
@@ -18783,6 +18883,7 @@ function buildLoopChildArmPlan(args) {
18783
18883
  innerLoops: buildBranchInnerLoopsPlan({
18784
18884
  innerLoops: branch.innerLoops,
18785
18885
  scopeVar: "__branchScope",
18886
+ condSlotId: condId,
18786
18887
  outerLoopParam: loopParam,
18787
18888
  outerLoopParamBindings: loopParamBindings,
18788
18889
  wrapOuter: wrap
@@ -18836,8 +18937,8 @@ function buildReactiveEffectsPlan(args) {
18836
18937
  wrappedCondition: wrap(cond.condition),
18837
18938
  whenTrueTemplateHtml: addCondAttrToTemplate(wrap(cond.whenTrueHtml), cond.slotId),
18838
18939
  whenFalseTemplateHtml: addCondAttrToTemplate(wrap(cond.whenFalseHtml), cond.slotId),
18839
- whenTrueArm: buildOuterArm(cond.whenTrue, wrap, loopParam, loopParamBindings, profileComponentName),
18840
- whenFalseArm: buildOuterArm(cond.whenFalse, wrap, loopParam, loopParamBindings, profileComponentName),
18940
+ whenTrueArm: buildOuterArm(cond.whenTrue, wrap, loopParam, loopParamBindings, cond.slotId, profileComponentName),
18941
+ whenFalseArm: buildOuterArm(cond.whenFalse, wrap, loopParam, loopParamBindings, cond.slotId, profileComponentName),
18841
18942
  ...cond.readsPreamble && { readsPreamble: true }
18842
18943
  });
18843
18944
  }
@@ -18849,7 +18950,7 @@ function buildReactiveEffectsPlan(args) {
18849
18950
  profileComponentName
18850
18951
  };
18851
18952
  }
18852
- function buildOuterArm(branch, wrap, loopParam, loopParamBindings, profileComponentName) {
18953
+ function buildOuterArm(branch, wrap, loopParam, loopParamBindings, condSlotId, profileComponentName) {
18853
18954
  return {
18854
18955
  events: buildBranchEventBindingsPlan({
18855
18956
  events: branch.events,
@@ -18863,6 +18964,7 @@ function buildOuterArm(branch, wrap, loopParam, loopParamBindings, profileCompon
18863
18964
  innerLoops: buildBranchInnerLoopsPlan({
18864
18965
  innerLoops: branch.innerLoops,
18865
18966
  scopeVar: "__branchScope",
18967
+ condSlotId,
18866
18968
  outerLoopParam: loopParam,
18867
18969
  outerLoopParamBindings: loopParamBindings,
18868
18970
  wrapOuter: wrap
@@ -18964,6 +19066,7 @@ function buildInnerLoopsPlan(args) {
18964
19066
  }
18965
19067
  function buildReactiveEmit(inner, level, wrapOuter, uidSuffix, outerLoopParam, outerLoopParamBindings) {
18966
19068
  const wrapInner = (expr) => wrapLoopParamAsAccessor(expr, inner.param, inner.paramBindings);
19069
+ const wrapBoth = (expr) => wrapLoopParamAsAccessor(wrapOuter(expr), inner.param, inner.paramBindings);
18967
19070
  const { head: paramHead, unwrap: paramUnwrap } = destructureLoopParam(inner.param, inner.paramBindings);
18968
19071
  const wrappedKey = inner.key ? wrapLoopParamAsAccessor(inner.key, inner.param, inner.paramBindings) : null;
18969
19072
  const wrapIRNode = (node) => {
@@ -19025,6 +19128,13 @@ function buildReactiveEmit(inner, level, wrapOuter, uidSuffix, outerLoopParam, o
19025
19128
  }));
19026
19129
  }
19027
19130
  const childRefs = buildChildRefBindings(inner.bindings.refs, inner.param, inner.paramBindings);
19131
+ const conditionals = buildLoopChildConditionalsPlan({
19132
+ conditionals: inner.bindings.conditionals,
19133
+ scopeVar: `__innerEl${uidSuffix}`,
19134
+ wrap: wrapBoth,
19135
+ loopParam: inner.param,
19136
+ loopParamBindings: inner.paramBindings
19137
+ });
19028
19138
  return {
19029
19139
  mode: "reactive",
19030
19140
  keyFn: loopKeyFn(inner),
@@ -19037,6 +19147,7 @@ function buildReactiveEmit(inner, level, wrapOuter, uidSuffix, outerLoopParam, o
19037
19147
  events,
19038
19148
  reactiveTexts,
19039
19149
  reactiveAttrs,
19150
+ conditionals,
19040
19151
  childRefs
19041
19152
  };
19042
19153
  }
@@ -19989,6 +20100,17 @@ function bindingIdArg(ctx, slotId) {
19989
20100
  return "";
19990
20101
  return `, ${JSON.stringify(`${ctx.componentName}#binding:${slotId}`)}`;
19991
20102
  }
20103
+ function emitValueUpdateStatements(target, expression) {
20104
+ return [
20105
+ `const __val = String(${expression})`,
20106
+ `if ('value' in ${target}) { if (${target}.value !== __val) ${target}.value = __val } else { ${target}.setAttribute('value', __val) }`
20107
+ ];
20108
+ }
20109
+ function emitChildValueMirrorStatements(target, expression) {
20110
+ return [
20111
+ `if ('value' in ${target}) { const __val = String(${expression}); if (${target}.value !== __val) ${target}.value = __val }`
20112
+ ];
20113
+ }
19992
20114
  function emitAttrUpdate(target, attrName, expression, meta) {
19993
20115
  const htmlName = toHtmlAttrName(attrName);
19994
20116
  if (attrName === "dangerouslySetInnerHTML" || htmlName === "dangerouslySetInnerHTML") {
@@ -20007,10 +20129,7 @@ function emitAttrUpdate(target, attrName, expression, meta) {
20007
20129
  ];
20008
20130
  }
20009
20131
  if (htmlName === "value") {
20010
- return [
20011
- `const __val = String(${expression})`,
20012
- `if (${target}.value !== __val) ${target}.value = __val`
20013
- ];
20132
+ return emitValueUpdateStatements(target, expression);
20014
20133
  }
20015
20134
  if (isBooleanAttr(htmlName)) {
20016
20135
  return [`${target}.${htmlName} = !!(${expression})`];
@@ -20258,30 +20377,30 @@ function emitReactivePropBindings(lines, ctx) {
20258
20377
  propsBySlot.get(prop.slotId).push(prop);
20259
20378
  }
20260
20379
  for (const [slotId, props] of propsBySlot) {
20261
- const v = varSlotId(slotId);
20262
- lines.push(` if (_${v}) {`);
20380
+ const ref = slotId === ctx.commentScopeRootSlotId ? "__scope" : `_${varSlotId(slotId)}`;
20381
+ lines.push(` if (${ref}) {`);
20263
20382
  for (const prop of props) {
20264
20383
  const value = `${prop.expression}()`;
20265
20384
  if (prop.propName === "selected") {
20266
20385
  if (prop.componentName === "TabsContent") {
20267
- lines.push(` _${v}.setAttribute('data-state', ${value} ? 'active' : 'inactive')`);
20386
+ lines.push(` ${ref}.setAttribute('data-state', ${value} ? 'active' : 'inactive')`);
20268
20387
  lines.push(` if (${value}) {`);
20269
- lines.push(` _${v}.classList.remove('hidden')`);
20388
+ lines.push(` ${ref}.classList.remove('hidden')`);
20270
20389
  lines.push(` } else {`);
20271
- lines.push(` _${v}.classList.add('hidden')`);
20390
+ lines.push(` ${ref}.classList.add('hidden')`);
20272
20391
  lines.push(` }`);
20273
20392
  } else {
20274
- lines.push(` _${v}.setAttribute('aria-selected', String(${value}))`);
20275
- lines.push(` _${v}.setAttribute('data-state', ${value} ? 'active' : 'inactive')`);
20276
- lines.push(` _${v}.setAttribute('tabindex', ${value} ? '0' : '-1')`);
20393
+ lines.push(` ${ref}.setAttribute('aria-selected', String(${value}))`);
20394
+ lines.push(` ${ref}.setAttribute('data-state', ${value} ? 'active' : 'inactive')`);
20395
+ lines.push(` ${ref}.setAttribute('tabindex', ${value} ? '0' : '-1')`);
20277
20396
  }
20278
20397
  } else if (prop.propName === "value") {
20279
- lines.push(` const __val = String(${value})`);
20280
- lines.push(` if (_${v}.value !== __val) _${v}.value = __val`);
20398
+ for (const stmt of emitChildValueMirrorStatements(ref, value))
20399
+ lines.push(` ${stmt}`);
20281
20400
  } else if (isBooleanAttr(prop.propName)) {
20282
- lines.push(` _${v}.${prop.propName} = !!(${value})`);
20401
+ lines.push(` ${ref}.${prop.propName} = !!(${value})`);
20283
20402
  } else {
20284
- lines.push(` _${v}.setAttribute('${prop.propName}', String(${value}))`);
20403
+ lines.push(` ${ref}.setAttribute('${prop.propName}', String(${value}))`);
20285
20404
  }
20286
20405
  }
20287
20406
  lines.push(` }`);
@@ -20304,13 +20423,17 @@ function emitReactiveChildProps(lines, ctx) {
20304
20423
  }
20305
20424
  for (const [, props] of propsByComponent) {
20306
20425
  const first = props[0];
20426
+ const isCommentRoot = first.slotId !== null && first.slotId === ctx.commentScopeRootSlotId;
20307
20427
  const varSuffix = first.slotId ? varSlotId(first.slotId).replace(/-/g, "_") : first.componentName;
20308
- const varName = `__${first.componentName}_${varSuffix}El`;
20309
- const selectorArg = first.slotId ? first.slotId : first.componentName;
20310
- lines.push(` const [${varName}] = $c(__scope, '${selectorArg}')`);
20428
+ const varName = isCommentRoot ? "__scope" : `__${first.componentName}_${varSuffix}El`;
20429
+ if (!isCommentRoot) {
20430
+ const selectorArg = first.slotId ? first.slotId : first.componentName;
20431
+ lines.push(` const [${varName}] = $c(__scope, '${selectorArg}')`);
20432
+ }
20311
20433
  lines.push(` if (${varName}) {`);
20312
20434
  for (const prop of props) {
20313
- for (const stmt of emitAttrUpdate(varName, prop.attrName, prop.expression, prop)) {
20435
+ const stmts = toHtmlAttrName(prop.attrName) === "value" ? emitChildValueMirrorStatements(varName, prop.expression) : emitAttrUpdate(varName, prop.attrName, prop.expression, prop);
20436
+ for (const stmt of stmts) {
20314
20437
  lines.push(` ${stmt}`);
20315
20438
  }
20316
20439
  }
@@ -20871,8 +20994,9 @@ function seedDiffersExpr(target, a) {
20871
20994
  return `${target}.getAttribute('style') !== styleToCss(__x)`;
20872
20995
  if (html === "class")
20873
20996
  return `${target}.getAttribute('class') !== (__x != null ? String(__x) : null)`;
20874
- if (html === "value")
20875
- return `${target}.value !== String(__x)`;
20997
+ if (html === "value") {
20998
+ return `('value' in ${target} ? ${target}.value !== String(__x) : ${target}.getAttribute('value') !== String(__x))`;
20999
+ }
20876
21000
  if (isBooleanAttr(html))
20877
21001
  return `${target}.${html} !== !!(__x)`;
20878
21002
  if (a.meta.presenceOrUndefined) {
@@ -21230,6 +21354,9 @@ function emitReactive(lines, inner, indent, pc) {
21230
21354
  }
21231
21355
  lines.push(`${indent} }${profileBindingId(pc, attr.slotId)}) }`);
21232
21356
  }
21357
+ if (emit.conditionals.length > 0) {
21358
+ stringifyLoopChildConditionals(lines, emit.conditionals, `${indent} `, pc);
21359
+ }
21233
21360
  emitLoopChildRefs(lines, emit.childRefs, {
21234
21361
  indent: `${indent} `,
21235
21362
  elVar: `__innerEl${uid}`,
@@ -21993,6 +22120,9 @@ function generateElementRefs(ctx) {
21993
22120
  for (const slotId of componentSlots) {
21994
22121
  regularSlots.delete(slotId);
21995
22122
  }
22123
+ if (ctx.commentScopeRootSlotId) {
22124
+ componentSlots.delete(ctx.commentScopeRootSlotId);
22125
+ }
21996
22126
  if (regularSlots.size === 0 && componentSlots.size === 0)
21997
22127
  return "";
21998
22128
  const refLines = [];
@@ -22479,6 +22609,7 @@ function createContext(ir, scope, adapterCapabilities, profile) {
22479
22609
  refElements: [],
22480
22610
  childInits: [],
22481
22611
  deferredChildSlots: new Set,
22612
+ commentScopeRootSlotId: ir.root.type === "component" ? ir.root.slotId : null,
22482
22613
  reactiveProps: [],
22483
22614
  reactiveChildProps: [],
22484
22615
  reactiveAttrs: [],
@@ -23480,12 +23611,38 @@ function evalNode(node, ctx) {
23480
23611
  const baseResult = evalNode(node.expression, ctx);
23481
23612
  if (baseResult === undefined)
23482
23613
  return;
23483
- return UNRESOLVED;
23614
+ if (baseResult === UNRESOLVED || baseResult === null || typeof baseResult !== "object") {
23615
+ return UNRESOLVED;
23616
+ }
23617
+ const proto = Object.getPrototypeOf(baseResult);
23618
+ if (proto !== Object.prototype && proto !== null)
23619
+ return UNRESOLVED;
23620
+ const key = node.name.text;
23621
+ return Object.prototype.hasOwnProperty.call(baseResult, key) ? baseResult[key] : undefined;
23484
23622
  }
23485
23623
  if (ts22.isCallExpression(node)) {
23486
23624
  if (node.arguments.length === 0 && ts22.isIdentifier(node.expression) && node.expression.text in ctx.bindings) {
23487
23625
  return ctx.bindings[node.expression.text];
23488
23626
  }
23627
+ if (ts22.isPropertyAccessExpression(node.expression) && node.expression.name.text === "map" && node.arguments.length === 1) {
23628
+ const arrow = node.arguments[0];
23629
+ if (ts22.isArrowFunction(arrow) && arrow.parameters.length === 1 && ts22.isIdentifier(arrow.parameters[0].name) && !ts22.isBlock(arrow.body)) {
23630
+ const recv = evalNode(node.expression.expression, ctx);
23631
+ if (Array.isArray(recv)) {
23632
+ const paramName = arrow.parameters[0].name.text;
23633
+ const mapped = [];
23634
+ for (const item of recv) {
23635
+ const localBindings = { ...ctx.bindings, [paramName]: item };
23636
+ const v = evalNode(arrow.body, { ...ctx, bindings: localBindings });
23637
+ if (v === UNRESOLVED)
23638
+ return UNRESOLVED;
23639
+ mapped.push(v === undefined ? null : v);
23640
+ }
23641
+ return mapped;
23642
+ }
23643
+ }
23644
+ return UNRESOLVED;
23645
+ }
23489
23646
  if (ts22.isPropertyAccessExpression(node.expression) && node.expression.name.text === "join") {
23490
23647
  const recv = evalNode(node.expression.expression, ctx);
23491
23648
  if (Array.isArray(recv)) {
@@ -23989,7 +24146,7 @@ function parseRecordIndexAccess(val, localConstants, propsParams, resolveKey) {
23989
24146
 
23990
24147
  // src/ssr-seed-plan.ts
23991
24148
  function classify2(name, origin, expr, parsed, available) {
23992
- if (!isSupported(parsed).supported)
24149
+ if (!isSupportedValue(parsed).supported)
23993
24150
  return { kind: "opaque", name, origin };
23994
24151
  const frees = freeIdentifiers(parsed);
23995
24152
  if (frees === null)
@@ -24052,7 +24209,7 @@ function computeSsrSeedPlan(metadata) {
24052
24209
  }
24053
24210
  }
24054
24211
  const expr = signal.initialValue.trim();
24055
- steps.push(expr === "" ? { kind: "opaque", name: signal.getter, origin: "signal" } : classify2(signal.getter, "signal", expr, resolveThroughLocalConsts(parseExpression(expr), localConsts), available));
24212
+ steps.push(expr === "" ? { kind: "opaque", name: signal.getter, origin: "signal" } : classify2(signal.getter, "signal", expr, resolveThroughLocalConsts(signal.parsed ?? parseExpression(`(${expr})`), localConsts), available));
24056
24213
  available.add(signal.getter);
24057
24214
  }
24058
24215
  for (const memo of metadata.memos) {
@@ -24216,7 +24373,7 @@ function checkExpr(expr, loc, meta, bindings, matchers, errors, seen) {
24216
24373
  break;
24217
24374
  case "object-literal":
24218
24375
  for (const prop of expr.properties)
24219
- recurse(prop.value);
24376
+ recurse(prop.kind === "spread" ? prop.expr : prop.value);
24220
24377
  break;
24221
24378
  case "array-method":
24222
24379
  recurse(expr.object);
@@ -25599,6 +25756,26 @@ function isStringConcatBinary(op, left, right, isStringName) {
25599
25756
  function groupBinaryOperand(operand, emitted) {
25600
25757
  return operand.kind === "binary" || operand.kind === "logical" || operand.kind === "conditional" ? `(${emitted})` : emitted;
25601
25758
  }
25759
+ function groupObjectLiteralSegments(properties, literalOf, emit) {
25760
+ const segments = [];
25761
+ let run = [];
25762
+ const flushRun = () => {
25763
+ if (run.length > 0) {
25764
+ segments.push(literalOf(run));
25765
+ run = [];
25766
+ }
25767
+ };
25768
+ for (const p of properties) {
25769
+ if (p.kind === "spread") {
25770
+ flushRun();
25771
+ segments.push(emit(p.expr));
25772
+ } else {
25773
+ run.push(p);
25774
+ }
25775
+ }
25776
+ flushRun();
25777
+ return segments;
25778
+ }
25602
25779
  function emitParsedExpr(expr, emitter) {
25603
25780
  const emit = (child) => emitParsedExpr(child, emitter);
25604
25781
  switch (expr.kind) {
@@ -25745,6 +25922,17 @@ function evaluateStaticLiteral(expr, bindings) {
25745
25922
  case "object-literal": {
25746
25923
  const out = {};
25747
25924
  for (const prop of expr.properties) {
25925
+ if (prop.kind === "spread") {
25926
+ const resolved2 = evaluateStaticLiteral(prop.expr, bindings);
25927
+ if (!resolved2)
25928
+ return null;
25929
+ if (resolved2.value === null || resolved2.value === undefined)
25930
+ continue;
25931
+ if (typeof resolved2.value !== "object" || Array.isArray(resolved2.value))
25932
+ return null;
25933
+ Object.assign(out, resolved2.value);
25934
+ continue;
25935
+ }
25748
25936
  const resolved = evaluateStaticLiteral(prop.value, bindings);
25749
25937
  if (!resolved)
25750
25938
  return null;
@@ -25814,6 +26002,8 @@ function matchQueryHrefCall(callee, args, localNames) {
25814
26002
  return null;
25815
26003
  const triples = [];
25816
26004
  for (const p of obj.properties) {
26005
+ if (p.kind === "spread")
26006
+ return null;
25817
26007
  const v = p.value;
25818
26008
  if (v.kind === "conditional" && isOmitBranch(v.alternate)) {
25819
26009
  triples.push({ guard: v.test, key: p.key, value: v.consequent });
@@ -26001,6 +26191,8 @@ function htmlPropValue(parsed) {
26001
26191
  if (parsed.properties.length !== 1)
26002
26192
  return null;
26003
26193
  const [prop] = parsed.properties;
26194
+ if (prop.kind === "spread")
26195
+ return null;
26004
26196
  if (prop.key !== "__html")
26005
26197
  return null;
26006
26198
  return prop.value;
@@ -28925,6 +29117,7 @@ export {
28925
29117
  joinProfilerEvents,
28926
29118
  isValueReferenceIdentifier,
28927
29119
  isValidHelperId,
29120
+ isSupportedValue,
28928
29121
  isSupported,
28929
29122
  isStringTypedOperand,
28930
29123
  isStringConcatBinary,
@@ -28937,6 +29130,7 @@ export {
28937
29130
  importsSearchParams,
28938
29131
  identifierPath,
28939
29132
  hasUnsafeStyleValue,
29133
+ groupObjectLiteralSegments,
28940
29134
  groupBinaryOperand,
28941
29135
  graphToJSON,
28942
29136
  getLoweringPlugins,