octane 0.1.22 → 0.1.23

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.
@@ -4404,6 +4404,31 @@ export function hasOwnValueReturn(node) {
4404
4404
  return walk(body.body || []);
4405
4405
  }
4406
4406
 
4407
+ /**
4408
+ * Whether a statement list always completes abruptly, so control can never fall
4409
+ * past its end. Lets an outputless `@{ … }` body drop the tail return it would
4410
+ * otherwise synthesize, because the body's own returns already cover every path.
4411
+ *
4412
+ * Deliberately syntactic: `return`, `throw`, a block that ends abruptly, and an
4413
+ * if/else whose arms both do. Anything subtler keeps the tail, which is always
4414
+ * safe — the runtime reads a fallen-through `undefined` as "this body already
4415
+ * emitted its template", so the tail must stay wherever reachability is unproven.
4416
+ */
4417
+ function alwaysCompletesAbruptly(statements) {
4418
+ const last = statements[statements.length - 1];
4419
+ if (!last) return false;
4420
+ if (last.type === 'ReturnStatement' || last.type === 'ThrowStatement') return true;
4421
+ if (last.type === 'BlockStatement') return alwaysCompletesAbruptly(last.body || []);
4422
+ if (last.type === 'IfStatement') {
4423
+ return (
4424
+ !!last.alternate &&
4425
+ alwaysCompletesAbruptly([last.consequent]) &&
4426
+ alwaysCompletesAbruptly([last.alternate])
4427
+ );
4428
+ }
4429
+ return false;
4430
+ }
4431
+
4407
4432
  /**
4408
4433
  * A mixed shorthand's early return must always reach renderReturnedValue. The
4409
4434
  * runtime reserves `undefined` for a compiled-void body that already emitted its
@@ -10562,10 +10587,20 @@ function compileFunctionBody(node, ctx, name, parentNs = 'html', cssHash = null,
10562
10587
  const shellOrigin = node.loc ? node : node.id?.loc ? node.id : prevFnOrigin;
10563
10588
  let plan = null;
10564
10589
  let returnedExpression = null;
10565
- if (returnedOutput) {
10566
- const rendered = jsxNodes[0];
10590
+ if (returnedOutput && jsxNodes.length === 0) {
10591
+ // A `@{ … }` body can carry value returns with NO trailing output node —
10592
+ // `@{ … return null }` while a component is being written, or a React-shaped
10593
+ // `return <jsx>` inside the block. There is no template to lower: the body's
10594
+ // own returns are the whole output, so the tail is a plain `null` covering
10595
+ // the fall-through path. When the body provably never falls through, that
10596
+ // tail is unreachable and is dropped. Statement returns already normalized
10597
+ // to `?? null`.
10598
+ if (!alwaysCompletesAbruptly(rewrittenStatements)) {
10599
+ returnedExpression = b.literal(null, 'null', node);
10600
+ }
10601
+ } else if (returnedOutput) {
10567
10602
  returnedExpression = lowerReturnJsx(
10568
- rewriteHookCalls(rendered, ctx, name, options?.localHookSlots === true),
10603
+ rewriteHookCalls(jsxNodes[0], ctx, name, options?.localHookSlots === true),
10569
10604
  ctx,
10570
10605
  inlinedSubs,
10571
10606
  cssHash,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "octane",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "sideEffects": false,