@tsrx/core 0.0.27 → 0.1.0
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 +5 -4
- package/src/index.js +6 -0
- package/src/plugin.js +131 -25
- package/src/runtime/language-helpers.js +57 -0
- package/src/runtime/ref.js +250 -0
- package/src/scope.js +7 -0
- package/src/transform/jsx/ast-builders.js +14 -13
- package/src/transform/jsx/index.js +490 -55
- package/src/transform/segments.js +19 -9
- package/types/index.d.ts +20 -1
- package/types/jsx-platform.d.ts +14 -1
- package/types/parse.d.ts +1 -1
- package/types/runtime/ref.d.ts +32 -0
- package/src/runtime/merge-refs.js +0 -61
- package/types/runtime/merge-refs.d.ts +0 -12
|
@@ -169,6 +169,8 @@ export function createJsxTransform(platform) {
|
|
|
169
169
|
needs_error_boundary: false,
|
|
170
170
|
needs_suspense: false,
|
|
171
171
|
needs_merge_refs: false,
|
|
172
|
+
needs_ref_prop: false,
|
|
173
|
+
needs_normalize_spread_props: false,
|
|
172
174
|
needs_fragment: false,
|
|
173
175
|
module_scoped_hook_components:
|
|
174
176
|
options?.moduleScopedHookComponents ?? !!platform.hooks?.moduleScopedHookComponents,
|
|
@@ -382,13 +384,31 @@ export function createJsxTransform(platform) {
|
|
|
382
384
|
|
|
383
385
|
Tsx(node, { next, path }) {
|
|
384
386
|
const inner = /** @type {any} */ (next() ?? node);
|
|
385
|
-
|
|
387
|
+
const in_jsx_child = in_jsx_child_context(path);
|
|
388
|
+
return /** @type {any} */ (
|
|
389
|
+
wrap_jsx_setup_declarations(tsx_node_to_jsx_expression(inner, in_jsx_child), in_jsx_child)
|
|
390
|
+
);
|
|
391
|
+
},
|
|
392
|
+
|
|
393
|
+
Tsrx(node, { next, path, state }) {
|
|
394
|
+
const inner = /** @type {any} */ (next() ?? node);
|
|
395
|
+
const in_jsx_child = in_jsx_child_context(path);
|
|
396
|
+
return /** @type {any} */ (
|
|
397
|
+
wrap_jsx_setup_declarations(
|
|
398
|
+
tsrx_node_to_jsx_expression(inner, state, in_jsx_child),
|
|
399
|
+
in_jsx_child,
|
|
400
|
+
)
|
|
401
|
+
);
|
|
386
402
|
},
|
|
387
403
|
|
|
388
404
|
TsxCompat(node, { next, path, state }) {
|
|
389
405
|
const inner = /** @type {any} */ (next() ?? node);
|
|
406
|
+
const in_jsx_child = in_jsx_child_context(path);
|
|
390
407
|
return /** @type {any} */ (
|
|
391
|
-
|
|
408
|
+
wrap_jsx_setup_declarations(
|
|
409
|
+
tsx_compat_node_to_jsx_expression(inner, state, in_jsx_child),
|
|
410
|
+
in_jsx_child,
|
|
411
|
+
)
|
|
392
412
|
);
|
|
393
413
|
},
|
|
394
414
|
|
|
@@ -432,6 +452,27 @@ export function createJsxTransform(platform) {
|
|
|
432
452
|
FunctionDeclaration: ensure_function_metadata,
|
|
433
453
|
FunctionExpression: ensure_function_metadata,
|
|
434
454
|
ArrowFunctionExpression: ensure_function_metadata,
|
|
455
|
+
|
|
456
|
+
RefExpression(node) {
|
|
457
|
+
return create_ref_prop_call(node, transform_context);
|
|
458
|
+
},
|
|
459
|
+
|
|
460
|
+
JSXOpeningElement(node, { next }) {
|
|
461
|
+
const visited = next() || node;
|
|
462
|
+
const is_component = is_component_like_jsx_name(visited.name);
|
|
463
|
+
const attrs = normalize_named_ref_attributes(
|
|
464
|
+
visited.attributes || [],
|
|
465
|
+
!is_component,
|
|
466
|
+
transform_context,
|
|
467
|
+
);
|
|
468
|
+
return {
|
|
469
|
+
...visited,
|
|
470
|
+
attributes: merge_duplicate_refs(
|
|
471
|
+
normalize_host_ref_spreads(attrs, !is_component, transform_context),
|
|
472
|
+
transform_context,
|
|
473
|
+
),
|
|
474
|
+
};
|
|
475
|
+
},
|
|
435
476
|
});
|
|
436
477
|
|
|
437
478
|
const expanded = expand_component_helpers(/** @type {AST.Program} */ (transformed));
|
|
@@ -906,6 +947,7 @@ function build_render_statements(body_nodes, return_null_when_empty, transform_c
|
|
|
906
947
|
|
|
907
948
|
if (is_jsx_child(child)) {
|
|
908
949
|
const jsx = to_jsx_child(child, transform_context);
|
|
950
|
+
statements.push(...extract_jsx_setup_declarations(jsx));
|
|
909
951
|
if (interleaved && is_capturable_jsx_child(jsx)) {
|
|
910
952
|
const { declaration, reference } = captureJsxChild(jsx, capture_index++);
|
|
911
953
|
statements.push(declaration);
|
|
@@ -1576,9 +1618,7 @@ function create_component_return_statement(
|
|
|
1576
1618
|
map_render_node_locations = true,
|
|
1577
1619
|
) {
|
|
1578
1620
|
const cloned = render_nodes.map((node) =>
|
|
1579
|
-
map_render_node_locations
|
|
1580
|
-
? clone_expression_node(node)
|
|
1581
|
-
: clone_expression_node_without_locations(node),
|
|
1621
|
+
map_render_node_locations ? clone_expression_node(node) : clone_expression_node(node, false),
|
|
1582
1622
|
);
|
|
1583
1623
|
|
|
1584
1624
|
return set_loc(b.return(build_return_expression(cloned) || create_null_literal()), source_node);
|
|
@@ -1645,7 +1685,7 @@ function build_tail_helper(continuation_body, source_node, transform_context) {
|
|
|
1645
1685
|
* @returns {any}
|
|
1646
1686
|
*/
|
|
1647
1687
|
function clone_tail_invocation(tail_helper) {
|
|
1648
|
-
return
|
|
1688
|
+
return clone_expression_node(tail_helper.component_element, false);
|
|
1649
1689
|
}
|
|
1650
1690
|
|
|
1651
1691
|
/**
|
|
@@ -2553,7 +2593,7 @@ function prepend_render_nodes_to_return_statement(node, render_nodes, inside_nes
|
|
|
2553
2593
|
* @returns {any}
|
|
2554
2594
|
*/
|
|
2555
2595
|
function combine_render_return_argument(render_nodes, return_argument) {
|
|
2556
|
-
const combined = render_nodes.map((node) =>
|
|
2596
|
+
const combined = render_nodes.map((node) => clone_expression_node(node, false));
|
|
2557
2597
|
|
|
2558
2598
|
if (return_argument != null && !is_null_literal(return_argument)) {
|
|
2559
2599
|
combined.push(return_argument_to_render_node(return_argument));
|
|
@@ -2586,30 +2626,6 @@ function is_null_literal(node) {
|
|
|
2586
2626
|
return node?.type === 'Literal' && node.value == null;
|
|
2587
2627
|
}
|
|
2588
2628
|
|
|
2589
|
-
/**
|
|
2590
|
-
* @param {any} node
|
|
2591
|
-
* @returns {any}
|
|
2592
|
-
*/
|
|
2593
|
-
function clone_expression_node_without_locations(node) {
|
|
2594
|
-
if (!node || typeof node !== 'object') return node;
|
|
2595
|
-
if (Array.isArray(node)) return node.map(clone_expression_node_without_locations);
|
|
2596
|
-
|
|
2597
|
-
const clone = { ...node };
|
|
2598
|
-
delete clone.loc;
|
|
2599
|
-
delete clone.start;
|
|
2600
|
-
delete clone.end;
|
|
2601
|
-
|
|
2602
|
-
for (const key of Object.keys(clone)) {
|
|
2603
|
-
if (key === 'metadata') {
|
|
2604
|
-
clone.metadata = clone.metadata ? { ...clone.metadata } : { path: [] };
|
|
2605
|
-
continue;
|
|
2606
|
-
}
|
|
2607
|
-
clone[key] = clone_expression_node_without_locations(clone[key]);
|
|
2608
|
-
}
|
|
2609
|
-
|
|
2610
|
-
return clone;
|
|
2611
|
-
}
|
|
2612
|
-
|
|
2613
2629
|
const TEMPLATE_FRAGMENT_ERROR =
|
|
2614
2630
|
'JSX fragment syntax is not needed in TSRX templates. TSRX renders in immediate mode, so everything is already a fragment. Use `<>...</>` only within <tsx>...</tsx>.';
|
|
2615
2631
|
|
|
@@ -3374,6 +3390,8 @@ function to_jsx_child(node, transform_context) {
|
|
|
3374
3390
|
// We're inside a JSX child position by construction, so keep a
|
|
3375
3391
|
// JSXExpressionContainer wrapper for bare `{expr}` children.
|
|
3376
3392
|
return tsx_node_to_jsx_expression(node, true);
|
|
3393
|
+
case 'Tsrx':
|
|
3394
|
+
return tsrx_node_to_jsx_expression(node, transform_context, true);
|
|
3377
3395
|
case 'TsxCompat':
|
|
3378
3396
|
return tsx_compat_node_to_jsx_expression(node, transform_context, true);
|
|
3379
3397
|
case 'Element':
|
|
@@ -3408,6 +3426,59 @@ function to_jsx_child(node, transform_context) {
|
|
|
3408
3426
|
}
|
|
3409
3427
|
}
|
|
3410
3428
|
|
|
3429
|
+
/**
|
|
3430
|
+
* Lower a `<tsrx>` node's native TSRX template body to a JSX expression.
|
|
3431
|
+
* Unlike `<tsx>`, children have already been parsed and transformed through
|
|
3432
|
+
* the normal TSRX Element/Text/control-flow visitors.
|
|
3433
|
+
*
|
|
3434
|
+
* @param {any} node
|
|
3435
|
+
* @param {TransformContext} transform_context
|
|
3436
|
+
* @param {boolean} [in_jsx_child]
|
|
3437
|
+
* @returns {any}
|
|
3438
|
+
*/
|
|
3439
|
+
function tsrx_node_to_jsx_expression(node, transform_context, in_jsx_child = false) {
|
|
3440
|
+
const children = (node.children || []).filter(
|
|
3441
|
+
(/** @type {any} */ child) =>
|
|
3442
|
+
child &&
|
|
3443
|
+
child.type !== 'EmptyStatement' &&
|
|
3444
|
+
(child.type !== 'JSXText' || child.value.trim() !== ''),
|
|
3445
|
+
);
|
|
3446
|
+
|
|
3447
|
+
/** @type {any} */
|
|
3448
|
+
let expression;
|
|
3449
|
+
if (children.length === 0) {
|
|
3450
|
+
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
|
+
} else {
|
|
3466
|
+
expression = statement_body_to_jsx_child(children, transform_context).expression;
|
|
3467
|
+
}
|
|
3468
|
+
|
|
3469
|
+
if (
|
|
3470
|
+
in_jsx_child &&
|
|
3471
|
+
expression.type !== 'JSXElement' &&
|
|
3472
|
+
expression.type !== 'JSXFragment' &&
|
|
3473
|
+
expression.type !== 'JSXText' &&
|
|
3474
|
+
expression.type !== 'JSXExpressionContainer'
|
|
3475
|
+
) {
|
|
3476
|
+
return to_jsx_expression_container(expression, node);
|
|
3477
|
+
}
|
|
3478
|
+
|
|
3479
|
+
return expression;
|
|
3480
|
+
}
|
|
3481
|
+
|
|
3411
3482
|
/**
|
|
3412
3483
|
* @param {any} node
|
|
3413
3484
|
* @param {TransformContext} transform_context
|
|
@@ -4201,30 +4272,79 @@ function inject_try_imports(program, transform_context, platform, suspense_sourc
|
|
|
4201
4272
|
});
|
|
4202
4273
|
}
|
|
4203
4274
|
|
|
4204
|
-
|
|
4205
|
-
|
|
4275
|
+
const merge_refs_source =
|
|
4276
|
+
transform_context.needs_merge_refs && platform.imports.mergeRefs
|
|
4277
|
+
? platform.imports.mergeRefs
|
|
4278
|
+
: null;
|
|
4279
|
+
const ref_prop_source =
|
|
4280
|
+
transform_context.needs_ref_prop && platform.imports.refProp ? platform.imports.refProp : null;
|
|
4281
|
+
const normalize_spread_props_source =
|
|
4282
|
+
transform_context.needs_normalize_spread_props && platform.imports.refProp
|
|
4283
|
+
? platform.imports.refProp
|
|
4284
|
+
: null;
|
|
4285
|
+
|
|
4286
|
+
/** @type {Map<string, any[]>} */
|
|
4287
|
+
const ref_imports = new Map();
|
|
4288
|
+
|
|
4289
|
+
if (merge_refs_source !== null) {
|
|
4290
|
+
add_ref_import_specifier(ref_imports, merge_refs_source, {
|
|
4291
|
+
type: 'ImportSpecifier',
|
|
4292
|
+
imported: {
|
|
4293
|
+
type: 'Identifier',
|
|
4294
|
+
name: 'mergeRefs',
|
|
4295
|
+
metadata: { path: [] },
|
|
4296
|
+
},
|
|
4297
|
+
local: {
|
|
4298
|
+
type: 'Identifier',
|
|
4299
|
+
name: MERGE_REFS_INTERNAL_NAME,
|
|
4300
|
+
metadata: { path: [] },
|
|
4301
|
+
},
|
|
4302
|
+
metadata: { path: [] },
|
|
4303
|
+
});
|
|
4304
|
+
}
|
|
4305
|
+
|
|
4306
|
+
if (ref_prop_source !== null) {
|
|
4307
|
+
add_ref_import_specifier(ref_imports, ref_prop_source, {
|
|
4308
|
+
type: 'ImportSpecifier',
|
|
4309
|
+
imported: {
|
|
4310
|
+
type: 'Identifier',
|
|
4311
|
+
name: 'create_ref_prop',
|
|
4312
|
+
metadata: { path: [] },
|
|
4313
|
+
},
|
|
4314
|
+
local: {
|
|
4315
|
+
type: 'Identifier',
|
|
4316
|
+
name: CREATE_REF_PROP_INTERNAL_NAME,
|
|
4317
|
+
metadata: { path: [] },
|
|
4318
|
+
},
|
|
4319
|
+
metadata: { path: [] },
|
|
4320
|
+
});
|
|
4321
|
+
}
|
|
4322
|
+
|
|
4323
|
+
if (normalize_spread_props_source !== null) {
|
|
4324
|
+
add_ref_import_specifier(ref_imports, normalize_spread_props_source, {
|
|
4325
|
+
type: 'ImportSpecifier',
|
|
4326
|
+
imported: {
|
|
4327
|
+
type: 'Identifier',
|
|
4328
|
+
name: 'normalize_spread_props',
|
|
4329
|
+
metadata: { path: [] },
|
|
4330
|
+
},
|
|
4331
|
+
local: {
|
|
4332
|
+
type: 'Identifier',
|
|
4333
|
+
name: NORMALIZE_SPREAD_PROPS_INTERNAL_NAME,
|
|
4334
|
+
metadata: { path: [] },
|
|
4335
|
+
},
|
|
4336
|
+
metadata: { path: [] },
|
|
4337
|
+
});
|
|
4338
|
+
}
|
|
4339
|
+
|
|
4340
|
+
for (const [source, ref_specifiers] of ref_imports) {
|
|
4206
4341
|
imports.push({
|
|
4207
4342
|
type: 'ImportDeclaration',
|
|
4208
|
-
specifiers:
|
|
4209
|
-
{
|
|
4210
|
-
type: 'ImportSpecifier',
|
|
4211
|
-
imported: {
|
|
4212
|
-
type: 'Identifier',
|
|
4213
|
-
name: 'mergeRefs',
|
|
4214
|
-
metadata: { path: [] },
|
|
4215
|
-
},
|
|
4216
|
-
local: {
|
|
4217
|
-
type: 'Identifier',
|
|
4218
|
-
name: MERGE_REFS_LOCAL_NAME,
|
|
4219
|
-
metadata: { path: [] },
|
|
4220
|
-
},
|
|
4221
|
-
metadata: { path: [] },
|
|
4222
|
-
},
|
|
4223
|
-
],
|
|
4343
|
+
specifiers: ref_specifiers,
|
|
4224
4344
|
source: {
|
|
4225
4345
|
type: 'Literal',
|
|
4226
|
-
value:
|
|
4227
|
-
raw: `'${
|
|
4346
|
+
value: source,
|
|
4347
|
+
raw: `'${source}'`,
|
|
4228
4348
|
},
|
|
4229
4349
|
metadata: { path: [] },
|
|
4230
4350
|
});
|
|
@@ -4235,6 +4355,20 @@ function inject_try_imports(program, transform_context, platform, suspense_sourc
|
|
|
4235
4355
|
}
|
|
4236
4356
|
}
|
|
4237
4357
|
|
|
4358
|
+
/**
|
|
4359
|
+
* @param {Map<string, any[]>} imports
|
|
4360
|
+
* @param {string} source
|
|
4361
|
+
* @param {any} specifier
|
|
4362
|
+
*/
|
|
4363
|
+
function add_ref_import_specifier(imports, source, specifier) {
|
|
4364
|
+
const specifiers = imports.get(source);
|
|
4365
|
+
if (specifiers) {
|
|
4366
|
+
specifiers.push(specifier);
|
|
4367
|
+
} else {
|
|
4368
|
+
imports.set(source, [specifier]);
|
|
4369
|
+
}
|
|
4370
|
+
}
|
|
4371
|
+
|
|
4238
4372
|
/**
|
|
4239
4373
|
* @param {any} node
|
|
4240
4374
|
* @param {TransformContext} transform_context
|
|
@@ -4421,6 +4555,8 @@ function to_jsx_expression_container(expression, source_node = expression) {
|
|
|
4421
4555
|
*/
|
|
4422
4556
|
function transform_element_attributes_dispatch(attrs, transform_context, element) {
|
|
4423
4557
|
validate_at_most_one_ref_attribute(attrs, transform_context);
|
|
4558
|
+
const is_component = is_component_like_element(element);
|
|
4559
|
+
attrs = normalize_named_ref_attributes(attrs, !is_component, transform_context);
|
|
4424
4560
|
const preprocess = transform_context.platform.hooks?.preprocessElementAttributes;
|
|
4425
4561
|
if (preprocess) {
|
|
4426
4562
|
attrs = preprocess(attrs, transform_context, element);
|
|
@@ -4429,7 +4565,238 @@ function transform_element_attributes_dispatch(attrs, transform_context, element
|
|
|
4429
4565
|
const result = hook
|
|
4430
4566
|
? hook(attrs, transform_context, element)
|
|
4431
4567
|
: attrs.map((/** @type {any} */ a) => to_jsx_attribute(a, transform_context));
|
|
4432
|
-
return merge_duplicate_refs(
|
|
4568
|
+
return merge_duplicate_refs(
|
|
4569
|
+
normalize_host_ref_spreads(result, !is_component, transform_context),
|
|
4570
|
+
transform_context,
|
|
4571
|
+
);
|
|
4572
|
+
}
|
|
4573
|
+
|
|
4574
|
+
/**
|
|
4575
|
+
* @param {any} element
|
|
4576
|
+
* @returns {boolean}
|
|
4577
|
+
*/
|
|
4578
|
+
function is_component_like_element(element) {
|
|
4579
|
+
const id = element?.id;
|
|
4580
|
+
if (!id) return false;
|
|
4581
|
+
if (id.type === 'Identifier') return /^[A-Z]/.test(id.name);
|
|
4582
|
+
if (id.type === 'JSXIdentifier') return /^[A-Z]/.test(id.name);
|
|
4583
|
+
if (id.type === 'MemberExpression') return true;
|
|
4584
|
+
if (id.type === 'JSXMemberExpression') return true;
|
|
4585
|
+
return false;
|
|
4586
|
+
}
|
|
4587
|
+
|
|
4588
|
+
/**
|
|
4589
|
+
* @param {any} name
|
|
4590
|
+
* @returns {boolean}
|
|
4591
|
+
*/
|
|
4592
|
+
function is_component_like_jsx_name(name) {
|
|
4593
|
+
if (!name) return false;
|
|
4594
|
+
if (name.type === 'JSXIdentifier') return /^[A-Z]/.test(name.name);
|
|
4595
|
+
if (name.type === 'JSXMemberExpression') return true;
|
|
4596
|
+
return false;
|
|
4597
|
+
}
|
|
4598
|
+
|
|
4599
|
+
/**
|
|
4600
|
+
* @param {any[]} attrs
|
|
4601
|
+
* @param {boolean} is_host
|
|
4602
|
+
* @param {TransformContext} transform_context
|
|
4603
|
+
* @returns {any[]}
|
|
4604
|
+
*/
|
|
4605
|
+
function normalize_named_ref_attributes(attrs, is_host, transform_context) {
|
|
4606
|
+
if (!is_host) return attrs;
|
|
4607
|
+
|
|
4608
|
+
return attrs.map((attr) => {
|
|
4609
|
+
if (!is_named_ref_attribute(attr)) {
|
|
4610
|
+
return attr;
|
|
4611
|
+
}
|
|
4612
|
+
|
|
4613
|
+
if (transform_context.typeOnly) {
|
|
4614
|
+
return mark_type_only_named_ref_attribute(attr);
|
|
4615
|
+
}
|
|
4616
|
+
|
|
4617
|
+
return {
|
|
4618
|
+
...attr,
|
|
4619
|
+
metadata: { ...(attr.metadata || {}), from_ref_keyword: true },
|
|
4620
|
+
name:
|
|
4621
|
+
attr.name?.type === 'JSXIdentifier'
|
|
4622
|
+
? { ...attr.name, name: 'ref' }
|
|
4623
|
+
: { type: 'Identifier', name: 'ref', metadata: { path: [] } },
|
|
4624
|
+
};
|
|
4625
|
+
});
|
|
4626
|
+
}
|
|
4627
|
+
|
|
4628
|
+
/**
|
|
4629
|
+
* @param {any} attr
|
|
4630
|
+
* @returns {any}
|
|
4631
|
+
*/
|
|
4632
|
+
function mark_type_only_named_ref_attribute(attr) {
|
|
4633
|
+
return {
|
|
4634
|
+
...attr,
|
|
4635
|
+
name: attr.name
|
|
4636
|
+
? {
|
|
4637
|
+
...attr.name,
|
|
4638
|
+
metadata: { ...(attr.name.metadata || {}), disable_verification: true },
|
|
4639
|
+
}
|
|
4640
|
+
: attr.name,
|
|
4641
|
+
};
|
|
4642
|
+
}
|
|
4643
|
+
|
|
4644
|
+
/**
|
|
4645
|
+
* @param {any[]} attrs
|
|
4646
|
+
* @param {boolean} is_host
|
|
4647
|
+
* @param {TransformContext} transform_context
|
|
4648
|
+
* @returns {any[]}
|
|
4649
|
+
*/
|
|
4650
|
+
function normalize_host_ref_spreads(attrs, is_host, transform_context) {
|
|
4651
|
+
if (!is_host) return attrs;
|
|
4652
|
+
|
|
4653
|
+
const needs_explicit_spread_ref =
|
|
4654
|
+
transform_context.platform.jsx?.hostSpreadRefStrategy === 'explicit-ref-attr';
|
|
4655
|
+
const ref_exprs = attrs
|
|
4656
|
+
.filter((attr) => is_jsx_ref_attribute(attr))
|
|
4657
|
+
.map((attr) => attr.value.expression);
|
|
4658
|
+
const needs_synthetic_spread_ref = needs_explicit_spread_ref || ref_exprs.length > 0;
|
|
4659
|
+
|
|
4660
|
+
return attrs.flatMap((attr) => {
|
|
4661
|
+
if (!attr || attr.type !== 'JSXSpreadAttribute') {
|
|
4662
|
+
return [attr];
|
|
4663
|
+
}
|
|
4664
|
+
|
|
4665
|
+
transform_context.needs_normalize_spread_props = true;
|
|
4666
|
+
const normalized = b.call(NORMALIZE_SPREAD_PROPS_INTERNAL_NAME, attr.argument);
|
|
4667
|
+
|
|
4668
|
+
if (needs_synthetic_spread_ref) {
|
|
4669
|
+
const normalized_id = create_generated_identifier(
|
|
4670
|
+
create_spread_props_name(transform_context),
|
|
4671
|
+
);
|
|
4672
|
+
const spread = {
|
|
4673
|
+
...attr,
|
|
4674
|
+
argument: clone_identifier(normalized_id),
|
|
4675
|
+
};
|
|
4676
|
+
const ref_attr = b.jsx_attribute(
|
|
4677
|
+
b.jsx_id('ref'),
|
|
4678
|
+
to_jsx_expression_container(b.member(clone_identifier(normalized_id), 'ref'), attr),
|
|
4679
|
+
false,
|
|
4680
|
+
attr,
|
|
4681
|
+
);
|
|
4682
|
+
ref_attr.metadata = { ...(ref_attr.metadata || {}) };
|
|
4683
|
+
/** @type {any} */ (ref_attr.metadata).from_ref_keyword = true;
|
|
4684
|
+
add_jsx_setup_declaration(spread, b.let(clone_identifier(normalized_id), normalized));
|
|
4685
|
+
|
|
4686
|
+
return [spread, ref_attr];
|
|
4687
|
+
}
|
|
4688
|
+
|
|
4689
|
+
return [
|
|
4690
|
+
{
|
|
4691
|
+
...attr,
|
|
4692
|
+
argument: normalized,
|
|
4693
|
+
},
|
|
4694
|
+
];
|
|
4695
|
+
});
|
|
4696
|
+
}
|
|
4697
|
+
|
|
4698
|
+
/**
|
|
4699
|
+
* @param {TransformContext} transform_context
|
|
4700
|
+
* @returns {string}
|
|
4701
|
+
*/
|
|
4702
|
+
function create_spread_props_name(transform_context) {
|
|
4703
|
+
if (transform_context.helper_state) {
|
|
4704
|
+
return create_helper_name(transform_context.helper_state, 'spread_props');
|
|
4705
|
+
}
|
|
4706
|
+
|
|
4707
|
+
transform_context.local_statement_component_index += 1;
|
|
4708
|
+
return `_tsrx_spread_props_${transform_context.local_statement_component_index}`;
|
|
4709
|
+
}
|
|
4710
|
+
|
|
4711
|
+
/**
|
|
4712
|
+
* @param {any} node
|
|
4713
|
+
* @param {any} declaration
|
|
4714
|
+
*/
|
|
4715
|
+
export function add_jsx_setup_declaration(node, declaration) {
|
|
4716
|
+
node.metadata ??= { path: [] };
|
|
4717
|
+
(node.metadata.generated_setup_declarations ??= []).push(declaration);
|
|
4718
|
+
}
|
|
4719
|
+
|
|
4720
|
+
/**
|
|
4721
|
+
* @param {any} node
|
|
4722
|
+
* @param {Set<any>} [seen]
|
|
4723
|
+
* @returns {any[]}
|
|
4724
|
+
*/
|
|
4725
|
+
export function extract_jsx_setup_declarations(node, seen = new Set()) {
|
|
4726
|
+
if (node == null || typeof node !== 'object' || seen.has(node)) {
|
|
4727
|
+
return [];
|
|
4728
|
+
}
|
|
4729
|
+
seen.add(node);
|
|
4730
|
+
|
|
4731
|
+
const declarations = node.metadata?.generated_setup_declarations ?? [];
|
|
4732
|
+
if (node.metadata?.generated_setup_declarations) {
|
|
4733
|
+
delete node.metadata.generated_setup_declarations;
|
|
4734
|
+
}
|
|
4735
|
+
|
|
4736
|
+
for (const key of Object.keys(node)) {
|
|
4737
|
+
if (key === 'loc' || key === 'start' || key === 'end' || key === 'metadata') {
|
|
4738
|
+
continue;
|
|
4739
|
+
}
|
|
4740
|
+
declarations.push(...extract_jsx_setup_declarations(node[key], seen));
|
|
4741
|
+
}
|
|
4742
|
+
|
|
4743
|
+
return declarations;
|
|
4744
|
+
}
|
|
4745
|
+
|
|
4746
|
+
/**
|
|
4747
|
+
* @param {any} expression
|
|
4748
|
+
* @param {boolean} in_jsx_child
|
|
4749
|
+
* @returns {any}
|
|
4750
|
+
*/
|
|
4751
|
+
function wrap_jsx_setup_declarations(expression, in_jsx_child) {
|
|
4752
|
+
const declarations = extract_jsx_setup_declarations(expression);
|
|
4753
|
+
if (declarations.length === 0) {
|
|
4754
|
+
return expression;
|
|
4755
|
+
}
|
|
4756
|
+
|
|
4757
|
+
const return_expression =
|
|
4758
|
+
expression?.type === 'JSXExpressionContainer' ? expression.expression : expression;
|
|
4759
|
+
const call = b.call(
|
|
4760
|
+
b.arrow(
|
|
4761
|
+
[],
|
|
4762
|
+
b.block([...declarations, b.return(return_expression)], expression),
|
|
4763
|
+
false,
|
|
4764
|
+
expression,
|
|
4765
|
+
),
|
|
4766
|
+
);
|
|
4767
|
+
|
|
4768
|
+
return in_jsx_child ? to_jsx_expression_container(call, expression) : call;
|
|
4769
|
+
}
|
|
4770
|
+
|
|
4771
|
+
/**
|
|
4772
|
+
* @param {any} attr
|
|
4773
|
+
* @returns {boolean}
|
|
4774
|
+
*/
|
|
4775
|
+
function is_named_ref_attribute(attr) {
|
|
4776
|
+
return !!(
|
|
4777
|
+
attr &&
|
|
4778
|
+
(attr.type === 'Attribute' || attr.type === 'JSXAttribute') &&
|
|
4779
|
+
attr.name &&
|
|
4780
|
+
((attr.name.type === 'Identifier' && attr.name.name !== 'ref') ||
|
|
4781
|
+
(attr.name.type === 'JSXIdentifier' && attr.name.name !== 'ref')) &&
|
|
4782
|
+
(attr.value?.type === 'RefExpression' ||
|
|
4783
|
+
is_ref_prop_expression(attr.value) ||
|
|
4784
|
+
(attr.value?.type === 'JSXExpressionContainer' &&
|
|
4785
|
+
is_ref_prop_expression(attr.value.expression)))
|
|
4786
|
+
);
|
|
4787
|
+
}
|
|
4788
|
+
|
|
4789
|
+
/**
|
|
4790
|
+
* @param {any} expression
|
|
4791
|
+
* @returns {boolean}
|
|
4792
|
+
*/
|
|
4793
|
+
export function is_ref_prop_expression(expression) {
|
|
4794
|
+
return (
|
|
4795
|
+
expression?.type === 'RefExpression' ||
|
|
4796
|
+
(expression?.type === 'CallExpression' &&
|
|
4797
|
+
expression.callee?.type === 'Identifier' &&
|
|
4798
|
+
expression.callee.name === CREATE_REF_PROP_INTERNAL_NAME)
|
|
4799
|
+
);
|
|
4433
4800
|
}
|
|
4434
4801
|
|
|
4435
4802
|
/**
|
|
@@ -4549,7 +4916,7 @@ export function merge_duplicate_refs(jsx_attrs, transform_context) {
|
|
|
4549
4916
|
type: 'CallExpression',
|
|
4550
4917
|
callee: {
|
|
4551
4918
|
type: 'Identifier',
|
|
4552
|
-
name:
|
|
4919
|
+
name: MERGE_REFS_INTERNAL_NAME,
|
|
4553
4920
|
metadata: { path: [] },
|
|
4554
4921
|
},
|
|
4555
4922
|
arguments: ref_exprs,
|
|
@@ -4610,7 +4977,9 @@ function is_jsx_ref_attribute(attr) {
|
|
|
4610
4977
|
* double-underscore matches the convention for compiler-generated
|
|
4611
4978
|
* identifiers and avoids shadowing user-declared `mergeRefs` symbols.
|
|
4612
4979
|
*/
|
|
4613
|
-
const
|
|
4980
|
+
export const MERGE_REFS_INTERNAL_NAME = '__mergeRefs';
|
|
4981
|
+
export const CREATE_REF_PROP_INTERNAL_NAME = '__create_ref_prop';
|
|
4982
|
+
export const NORMALIZE_SPREAD_PROPS_INTERNAL_NAME = '__normalize_spread_props';
|
|
4614
4983
|
|
|
4615
4984
|
/**
|
|
4616
4985
|
* @param {any} attr
|
|
@@ -4619,7 +4988,31 @@ const MERGE_REFS_LOCAL_NAME = '__mergeRefs';
|
|
|
4619
4988
|
*/
|
|
4620
4989
|
export function to_jsx_attribute(attr, transform_context) {
|
|
4621
4990
|
if (!attr) return attr;
|
|
4622
|
-
if (attr.type === 'JSXAttribute'
|
|
4991
|
+
if (attr.type === 'JSXAttribute') {
|
|
4992
|
+
if (
|
|
4993
|
+
attr.value?.type === 'JSXExpressionContainer' &&
|
|
4994
|
+
attr.value.expression?.type === 'RefExpression'
|
|
4995
|
+
) {
|
|
4996
|
+
return {
|
|
4997
|
+
...attr,
|
|
4998
|
+
value: to_jsx_expression_container(
|
|
4999
|
+
create_ref_prop_call(attr.value.expression, transform_context),
|
|
5000
|
+
),
|
|
5001
|
+
metadata: { ...(attr.metadata || {}), from_ref_keyword: true },
|
|
5002
|
+
};
|
|
5003
|
+
}
|
|
5004
|
+
if (
|
|
5005
|
+
attr.value?.type === 'JSXExpressionContainer' &&
|
|
5006
|
+
is_ref_prop_expression(attr.value.expression)
|
|
5007
|
+
) {
|
|
5008
|
+
return {
|
|
5009
|
+
...attr,
|
|
5010
|
+
metadata: { ...(attr.metadata || {}), from_ref_keyword: true },
|
|
5011
|
+
};
|
|
5012
|
+
}
|
|
5013
|
+
return attr;
|
|
5014
|
+
}
|
|
5015
|
+
if (attr.type === 'JSXSpreadAttribute') {
|
|
4623
5016
|
return attr;
|
|
4624
5017
|
}
|
|
4625
5018
|
if (attr.type === 'SpreadAttribute') {
|
|
@@ -4670,15 +5063,28 @@ export function to_jsx_attribute(attr, transform_context) {
|
|
|
4670
5063
|
attr_name && attr_name.type === 'Identifier' ? identifier_to_jsx_name(attr_name) : attr_name;
|
|
4671
5064
|
|
|
4672
5065
|
let value = attr.value;
|
|
5066
|
+
const is_ref_expression_value =
|
|
5067
|
+
value?.type === 'RefExpression' ||
|
|
5068
|
+
is_ref_prop_expression(value) ||
|
|
5069
|
+
(value?.type === 'JSXExpressionContainer' && is_ref_prop_expression(value.expression));
|
|
4673
5070
|
if (value) {
|
|
4674
5071
|
if (value.type === 'Literal' && typeof value.value === 'string') {
|
|
4675
5072
|
// Keep string literal as attribute string.
|
|
5073
|
+
} else if (value.type === 'RefExpression') {
|
|
5074
|
+
value = to_jsx_expression_container(create_ref_prop_call(value, transform_context));
|
|
4676
5075
|
} else if (value.type !== 'JSXExpressionContainer') {
|
|
4677
5076
|
value = to_jsx_expression_container(value);
|
|
5077
|
+
} else if (value.expression?.type === 'RefExpression') {
|
|
5078
|
+
value = to_jsx_expression_container(
|
|
5079
|
+
create_ref_prop_call(value.expression, transform_context),
|
|
5080
|
+
);
|
|
4678
5081
|
}
|
|
4679
5082
|
}
|
|
4680
5083
|
|
|
4681
5084
|
const jsx_attribute = build_jsx_attribute(name, value || null, attr.shorthand === true);
|
|
5085
|
+
if (is_ref_expression_value) {
|
|
5086
|
+
/** @type {any} */ (jsx_attribute.metadata).from_ref_keyword = true;
|
|
5087
|
+
}
|
|
4682
5088
|
|
|
4683
5089
|
if (value_has_unmappable_jsx_loc(value)) {
|
|
4684
5090
|
/** @type {any} */ (jsx_attribute.metadata).has_unmappable_value = true;
|
|
@@ -4700,6 +5106,35 @@ function value_has_unmappable_jsx_loc(value) {
|
|
|
4700
5106
|
);
|
|
4701
5107
|
}
|
|
4702
5108
|
|
|
5109
|
+
/**
|
|
5110
|
+
* @param {any} node
|
|
5111
|
+
* @param {TransformContext} transform_context
|
|
5112
|
+
* @returns {any}
|
|
5113
|
+
*/
|
|
5114
|
+
function create_ref_prop_call(node, transform_context) {
|
|
5115
|
+
transform_context.needs_ref_prop = true;
|
|
5116
|
+
|
|
5117
|
+
const argument = node.argument;
|
|
5118
|
+
const args = [b.thunk(argument)];
|
|
5119
|
+
|
|
5120
|
+
if (argument.type === 'Identifier' || argument.type === 'MemberExpression') {
|
|
5121
|
+
args.push(
|
|
5122
|
+
b.arrow(
|
|
5123
|
+
[b.id('v')],
|
|
5124
|
+
/** @type {any} */ ({
|
|
5125
|
+
type: 'AssignmentExpression',
|
|
5126
|
+
operator: '=',
|
|
5127
|
+
left: clone_expression_node(argument, false),
|
|
5128
|
+
right: b.id('v'),
|
|
5129
|
+
metadata: { path: [] },
|
|
5130
|
+
}),
|
|
5131
|
+
),
|
|
5132
|
+
);
|
|
5133
|
+
}
|
|
5134
|
+
|
|
5135
|
+
return b.call(CREATE_REF_PROP_INTERNAL_NAME, ...args);
|
|
5136
|
+
}
|
|
5137
|
+
|
|
4703
5138
|
/**
|
|
4704
5139
|
* @param {any} node
|
|
4705
5140
|
* @param {TransformContext} transform_context
|