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.
- package/dist/compiler/compile.js +38 -3
- package/package.json +1 -1
package/dist/compiler/compile.js
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
10603
|
+
rewriteHookCalls(jsxNodes[0], ctx, name, options?.localHookSlots === true),
|
|
10569
10604
|
ctx,
|
|
10570
10605
|
inlinedSubs,
|
|
10571
10606
|
cssHash,
|