@tsrx/core 0.1.1 → 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 +182 -2
- 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
|
@@ -202,6 +202,7 @@ export function TSRXPlugin(config) {
|
|
|
202
202
|
// Some parser constructors (e.g. via TS plugins) expose `tokContexts` without `b_stat`.
|
|
203
203
|
// If we push an undefined context, Acorn's tokenizer will later crash reading `.override`.
|
|
204
204
|
const b_stat = tc.b_stat || acorn.tokContexts.b_stat;
|
|
205
|
+
const b_expr = tc.b_expr || acorn.tokContexts.b_expr;
|
|
205
206
|
const tstt = Parser.acornTypeScript.tokTypes;
|
|
206
207
|
const tstc = Parser.acornTypeScript.tokContexts;
|
|
207
208
|
|
|
@@ -219,6 +220,7 @@ export function TSRXPlugin(config) {
|
|
|
219
220
|
#errors = undefined;
|
|
220
221
|
/** @type {string | null} */
|
|
221
222
|
#filename = null;
|
|
223
|
+
#componentDepth = 0;
|
|
222
224
|
#functionBodyDepth = 0;
|
|
223
225
|
|
|
224
226
|
/**
|
|
@@ -269,6 +271,14 @@ export function TSRXPlugin(config) {
|
|
|
269
271
|
return null;
|
|
270
272
|
}
|
|
271
273
|
|
|
274
|
+
#isInsideComponent() {
|
|
275
|
+
return this.#componentDepth > 0;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
#isInsideComponentTemplate() {
|
|
279
|
+
return this.#isInsideComponent() && this.#functionBodyDepth === 0;
|
|
280
|
+
}
|
|
281
|
+
|
|
272
282
|
#popTsxTokenContextBeforeTemplateExpressionChild() {
|
|
273
283
|
let index = this.pos;
|
|
274
284
|
let has_newline = false;
|
|
@@ -319,6 +329,137 @@ export function TSRXPlugin(config) {
|
|
|
319
329
|
}
|
|
320
330
|
}
|
|
321
331
|
|
|
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
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return index;
|
|
356
|
+
}
|
|
357
|
+
|
|
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.
|
|
451
|
+
if (
|
|
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 === '[')
|
|
457
|
+
) {
|
|
458
|
+
ctx.pop();
|
|
459
|
+
this.exprAllowed = false;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
322
463
|
#isDoubleQuotedTextChildStart() {
|
|
323
464
|
if (this.#path.findLast((n) => n.type === 'TsxCompat' || n.type === 'Tsx')) {
|
|
324
465
|
return false;
|
|
@@ -717,7 +858,7 @@ export function TSRXPlugin(config) {
|
|
|
717
858
|
|
|
718
859
|
if (code === 60) {
|
|
719
860
|
// < character
|
|
720
|
-
const inComponent = this.#
|
|
861
|
+
const inComponent = this.#isInsideComponentTemplate();
|
|
721
862
|
/** @type {number | null} */
|
|
722
863
|
let prevNonWhitespaceChar = null;
|
|
723
864
|
|
|
@@ -1073,11 +1214,13 @@ export function TSRXPlugin(config) {
|
|
|
1073
1214
|
this.eat(tt.braceL);
|
|
1074
1215
|
node.body = [];
|
|
1075
1216
|
this.#path.push(node);
|
|
1217
|
+
this.#componentDepth++;
|
|
1076
1218
|
|
|
1077
1219
|
try {
|
|
1078
1220
|
this.parseTemplateBody(node.body);
|
|
1079
1221
|
} finally {
|
|
1080
1222
|
this.#functionBodyDepth = parent_function_body_depth;
|
|
1223
|
+
this.#componentDepth--;
|
|
1081
1224
|
}
|
|
1082
1225
|
this.#path.pop();
|
|
1083
1226
|
this.exitScope();
|
|
@@ -1301,6 +1444,23 @@ export function TSRXPlugin(config) {
|
|
|
1301
1444
|
parseFunctionBody(node, isArrowFunction, isMethod, forInit, ...args) {
|
|
1302
1445
|
this.#functionBodyDepth++;
|
|
1303
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
|
+
}
|
|
1304
1464
|
|
|
1305
1465
|
try {
|
|
1306
1466
|
return super.parseFunctionBody(node, isArrowFunction, isMethod, forInit, ...args);
|
|
@@ -1910,9 +2070,20 @@ export function TSRXPlugin(config) {
|
|
|
1910
2070
|
// Use Ripple's parseElement to create a Tsx/Tsrx/TsxCompat node.
|
|
1911
2071
|
// Bare fragments (<></>) are shorthand for <tsx>...</tsx>.
|
|
1912
2072
|
this.next();
|
|
1913
|
-
|
|
2073
|
+
const parsed = /** @type {import('estree-jsx').JSXElement} */ (
|
|
1914
2074
|
/** @type {unknown} */ (this.parseElement())
|
|
1915
2075
|
);
|
|
2076
|
+
this.#popTokenContextsAfterTemplateExpressionElement(
|
|
2077
|
+
/** @type {AST.Tsx | AST.Tsrx | AST.TsxCompat} */ (/** @type {unknown} */ (parsed)),
|
|
2078
|
+
);
|
|
2079
|
+
return parsed;
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
if (
|
|
2083
|
+
!this.#path.findLast((node) => node.type === 'Component') &&
|
|
2084
|
+
!this.#functionStack.findLast(is_pascal_case_function)
|
|
2085
|
+
) {
|
|
2086
|
+
return super.jsx_parseElement();
|
|
1916
2087
|
}
|
|
1917
2088
|
|
|
1918
2089
|
const code = this.#functionStack.findLast(is_pascal_case_function)
|
|
@@ -2828,6 +2999,15 @@ export function TSRXPlugin(config) {
|
|
|
2828
2999
|
if (!node) {
|
|
2829
3000
|
this.unexpected();
|
|
2830
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
|
+
}
|
|
2831
3011
|
return node;
|
|
2832
3012
|
}
|
|
2833
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',
|