@tsrx/core 0.1.2 → 0.1.3
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/package.json +1 -1
- package/src/index.js +1 -0
- package/src/plugin.js +164 -9
- package/src/transform/jsx/index.js +179 -21
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -149,6 +149,7 @@ export {
|
|
|
149
149
|
MERGE_REFS_INTERNAL_NAME,
|
|
150
150
|
merge_duplicate_refs as mergeDuplicateRefs,
|
|
151
151
|
NORMALIZE_SPREAD_PROPS_INTERNAL_NAME,
|
|
152
|
+
return_value_body_to_expression as returnValueBodyToExpression,
|
|
152
153
|
rewrite_loop_continues_to_bare_returns as rewriteLoopContinuesToBareReturns,
|
|
153
154
|
to_jsx_attribute as toJsxAttribute,
|
|
154
155
|
validate_at_most_one_ref_attribute as validateAtMostOneRefAttribute,
|
package/src/plugin.js
CHANGED
|
@@ -220,6 +220,7 @@ export function TSRXPlugin(config) {
|
|
|
220
220
|
#errors = undefined;
|
|
221
221
|
/** @type {string | null} */
|
|
222
222
|
#filename = null;
|
|
223
|
+
#componentDepth = 0;
|
|
223
224
|
#functionBodyDepth = 0;
|
|
224
225
|
|
|
225
226
|
/**
|
|
@@ -270,6 +271,14 @@ export function TSRXPlugin(config) {
|
|
|
270
271
|
return null;
|
|
271
272
|
}
|
|
272
273
|
|
|
274
|
+
#isInsideComponent() {
|
|
275
|
+
return this.#componentDepth > 0;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
#isInsideComponentTemplate() {
|
|
279
|
+
return this.#isInsideComponent() && this.#functionBodyDepth === 0;
|
|
280
|
+
}
|
|
281
|
+
|
|
273
282
|
#popTsxTokenContextBeforeTemplateExpressionChild() {
|
|
274
283
|
let index = this.pos;
|
|
275
284
|
let has_newline = false;
|
|
@@ -320,17 +329,133 @@ export function TSRXPlugin(config) {
|
|
|
320
329
|
}
|
|
321
330
|
}
|
|
322
331
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
332
|
+
/**
|
|
333
|
+
* @param {number} index
|
|
334
|
+
* @returns {number}
|
|
335
|
+
*/
|
|
336
|
+
#skipWhitespaceAndComments(index) {
|
|
337
|
+
while (index < this.input.length) {
|
|
338
|
+
const ch = this.input.charCodeAt(index);
|
|
339
|
+
if (ch === 32 || ch === 9 || ch === 10 || ch === 13) {
|
|
340
|
+
index++;
|
|
341
|
+
} else if (ch === 47 && this.input.charCodeAt(index + 1) === 42) {
|
|
342
|
+
const end = this.input.indexOf('*/', index + 2);
|
|
343
|
+
index = end === -1 ? this.input.length : end + 2;
|
|
344
|
+
} else if (ch === 47 && this.input.charCodeAt(index + 1) === 47) {
|
|
345
|
+
index += 2;
|
|
346
|
+
while (index < this.input.length) {
|
|
347
|
+
const comment_ch = this.input.charCodeAt(index);
|
|
348
|
+
if (comment_ch === 10 || comment_ch === 13) break;
|
|
349
|
+
index++;
|
|
350
|
+
}
|
|
351
|
+
} else {
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
326
354
|
}
|
|
355
|
+
return index;
|
|
356
|
+
}
|
|
327
357
|
|
|
328
|
-
|
|
358
|
+
/** @returns {number} */
|
|
359
|
+
#countFollowingRightBraces() {
|
|
360
|
+
let index = this.end;
|
|
361
|
+
let count = 0;
|
|
362
|
+
while (index < this.input.length) {
|
|
363
|
+
index = this.#skipWhitespaceAndComments(index);
|
|
364
|
+
if (this.input.charCodeAt(index) !== 125) break;
|
|
365
|
+
count++;
|
|
366
|
+
index++;
|
|
367
|
+
}
|
|
368
|
+
return count;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* @param {AST.Tsx | AST.Tsrx | AST.TsxCompat} node
|
|
373
|
+
* @returns {boolean}
|
|
374
|
+
*/
|
|
375
|
+
#hasDirectStatementChild(node) {
|
|
376
|
+
return node.children?.some(
|
|
377
|
+
(child) => child.type.endsWith('Statement') || child.type === 'VariableDeclaration',
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* @param {AST.Tsx | AST.Tsrx | AST.TsxCompat} node
|
|
383
|
+
*/
|
|
384
|
+
#popTokenContextsAfterTemplateExpressionElement(node) {
|
|
385
|
+
const ctx = this.context;
|
|
386
|
+
const ci = ctx.length - 1;
|
|
387
|
+
const top = ctx[ci];
|
|
388
|
+
const second = ctx[ci - 1];
|
|
389
|
+
|
|
390
|
+
// Expression-bodied templates (no statement child) followed by `,`
|
|
391
|
+
// in an object/array literal need surgical fixups; statement-bodied
|
|
392
|
+
// templates fall through to the JSX-expression-container strip.
|
|
393
|
+
const has_stmt_child = this.#hasDirectStatementChild(node);
|
|
394
|
+
if (this.type === tt.comma && !has_stmt_child) {
|
|
395
|
+
// Tail `..., (b_expr)+, tc_expr, b_stat`: the JSX expression
|
|
396
|
+
// container leaks an extra `tc_expr, b_stat`. Pop them, and if
|
|
397
|
+
// the JSX container also closes immediately (`}}` ahead), drop
|
|
398
|
+
// one of the doubled-up `b_expr` contexts too.
|
|
399
|
+
if (top === b_stat && second === tstc.tc_expr) {
|
|
400
|
+
let expr_count = 0;
|
|
401
|
+
for (let i = ci - 2; ctx[i] === b_expr; i--) expr_count++;
|
|
402
|
+
const following_braces = this.#countFollowingRightBraces();
|
|
403
|
+
if (expr_count === 2 || following_braces > 1) {
|
|
404
|
+
if (following_braces > 1 && expr_count > 1) {
|
|
405
|
+
ctx.splice(ci - 2, expr_count - 1);
|
|
406
|
+
ctx.pop();
|
|
407
|
+
this.exprAllowed = false;
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
if (expr_count === 2 && following_braces === 0) {
|
|
411
|
+
// Fragment expression value followed by another
|
|
412
|
+
// object/array entry inside a JSX expression
|
|
413
|
+
// container (`{ a: <></>, b: ... }` or
|
|
414
|
+
// `[<></>, ...]`): strip both the leaked tc_expr
|
|
415
|
+
// and b_stat so the next entry parses as an
|
|
416
|
+
// expression, and leave exprAllowed alone so a
|
|
417
|
+
// following `<` still tokenizes as jsxTagStart.
|
|
418
|
+
ctx.length = ci - 1;
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
ctx.pop();
|
|
422
|
+
this.exprAllowed = false;
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
// Tail `..., b_expr, b_expr` for fragments-with-children
|
|
427
|
+
// inside an array or object literal: re-arm expression mode
|
|
428
|
+
// so the next item parses as an expression value, not a JSX
|
|
429
|
+
// child. If the surrounding b_expr chain has already been
|
|
430
|
+
// consumed, push one back so the subsequent item still has
|
|
431
|
+
// a literal context. Leave exprAllowed alone so a following
|
|
432
|
+
// `<` still tokenizes as jsxTagStart.
|
|
433
|
+
if (top === b_expr && second === b_expr) {
|
|
434
|
+
if (ctx[ci - 2] !== b_expr && ctx[ci - 2] !== tstc.tc_oTag) {
|
|
435
|
+
ctx.push(b_expr);
|
|
436
|
+
}
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Inside `{<tsrx>...</tsrx>}` JSX expression container — strip
|
|
442
|
+
// both the leaked `b_stat` and the container's `tc_expr`.
|
|
443
|
+
if (top === b_stat && second === tstc.tc_expr) {
|
|
444
|
+
ctx.length = ci - 1;
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
// Closing token after the template at expression position. For `}`
|
|
448
|
+
// only pop if it actually closes this `b_expr` — otherwise the
|
|
449
|
+
// brace targets an inner callback/object body that should pop it
|
|
450
|
+
// naturally on the next token step.
|
|
329
451
|
if (
|
|
330
|
-
this.
|
|
331
|
-
|
|
452
|
+
(this.type === tt.braceR &&
|
|
453
|
+
top === b_expr &&
|
|
454
|
+
(this.#countFollowingRightBraces() === 0 || second === b_expr)) ||
|
|
455
|
+
(this.type === tt.parenR && top?.token === '(') ||
|
|
456
|
+
(this.type === tt.bracketR && top?.token === '[')
|
|
332
457
|
) {
|
|
333
|
-
|
|
458
|
+
ctx.pop();
|
|
334
459
|
this.exprAllowed = false;
|
|
335
460
|
}
|
|
336
461
|
}
|
|
@@ -733,7 +858,7 @@ export function TSRXPlugin(config) {
|
|
|
733
858
|
|
|
734
859
|
if (code === 60) {
|
|
735
860
|
// < character
|
|
736
|
-
const inComponent = this.#
|
|
861
|
+
const inComponent = this.#isInsideComponentTemplate();
|
|
737
862
|
/** @type {number | null} */
|
|
738
863
|
let prevNonWhitespaceChar = null;
|
|
739
864
|
|
|
@@ -1089,11 +1214,13 @@ export function TSRXPlugin(config) {
|
|
|
1089
1214
|
this.eat(tt.braceL);
|
|
1090
1215
|
node.body = [];
|
|
1091
1216
|
this.#path.push(node);
|
|
1217
|
+
this.#componentDepth++;
|
|
1092
1218
|
|
|
1093
1219
|
try {
|
|
1094
1220
|
this.parseTemplateBody(node.body);
|
|
1095
1221
|
} finally {
|
|
1096
1222
|
this.#functionBodyDepth = parent_function_body_depth;
|
|
1223
|
+
this.#componentDepth--;
|
|
1097
1224
|
}
|
|
1098
1225
|
this.#path.pop();
|
|
1099
1226
|
this.exitScope();
|
|
@@ -1317,6 +1444,23 @@ export function TSRXPlugin(config) {
|
|
|
1317
1444
|
parseFunctionBody(node, isArrowFunction, isMethod, forInit, ...args) {
|
|
1318
1445
|
this.#functionBodyDepth++;
|
|
1319
1446
|
this.#functionStack.push(node);
|
|
1447
|
+
// Inside a component, nested JS function bodies should parse like
|
|
1448
|
+
// ordinary functions, not component template bodies.
|
|
1449
|
+
if (
|
|
1450
|
+
// Only adjust functions declared while parsing a component body.
|
|
1451
|
+
this.#isInsideComponent() &&
|
|
1452
|
+
// A stale JSX expression context means the surrounding template
|
|
1453
|
+
// tokenizer can still treat `<` as template markup.
|
|
1454
|
+
this.context.some((context) => context === tstc.tc_expr) &&
|
|
1455
|
+
// Keep arrows/functions inside JSX tags, such as event handlers,
|
|
1456
|
+
// on the normal JSX attribute parsing path.
|
|
1457
|
+
!this.context.some((context) => context === tstc.tc_oTag || context === tstc.tc_cTag) &&
|
|
1458
|
+
// Only reset statement-level function bodies, not expression
|
|
1459
|
+
// contexts that are actively parsing JSX.
|
|
1460
|
+
this.curContext() === b_stat
|
|
1461
|
+
) {
|
|
1462
|
+
this.context = [b_stat];
|
|
1463
|
+
}
|
|
1320
1464
|
|
|
1321
1465
|
try {
|
|
1322
1466
|
return super.parseFunctionBody(node, isArrowFunction, isMethod, forInit, ...args);
|
|
@@ -1929,7 +2073,9 @@ export function TSRXPlugin(config) {
|
|
|
1929
2073
|
const parsed = /** @type {import('estree-jsx').JSXElement} */ (
|
|
1930
2074
|
/** @type {unknown} */ (this.parseElement())
|
|
1931
2075
|
);
|
|
1932
|
-
this.#
|
|
2076
|
+
this.#popTokenContextsAfterTemplateExpressionElement(
|
|
2077
|
+
/** @type {AST.Tsx | AST.Tsrx | AST.TsxCompat} */ (/** @type {unknown} */ (parsed)),
|
|
2078
|
+
);
|
|
1933
2079
|
return parsed;
|
|
1934
2080
|
}
|
|
1935
2081
|
|
|
@@ -2853,6 +2999,15 @@ export function TSRXPlugin(config) {
|
|
|
2853
2999
|
if (!node) {
|
|
2854
3000
|
this.unexpected();
|
|
2855
3001
|
}
|
|
3002
|
+
if (this.#functionBodyDepth > 0 && node.type === 'Tsrx' && this.curContext() === b_stat) {
|
|
3003
|
+
this.context.pop();
|
|
3004
|
+
if (this.curContext() === tstc.tc_expr) {
|
|
3005
|
+
this.context.pop();
|
|
3006
|
+
}
|
|
3007
|
+
if (this.curContext() === b_stat) {
|
|
3008
|
+
this.context.pop();
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
2856
3011
|
return node;
|
|
2857
3012
|
}
|
|
2858
3013
|
|
|
@@ -682,7 +682,7 @@ function build_component_statements(body_nodes, transform_context) {
|
|
|
682
682
|
function build_render_statements(body_nodes, return_null_when_empty, transform_context) {
|
|
683
683
|
const statements = [];
|
|
684
684
|
const render_nodes = [];
|
|
685
|
-
let
|
|
685
|
+
let has_terminal_return = false;
|
|
686
686
|
|
|
687
687
|
// Create a new bindings map so inner-scope bindings from
|
|
688
688
|
// collect_statement_bindings don't leak to the caller's scope.
|
|
@@ -707,7 +707,13 @@ function build_render_statements(body_nodes, return_null_when_empty, transform_c
|
|
|
707
707
|
if (is_bare_return_statement(child)) {
|
|
708
708
|
statements.push(create_component_return_statement(render_nodes, child));
|
|
709
709
|
render_nodes.length = 0;
|
|
710
|
-
|
|
710
|
+
has_terminal_return = true;
|
|
711
|
+
continue;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
if (child?.type === 'ReturnStatement' && child.argument != null) {
|
|
715
|
+
statements.push(child);
|
|
716
|
+
has_terminal_return = true;
|
|
711
717
|
continue;
|
|
712
718
|
}
|
|
713
719
|
|
|
@@ -968,7 +974,7 @@ function build_render_statements(body_nodes, return_null_when_empty, transform_c
|
|
|
968
974
|
}
|
|
969
975
|
|
|
970
976
|
const return_arg = build_return_expression(render_nodes);
|
|
971
|
-
if (return_arg || (return_null_when_empty && !
|
|
977
|
+
if (return_arg || (return_null_when_empty && !has_terminal_return)) {
|
|
972
978
|
statements.push({
|
|
973
979
|
type: 'ReturnStatement',
|
|
974
980
|
argument: return_arg || { type: 'Literal', value: null, raw: 'null' },
|
|
@@ -2761,7 +2767,10 @@ function child_contains_return_semantics(node) {
|
|
|
2761
2767
|
return false;
|
|
2762
2768
|
}
|
|
2763
2769
|
|
|
2764
|
-
if (
|
|
2770
|
+
if (
|
|
2771
|
+
(node.type === 'ReturnStatement' && node.argument == null) ||
|
|
2772
|
+
is_lone_return_if_statement(node)
|
|
2773
|
+
) {
|
|
2765
2774
|
return true;
|
|
2766
2775
|
}
|
|
2767
2776
|
|
|
@@ -3448,22 +3457,25 @@ function tsrx_node_to_jsx_expression(node, transform_context, in_jsx_child = fal
|
|
|
3448
3457
|
let expression;
|
|
3449
3458
|
if (children.length === 0) {
|
|
3450
3459
|
expression = create_null_literal();
|
|
3451
|
-
} else if (
|
|
3452
|
-
children.every(is_inline_element_child) &&
|
|
3453
|
-
!children_contain_return_semantics(children)
|
|
3454
|
-
) {
|
|
3455
|
-
const saved_inside_element_child = transform_context.inside_element_child;
|
|
3456
|
-
transform_context.inside_element_child = true;
|
|
3457
|
-
try {
|
|
3458
|
-
const render_nodes = children.map((/** @type {any} */ child) =>
|
|
3459
|
-
to_jsx_child(child, transform_context),
|
|
3460
|
-
);
|
|
3461
|
-
expression = build_return_expression(render_nodes) || create_null_literal();
|
|
3462
|
-
} finally {
|
|
3463
|
-
transform_context.inside_element_child = saved_inside_element_child;
|
|
3464
|
-
}
|
|
3465
3460
|
} else {
|
|
3466
|
-
expression =
|
|
3461
|
+
expression = return_value_body_to_expression(children, node, transform_context);
|
|
3462
|
+
}
|
|
3463
|
+
|
|
3464
|
+
if (!expression) {
|
|
3465
|
+
if (children.every(is_inline_element_child) && !children_contain_return_semantics(children)) {
|
|
3466
|
+
const saved_inside_element_child = transform_context.inside_element_child;
|
|
3467
|
+
transform_context.inside_element_child = true;
|
|
3468
|
+
try {
|
|
3469
|
+
const render_nodes = children.map((/** @type {any} */ child) =>
|
|
3470
|
+
to_jsx_child(child, transform_context),
|
|
3471
|
+
);
|
|
3472
|
+
expression = build_return_expression(render_nodes) || create_null_literal();
|
|
3473
|
+
} finally {
|
|
3474
|
+
transform_context.inside_element_child = saved_inside_element_child;
|
|
3475
|
+
}
|
|
3476
|
+
} else {
|
|
3477
|
+
expression = statement_body_to_jsx_child(children, transform_context).expression;
|
|
3478
|
+
}
|
|
3467
3479
|
}
|
|
3468
3480
|
|
|
3469
3481
|
if (
|
|
@@ -3479,6 +3491,149 @@ function tsrx_node_to_jsx_expression(node, transform_context, in_jsx_child = fal
|
|
|
3479
3491
|
return expression;
|
|
3480
3492
|
}
|
|
3481
3493
|
|
|
3494
|
+
/**
|
|
3495
|
+
* Explicit return values inside expression-position `<tsrx>` templates are JavaScript
|
|
3496
|
+
* values, so keep them out of platform render control flow.
|
|
3497
|
+
*
|
|
3498
|
+
* @param {any[]} body_nodes
|
|
3499
|
+
* @param {any} source_node
|
|
3500
|
+
* @param {TransformContext} [transform_context]
|
|
3501
|
+
* @returns {any | null}
|
|
3502
|
+
*/
|
|
3503
|
+
export function return_value_body_to_expression(body_nodes, source_node, transform_context) {
|
|
3504
|
+
if (!body_contains_top_level_return_value(body_nodes)) return null;
|
|
3505
|
+
|
|
3506
|
+
if (body_nodes.length === 1) {
|
|
3507
|
+
const expression = return_value_statement_to_expression(body_nodes[0], transform_context);
|
|
3508
|
+
if (expression) return expression;
|
|
3509
|
+
}
|
|
3510
|
+
|
|
3511
|
+
return create_statement_iife(body_nodes, source_node, transform_context);
|
|
3512
|
+
}
|
|
3513
|
+
|
|
3514
|
+
/**
|
|
3515
|
+
* @param {any} node
|
|
3516
|
+
* @param {TransformContext} [transform_context]
|
|
3517
|
+
* @returns {any | null}
|
|
3518
|
+
*/
|
|
3519
|
+
function return_value_statement_to_expression(node, transform_context) {
|
|
3520
|
+
if (node?.type === 'ReturnStatement' && node.argument != null) {
|
|
3521
|
+
return node.argument;
|
|
3522
|
+
}
|
|
3523
|
+
|
|
3524
|
+
if (node?.type === 'IfStatement') {
|
|
3525
|
+
return return_value_if_statement_to_conditional_expression(node, transform_context);
|
|
3526
|
+
}
|
|
3527
|
+
|
|
3528
|
+
return null;
|
|
3529
|
+
}
|
|
3530
|
+
|
|
3531
|
+
/**
|
|
3532
|
+
* @param {any} node
|
|
3533
|
+
* @returns {boolean}
|
|
3534
|
+
*/
|
|
3535
|
+
function body_contains_top_level_return_value(node) {
|
|
3536
|
+
if (!node || typeof node !== 'object') return false;
|
|
3537
|
+
|
|
3538
|
+
if (Array.isArray(node)) {
|
|
3539
|
+
return node.some(body_contains_top_level_return_value);
|
|
3540
|
+
}
|
|
3541
|
+
|
|
3542
|
+
if (node.type === 'ReturnStatement') {
|
|
3543
|
+
return node.argument != null;
|
|
3544
|
+
}
|
|
3545
|
+
|
|
3546
|
+
if (
|
|
3547
|
+
node.type === 'FunctionDeclaration' ||
|
|
3548
|
+
node.type === 'FunctionExpression' ||
|
|
3549
|
+
node.type === 'ArrowFunctionExpression' ||
|
|
3550
|
+
node.type === 'ClassDeclaration' ||
|
|
3551
|
+
node.type === 'ClassExpression' ||
|
|
3552
|
+
node.type === 'Component'
|
|
3553
|
+
) {
|
|
3554
|
+
return false;
|
|
3555
|
+
}
|
|
3556
|
+
|
|
3557
|
+
for (const key of Object.keys(node)) {
|
|
3558
|
+
if (key === 'loc' || key === 'start' || key === 'end' || key === 'metadata') {
|
|
3559
|
+
continue;
|
|
3560
|
+
}
|
|
3561
|
+
if (body_contains_top_level_return_value(node[key])) {
|
|
3562
|
+
return true;
|
|
3563
|
+
}
|
|
3564
|
+
}
|
|
3565
|
+
|
|
3566
|
+
return false;
|
|
3567
|
+
}
|
|
3568
|
+
|
|
3569
|
+
/**
|
|
3570
|
+
* @param {any[]} body_nodes
|
|
3571
|
+
* @param {any} source_node
|
|
3572
|
+
* @param {TransformContext} [transform_context]
|
|
3573
|
+
* @returns {any}
|
|
3574
|
+
*/
|
|
3575
|
+
function create_statement_iife(body_nodes, source_node, transform_context) {
|
|
3576
|
+
return set_generated_expression_loc(
|
|
3577
|
+
b.call(b.arrow([], b.block(body_nodes))),
|
|
3578
|
+
source_node,
|
|
3579
|
+
transform_context,
|
|
3580
|
+
);
|
|
3581
|
+
}
|
|
3582
|
+
|
|
3583
|
+
/**
|
|
3584
|
+
* @param {any} node
|
|
3585
|
+
* @param {any} source_node
|
|
3586
|
+
* @param {TransformContext} [transform_context]
|
|
3587
|
+
* @returns {any}
|
|
3588
|
+
*/
|
|
3589
|
+
function set_generated_expression_loc(node, source_node, transform_context) {
|
|
3590
|
+
if (transform_context?.typeOnly || !source_node?.loc) return node;
|
|
3591
|
+
return setLocation(/** @type {any} */ (node), source_node);
|
|
3592
|
+
}
|
|
3593
|
+
|
|
3594
|
+
/**
|
|
3595
|
+
* @returns {any}
|
|
3596
|
+
*/
|
|
3597
|
+
function create_undefined_expression() {
|
|
3598
|
+
return b.unary('void', b.literal(0));
|
|
3599
|
+
}
|
|
3600
|
+
|
|
3601
|
+
/**
|
|
3602
|
+
* @param {any} node
|
|
3603
|
+
* @param {TransformContext} [transform_context]
|
|
3604
|
+
* @returns {any | null}
|
|
3605
|
+
*/
|
|
3606
|
+
function return_value_block_to_expression(node, transform_context) {
|
|
3607
|
+
const body = node?.type === 'BlockStatement' ? node.body : node ? [node] : [];
|
|
3608
|
+
if (body.length !== 1) return null;
|
|
3609
|
+
|
|
3610
|
+
return return_value_statement_to_expression(body[0], transform_context);
|
|
3611
|
+
}
|
|
3612
|
+
|
|
3613
|
+
/**
|
|
3614
|
+
* @param {any} node
|
|
3615
|
+
* @param {TransformContext} [transform_context]
|
|
3616
|
+
* @returns {any | null}
|
|
3617
|
+
*/
|
|
3618
|
+
function return_value_if_statement_to_conditional_expression(node, transform_context) {
|
|
3619
|
+
if (!node || node.type !== 'IfStatement') return null;
|
|
3620
|
+
|
|
3621
|
+
const consequent = return_value_block_to_expression(node.consequent, transform_context);
|
|
3622
|
+
if (!consequent) return null;
|
|
3623
|
+
|
|
3624
|
+
let alternate = create_undefined_expression();
|
|
3625
|
+
if (node.alternate) {
|
|
3626
|
+
alternate = return_value_block_to_expression(node.alternate, transform_context);
|
|
3627
|
+
if (!alternate) return null;
|
|
3628
|
+
}
|
|
3629
|
+
|
|
3630
|
+
return set_generated_expression_loc(
|
|
3631
|
+
b.conditional(node.test, consequent, alternate),
|
|
3632
|
+
node,
|
|
3633
|
+
transform_context,
|
|
3634
|
+
);
|
|
3635
|
+
}
|
|
3636
|
+
|
|
3482
3637
|
/**
|
|
3483
3638
|
* @param {any} node
|
|
3484
3639
|
* @param {TransformContext} transform_context
|
|
@@ -4009,7 +4164,7 @@ function try_statement_to_jsx_child(node, transform_context) {
|
|
|
4009
4164
|
);
|
|
4010
4165
|
}
|
|
4011
4166
|
const pending_body = pending.body || [];
|
|
4012
|
-
if (!pending_body.some(is_jsx_child)) {
|
|
4167
|
+
if (pending_body.length > 0 && !pending_body.some(is_jsx_child)) {
|
|
4013
4168
|
error(
|
|
4014
4169
|
'Component try statements must contain a template in their "pending" body. Rendering a pending fallback is required to have a template.',
|
|
4015
4170
|
transform_context.filename,
|
|
@@ -4031,7 +4186,10 @@ function try_statement_to_jsx_child(node, transform_context) {
|
|
|
4031
4186
|
if (pending) {
|
|
4032
4187
|
transform_context.needs_suspense = true;
|
|
4033
4188
|
const pending_body_nodes = pending.body || [];
|
|
4034
|
-
const fallback_content =
|
|
4189
|
+
const fallback_content =
|
|
4190
|
+
pending_body_nodes.length === 0
|
|
4191
|
+
? to_jsx_expression_container(create_null_literal())
|
|
4192
|
+
: statement_body_to_jsx_child(pending_body_nodes, transform_context);
|
|
4035
4193
|
|
|
4036
4194
|
result = create_jsx_element(
|
|
4037
4195
|
'Suspense',
|