@tsrx/core 0.0.26 → 0.0.28
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/analyze/validation.js +59 -0
- package/src/index.js +15 -1
- package/src/plugin.js +18 -62
- package/src/runtime/language-helpers.js +57 -0
- package/src/runtime/ref.js +250 -0
- package/src/transform/jsx/ast-builders.js +64 -13
- package/src/transform/jsx/index.js +563 -98
- package/src/transform/segments.js +21 -19
- package/src/transform/stylesheet.js +19 -0
- package/types/index.d.ts +58 -12
- package/types/jsx-platform.d.ts +47 -3
- 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
|
@@ -20,12 +20,13 @@ import {
|
|
|
20
20
|
flatten_switch_consequent,
|
|
21
21
|
get_for_of_iteration_params,
|
|
22
22
|
identifier_to_jsx_name,
|
|
23
|
+
is_bare_render_expression,
|
|
23
24
|
is_dynamic_element_id,
|
|
24
25
|
is_jsx_child,
|
|
25
26
|
set_loc,
|
|
26
27
|
to_text_expression,
|
|
27
28
|
} from './ast-builders.js';
|
|
28
|
-
import {
|
|
29
|
+
import { render_css_result } from '../stylesheet.js';
|
|
29
30
|
import {
|
|
30
31
|
set_location as setLocation,
|
|
31
32
|
jsx_attribute as build_jsx_attribute,
|
|
@@ -41,8 +42,10 @@ import {
|
|
|
41
42
|
import { find_first_top_level_await_in_component_body } from '../await.js';
|
|
42
43
|
import { prepare_stylesheet_for_render, annotate_component_with_hash } from '../scoping.js';
|
|
43
44
|
import {
|
|
45
|
+
validate_class_component_declarations,
|
|
44
46
|
validate_component_loop_break_statement,
|
|
45
47
|
validate_component_loop_return_statement,
|
|
48
|
+
validate_component_params,
|
|
46
49
|
validate_component_return_statement,
|
|
47
50
|
validate_component_unsupported_loop_statement,
|
|
48
51
|
} from '../../analyze/validation.js';
|
|
@@ -166,7 +169,11 @@ export function createJsxTransform(platform) {
|
|
|
166
169
|
needs_error_boundary: false,
|
|
167
170
|
needs_suspense: false,
|
|
168
171
|
needs_merge_refs: false,
|
|
172
|
+
needs_ref_prop: false,
|
|
173
|
+
needs_normalize_spread_props: false,
|
|
169
174
|
needs_fragment: false,
|
|
175
|
+
module_scoped_hook_components:
|
|
176
|
+
options?.moduleScopedHookComponents ?? !!platform.hooks?.moduleScopedHookComponents,
|
|
170
177
|
helper_state: null,
|
|
171
178
|
available_bindings: new Map(),
|
|
172
179
|
lazy_next_id: 0,
|
|
@@ -175,12 +182,15 @@ export function createJsxTransform(platform) {
|
|
|
175
182
|
collect,
|
|
176
183
|
errors: collect ? options?.errors : undefined,
|
|
177
184
|
comments: options?.comments,
|
|
185
|
+
typeOnly: !!options?.typeOnly,
|
|
178
186
|
// Platforms can seed their own tracking state (e.g. solid's
|
|
179
187
|
// needs_show / needs_for flags) via `hooks.initialState`.
|
|
180
188
|
...(platform.hooks?.initialState?.() ?? {}),
|
|
181
189
|
};
|
|
182
190
|
|
|
183
|
-
|
|
191
|
+
if (!transform_context.typeOnly) {
|
|
192
|
+
preallocate_lazy_ids(/** @type {any} */ (ast), transform_context);
|
|
193
|
+
}
|
|
184
194
|
|
|
185
195
|
walk(/** @type {any} */ (ast), transform_context, {
|
|
186
196
|
ReturnStatement(node, { next, path }) {
|
|
@@ -270,9 +280,26 @@ export function createJsxTransform(platform) {
|
|
|
270
280
|
return next();
|
|
271
281
|
},
|
|
272
282
|
|
|
283
|
+
ClassBody(node, { next }) {
|
|
284
|
+
validate_class_component_declarations(
|
|
285
|
+
/** @type {any} */ (node),
|
|
286
|
+
filename,
|
|
287
|
+
transform_context.errors,
|
|
288
|
+
transform_context.comments,
|
|
289
|
+
);
|
|
290
|
+
return next();
|
|
291
|
+
},
|
|
292
|
+
|
|
273
293
|
Component(node, { next, state }) {
|
|
274
294
|
const as_any = /** @type {any} */ (node);
|
|
275
295
|
|
|
296
|
+
validate_component_params(
|
|
297
|
+
as_any,
|
|
298
|
+
filename,
|
|
299
|
+
transform_context.errors,
|
|
300
|
+
transform_context.comments,
|
|
301
|
+
);
|
|
302
|
+
|
|
276
303
|
const await_expression = find_first_top_level_await_in_component_body(as_any.body || []);
|
|
277
304
|
|
|
278
305
|
if (await_expression) {
|
|
@@ -357,13 +384,20 @@ export function createJsxTransform(platform) {
|
|
|
357
384
|
|
|
358
385
|
Tsx(node, { next, path }) {
|
|
359
386
|
const inner = /** @type {any} */ (next() ?? node);
|
|
360
|
-
|
|
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
|
+
);
|
|
361
391
|
},
|
|
362
392
|
|
|
363
393
|
TsxCompat(node, { next, path, state }) {
|
|
364
394
|
const inner = /** @type {any} */ (next() ?? node);
|
|
395
|
+
const in_jsx_child = in_jsx_child_context(path);
|
|
365
396
|
return /** @type {any} */ (
|
|
366
|
-
|
|
397
|
+
wrap_jsx_setup_declarations(
|
|
398
|
+
tsx_compat_node_to_jsx_expression(inner, state, in_jsx_child),
|
|
399
|
+
in_jsx_child,
|
|
400
|
+
)
|
|
367
401
|
);
|
|
368
402
|
},
|
|
369
403
|
|
|
@@ -407,6 +441,27 @@ export function createJsxTransform(platform) {
|
|
|
407
441
|
FunctionDeclaration: ensure_function_metadata,
|
|
408
442
|
FunctionExpression: ensure_function_metadata,
|
|
409
443
|
ArrowFunctionExpression: ensure_function_metadata,
|
|
444
|
+
|
|
445
|
+
RefExpression(node) {
|
|
446
|
+
return create_ref_prop_call(node, transform_context);
|
|
447
|
+
},
|
|
448
|
+
|
|
449
|
+
JSXOpeningElement(node, { next }) {
|
|
450
|
+
const visited = next() || node;
|
|
451
|
+
const is_component = is_component_like_jsx_name(visited.name);
|
|
452
|
+
const attrs = normalize_named_ref_attributes(
|
|
453
|
+
visited.attributes || [],
|
|
454
|
+
!is_component,
|
|
455
|
+
transform_context,
|
|
456
|
+
);
|
|
457
|
+
return {
|
|
458
|
+
...visited,
|
|
459
|
+
attributes: merge_duplicate_refs(
|
|
460
|
+
normalize_host_ref_spreads(attrs, !is_component, transform_context),
|
|
461
|
+
transform_context,
|
|
462
|
+
),
|
|
463
|
+
};
|
|
464
|
+
},
|
|
410
465
|
});
|
|
411
466
|
|
|
412
467
|
const expanded = expand_component_helpers(/** @type {AST.Program} */ (transformed));
|
|
@@ -420,8 +475,15 @@ export function createJsxTransform(platform) {
|
|
|
420
475
|
// declarations, arrow functions, etc.). Component bodies have already been
|
|
421
476
|
// transformed inside component_to_function_declaration; this catches plain
|
|
422
477
|
// functions outside components and any lazy patterns in module scope.
|
|
478
|
+
// In type-only mode, the lazy patterns survive untouched: esrap ignores the
|
|
479
|
+
// non-standard `lazy` flag, so `&{ a, b }` prints as `{ a, b }`, `let &[a]
|
|
480
|
+
// = expr` prints as `let [a] = expr`, and the bare statement-level form
|
|
481
|
+
// `&[x] = expr;` (used when `x` is already declared) prints as `[x] =
|
|
482
|
+
// expr;` — a valid destructuring assignment to the existing binding.
|
|
423
483
|
const final_program = /** @type {any} */ (
|
|
424
|
-
|
|
484
|
+
transform_context.typeOnly
|
|
485
|
+
? expanded
|
|
486
|
+
: apply_lazy_transforms(/** @type {any} */ (expanded), new Map())
|
|
425
487
|
);
|
|
426
488
|
|
|
427
489
|
const result = print(/** @type {any} */ (final_program), tsx_with_ts_locations(), {
|
|
@@ -429,17 +491,11 @@ export function createJsxTransform(platform) {
|
|
|
429
491
|
sourceMapContent: source,
|
|
430
492
|
});
|
|
431
493
|
|
|
432
|
-
const css =
|
|
433
|
-
stylesheets.
|
|
434
|
-
|
|
435
|
-
code: renderStylesheets(
|
|
436
|
-
/** @type {any} */ (stylesheets.map(prepare_stylesheet_for_render)),
|
|
437
|
-
),
|
|
438
|
-
hash: stylesheets.map((s) => s.hash).join(' '),
|
|
439
|
-
}
|
|
440
|
-
: null;
|
|
494
|
+
const { css, cssHash } = render_css_result(
|
|
495
|
+
/** @type {any} */ (stylesheets.map(prepare_stylesheet_for_render)),
|
|
496
|
+
);
|
|
441
497
|
|
|
442
|
-
return { ast: final_program, code: result.code, map: result.map, css };
|
|
498
|
+
return { ast: final_program, code: result.code, map: result.map, css, cssHash };
|
|
443
499
|
}
|
|
444
500
|
|
|
445
501
|
return transform;
|
|
@@ -503,7 +559,11 @@ export function component_to_function_declaration(component, transform_context,
|
|
|
503
559
|
// Collect lazy binding info WITHOUT mutating patterns. Stores lazy_id on metadata
|
|
504
560
|
// for later replacement. Body bindings (count, setCount, etc.) are still in the
|
|
505
561
|
// original patterns, so collect_statement_bindings during build will find them.
|
|
506
|
-
|
|
562
|
+
// In type-only mode the lazy rewrite is skipped entirely so destructuring
|
|
563
|
+
// patterns survive into the virtual TSX and TypeScript can flow real types.
|
|
564
|
+
const lazy_bindings = transform_context.typeOnly
|
|
565
|
+
? new Map()
|
|
566
|
+
: collect_lazy_bindings_from_component(params, body, transform_context);
|
|
507
567
|
|
|
508
568
|
// Save and set context for this component scope
|
|
509
569
|
const saved_helper_state = transform_context.helper_state;
|
|
@@ -876,6 +936,7 @@ function build_render_statements(body_nodes, return_null_when_empty, transform_c
|
|
|
876
936
|
|
|
877
937
|
if (is_jsx_child(child)) {
|
|
878
938
|
const jsx = to_jsx_child(child, transform_context);
|
|
939
|
+
statements.push(...extract_jsx_setup_declarations(jsx));
|
|
879
940
|
if (interleaved && is_capturable_jsx_child(jsx)) {
|
|
880
941
|
const { declaration, reference } = captureJsxChild(jsx, capture_index++);
|
|
881
942
|
statements.push(declaration);
|
|
@@ -883,6 +944,8 @@ function build_render_statements(body_nodes, return_null_when_empty, transform_c
|
|
|
883
944
|
} else {
|
|
884
945
|
render_nodes.push(jsx);
|
|
885
946
|
}
|
|
947
|
+
} else if (is_bare_render_expression(child)) {
|
|
948
|
+
render_nodes.push(to_jsx_expression_container(child, child));
|
|
886
949
|
} else {
|
|
887
950
|
statements.push(child);
|
|
888
951
|
collect_statement_bindings(child, transform_context.available_bindings);
|
|
@@ -1170,6 +1233,25 @@ function create_helper_state(base_name) {
|
|
|
1170
1233
|
};
|
|
1171
1234
|
}
|
|
1172
1235
|
|
|
1236
|
+
/**
|
|
1237
|
+
* @param {TransformContext} transform_context
|
|
1238
|
+
* @returns {boolean}
|
|
1239
|
+
*/
|
|
1240
|
+
function should_use_module_scoped_hook_components(transform_context) {
|
|
1241
|
+
return !!(transform_context.helper_state && transform_context.module_scoped_hook_components);
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
/**
|
|
1245
|
+
* @param {AST.Identifier} helper_id
|
|
1246
|
+
* @param {TransformContext} transform_context
|
|
1247
|
+
* @returns {AST.Identifier}
|
|
1248
|
+
*/
|
|
1249
|
+
function create_module_scoped_hook_component_id(helper_id, transform_context) {
|
|
1250
|
+
return create_generated_identifier(
|
|
1251
|
+
`${transform_context.helper_state?.base_name || 'Component'}__${helper_id.name}`,
|
|
1252
|
+
);
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1173
1255
|
/**
|
|
1174
1256
|
* @param {any[]} params
|
|
1175
1257
|
* @returns {Map<string, AST.Identifier>}
|
|
@@ -1525,9 +1607,7 @@ function create_component_return_statement(
|
|
|
1525
1607
|
map_render_node_locations = true,
|
|
1526
1608
|
) {
|
|
1527
1609
|
const cloned = render_nodes.map((node) =>
|
|
1528
|
-
map_render_node_locations
|
|
1529
|
-
? clone_expression_node(node)
|
|
1530
|
-
: clone_expression_node_without_locations(node),
|
|
1610
|
+
map_render_node_locations ? clone_expression_node(node) : clone_expression_node(node, false),
|
|
1531
1611
|
);
|
|
1532
1612
|
|
|
1533
1613
|
return set_loc(b.return(build_return_expression(cloned) || create_null_literal()), source_node);
|
|
@@ -1594,7 +1674,7 @@ function build_tail_helper(continuation_body, source_node, transform_context) {
|
|
|
1594
1674
|
* @returns {any}
|
|
1595
1675
|
*/
|
|
1596
1676
|
function clone_tail_invocation(tail_helper) {
|
|
1597
|
-
return
|
|
1677
|
+
return clone_expression_node(tail_helper.component_element, false);
|
|
1598
1678
|
}
|
|
1599
1679
|
|
|
1600
1680
|
/**
|
|
@@ -2149,25 +2229,33 @@ function build_hoisted_for_of_with_hooks(node, continuation_body, transform_cont
|
|
|
2149
2229
|
const helper_id = create_generated_identifier(
|
|
2150
2230
|
create_local_statement_component_name(transform_context),
|
|
2151
2231
|
);
|
|
2152
|
-
|
|
2153
|
-
const
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2232
|
+
const use_module_scoped_component = should_use_module_scoped_hook_components(transform_context);
|
|
2233
|
+
const component_id = use_module_scoped_component
|
|
2234
|
+
? create_module_scoped_hook_component_id(helper_id, transform_context)
|
|
2235
|
+
: helper_id;
|
|
2236
|
+
|
|
2237
|
+
const outer_aliases = use_module_scoped_component
|
|
2238
|
+
? []
|
|
2239
|
+
: outer_bindings.map((binding) => create_helper_type_alias_declaration(helper_id, binding));
|
|
2240
|
+
const loop_aliases = use_module_scoped_component
|
|
2241
|
+
? []
|
|
2242
|
+
: loop_bindings.map((binding) =>
|
|
2243
|
+
create_loop_scoped_type_alias_declaration(helper_id, binding, source_id, loop_params),
|
|
2244
|
+
);
|
|
2159
2245
|
|
|
2160
2246
|
// Synthetic `isLast` prop on the loop helper when there's a tail. It's
|
|
2161
2247
|
// passed from the .map callback as `i === source.length - 1` so every
|
|
2162
2248
|
// loop-helper return can append the tail helper on the last iteration.
|
|
2163
2249
|
const tail_isLast_alias = has_tail
|
|
2164
|
-
?
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
create_generated_identifier(`_tsrx_${helper_id.name}_isLast`),
|
|
2168
|
-
b.
|
|
2169
|
-
|
|
2170
|
-
|
|
2250
|
+
? use_module_scoped_component
|
|
2251
|
+
? null
|
|
2252
|
+
: {
|
|
2253
|
+
id: create_generated_identifier(`_tsrx_${helper_id.name}_isLast`),
|
|
2254
|
+
declaration: b.ts_type_alias(
|
|
2255
|
+
create_generated_identifier(`_tsrx_${helper_id.name}_isLast`),
|
|
2256
|
+
b.ts_keyword_type('boolean'),
|
|
2257
|
+
),
|
|
2258
|
+
}
|
|
2171
2259
|
: null;
|
|
2172
2260
|
|
|
2173
2261
|
const ordered_bindings = [...outer_bindings, ...loop_bindings];
|
|
@@ -2181,7 +2269,7 @@ function build_hoisted_for_of_with_hooks(node, continuation_body, transform_cont
|
|
|
2181
2269
|
const signature_use_typeof = has_tail ? [...ordered_use_typeof, false] : ordered_use_typeof;
|
|
2182
2270
|
|
|
2183
2271
|
const props_type =
|
|
2184
|
-
signature_bindings.length > 0
|
|
2272
|
+
signature_bindings.length > 0 && !use_module_scoped_component
|
|
2185
2273
|
? create_helper_props_type_literal_with_typeof_flags(
|
|
2186
2274
|
signature_bindings,
|
|
2187
2275
|
signature_aliases,
|
|
@@ -2189,7 +2277,13 @@ function build_hoisted_for_of_with_hooks(node, continuation_body, transform_cont
|
|
|
2189
2277
|
)
|
|
2190
2278
|
: null;
|
|
2191
2279
|
const params =
|
|
2192
|
-
|
|
2280
|
+
signature_bindings.length > 0
|
|
2281
|
+
? [
|
|
2282
|
+
props_type !== null
|
|
2283
|
+
? create_typed_helper_props_pattern(signature_bindings, props_type)
|
|
2284
|
+
: create_helper_props_pattern(signature_bindings),
|
|
2285
|
+
]
|
|
2286
|
+
: [];
|
|
2193
2287
|
|
|
2194
2288
|
const fn_saved_bindings = transform_context.available_bindings;
|
|
2195
2289
|
transform_context.available_bindings = new Map(fn_saved_bindings);
|
|
@@ -2207,12 +2301,17 @@ function build_hoisted_for_of_with_hooks(node, continuation_body, transform_cont
|
|
|
2207
2301
|
transform_context.available_bindings = fn_saved_bindings;
|
|
2208
2302
|
|
|
2209
2303
|
const helper_fn = /** @type {any} */ (
|
|
2210
|
-
b.function(clone_identifier(
|
|
2304
|
+
b.function(clone_identifier(component_id), params, b.block(fn_body_statements))
|
|
2211
2305
|
);
|
|
2212
2306
|
helper_fn.metadata = { path: [], is_component: true, is_method: false };
|
|
2213
2307
|
|
|
2214
2308
|
let helper_decl;
|
|
2215
|
-
if (transform_context.helper_state) {
|
|
2309
|
+
if (transform_context.helper_state && use_module_scoped_component) {
|
|
2310
|
+
transform_context.helper_state.helpers.push(
|
|
2311
|
+
create_helper_declaration(component_id, helper_fn, node, transform_context),
|
|
2312
|
+
);
|
|
2313
|
+
helper_decl = null;
|
|
2314
|
+
} else if (transform_context.helper_state) {
|
|
2216
2315
|
const cache_id = create_generated_identifier(
|
|
2217
2316
|
`${transform_context.helper_state.base_name}__${helper_id.name}`,
|
|
2218
2317
|
);
|
|
@@ -2229,7 +2328,7 @@ function build_hoisted_for_of_with_hooks(node, continuation_body, transform_cont
|
|
|
2229
2328
|
transform_context.available_bindings = saved_bindings;
|
|
2230
2329
|
|
|
2231
2330
|
const callback_invocation_element = create_helper_component_element(
|
|
2232
|
-
|
|
2331
|
+
component_id,
|
|
2233
2332
|
ordered_bindings,
|
|
2234
2333
|
node,
|
|
2235
2334
|
{ mapWrapper: false, mapBindingNames: false, mapBindingValues: false },
|
|
@@ -2310,7 +2409,9 @@ function build_hoisted_for_of_with_hooks(node, continuation_body, transform_cont
|
|
|
2310
2409
|
if (has_tail && tail_isLast_alias) {
|
|
2311
2410
|
hoist_statements.push(tail_isLast_alias.declaration);
|
|
2312
2411
|
}
|
|
2313
|
-
|
|
2412
|
+
if (helper_decl) {
|
|
2413
|
+
hoist_statements.push(helper_decl);
|
|
2414
|
+
}
|
|
2314
2415
|
|
|
2315
2416
|
return {
|
|
2316
2417
|
hoist_statements,
|
|
@@ -2481,7 +2582,7 @@ function prepend_render_nodes_to_return_statement(node, render_nodes, inside_nes
|
|
|
2481
2582
|
* @returns {any}
|
|
2482
2583
|
*/
|
|
2483
2584
|
function combine_render_return_argument(render_nodes, return_argument) {
|
|
2484
|
-
const combined = render_nodes.map((node) =>
|
|
2585
|
+
const combined = render_nodes.map((node) => clone_expression_node(node, false));
|
|
2485
2586
|
|
|
2486
2587
|
if (return_argument != null && !is_null_literal(return_argument)) {
|
|
2487
2588
|
combined.push(return_argument_to_render_node(return_argument));
|
|
@@ -2514,30 +2615,6 @@ function is_null_literal(node) {
|
|
|
2514
2615
|
return node?.type === 'Literal' && node.value == null;
|
|
2515
2616
|
}
|
|
2516
2617
|
|
|
2517
|
-
/**
|
|
2518
|
-
* @param {any} node
|
|
2519
|
-
* @returns {any}
|
|
2520
|
-
*/
|
|
2521
|
-
function clone_expression_node_without_locations(node) {
|
|
2522
|
-
if (!node || typeof node !== 'object') return node;
|
|
2523
|
-
if (Array.isArray(node)) return node.map(clone_expression_node_without_locations);
|
|
2524
|
-
|
|
2525
|
-
const clone = { ...node };
|
|
2526
|
-
delete clone.loc;
|
|
2527
|
-
delete clone.start;
|
|
2528
|
-
delete clone.end;
|
|
2529
|
-
|
|
2530
|
-
for (const key of Object.keys(clone)) {
|
|
2531
|
-
if (key === 'metadata') {
|
|
2532
|
-
clone.metadata = clone.metadata ? { ...clone.metadata } : { path: [] };
|
|
2533
|
-
continue;
|
|
2534
|
-
}
|
|
2535
|
-
clone[key] = clone_expression_node_without_locations(clone[key]);
|
|
2536
|
-
}
|
|
2537
|
-
|
|
2538
|
-
return clone;
|
|
2539
|
-
}
|
|
2540
|
-
|
|
2541
2618
|
const TEMPLATE_FRAGMENT_ERROR =
|
|
2542
2619
|
'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>.';
|
|
2543
2620
|
|
|
@@ -2770,8 +2847,8 @@ function create_local_statement_component_name(transform_context) {
|
|
|
2770
2847
|
/**
|
|
2771
2848
|
* Wraps a list of body nodes into a component and returns
|
|
2772
2849
|
* statements that return `<ComponentName prop1={prop1} ... />`.
|
|
2773
|
-
*
|
|
2774
|
-
*
|
|
2850
|
+
* Targets can either emit the helper component at module scope or cache the
|
|
2851
|
+
* component identity in module state while initializing it from the parent.
|
|
2775
2852
|
* Used when a control flow branch contains hook calls that must be moved
|
|
2776
2853
|
* into their own component boundary to satisfy the Rules of Hooks.
|
|
2777
2854
|
*
|
|
@@ -2844,24 +2921,36 @@ function create_hook_safe_helper(
|
|
|
2844
2921
|
const helper_id =
|
|
2845
2922
|
preallocated_helper_id ??
|
|
2846
2923
|
create_generated_identifier(create_local_statement_component_name(transform_context));
|
|
2924
|
+
const use_module_scoped_component = should_use_module_scoped_hook_components(transform_context);
|
|
2925
|
+
const component_id = use_module_scoped_component
|
|
2926
|
+
? create_module_scoped_hook_component_id(helper_id, transform_context)
|
|
2927
|
+
: helper_id;
|
|
2847
2928
|
const helper_bindings = get_referenced_helper_bindings(
|
|
2848
2929
|
body_nodes,
|
|
2849
2930
|
transform_context.available_bindings,
|
|
2850
2931
|
);
|
|
2851
|
-
const aliases =
|
|
2852
|
-
|
|
2853
|
-
|
|
2932
|
+
const aliases = use_module_scoped_component
|
|
2933
|
+
? []
|
|
2934
|
+
: helper_bindings.map((binding) => create_helper_type_alias_declaration(helper_id, binding));
|
|
2854
2935
|
const props_type =
|
|
2855
|
-
helper_bindings.length > 0
|
|
2936
|
+
helper_bindings.length > 0 && !use_module_scoped_component
|
|
2937
|
+
? create_helper_props_type_literal(helper_bindings, aliases)
|
|
2938
|
+
: null;
|
|
2856
2939
|
const params =
|
|
2857
|
-
|
|
2940
|
+
helper_bindings.length > 0
|
|
2941
|
+
? [
|
|
2942
|
+
props_type !== null
|
|
2943
|
+
? create_typed_helper_props_pattern(helper_bindings, props_type)
|
|
2944
|
+
: create_helper_props_pattern(helper_bindings),
|
|
2945
|
+
]
|
|
2946
|
+
: [];
|
|
2858
2947
|
|
|
2859
2948
|
const saved_bindings = transform_context.available_bindings;
|
|
2860
2949
|
transform_context.available_bindings = new Map(saved_bindings);
|
|
2861
2950
|
|
|
2862
2951
|
const helper_fn = /** @type {any} */ ({
|
|
2863
2952
|
type: 'FunctionExpression',
|
|
2864
|
-
id: clone_identifier(
|
|
2953
|
+
id: clone_identifier(component_id),
|
|
2865
2954
|
params,
|
|
2866
2955
|
body: {
|
|
2867
2956
|
type: 'BlockStatement',
|
|
@@ -2880,7 +2969,7 @@ function create_hook_safe_helper(
|
|
|
2880
2969
|
transform_context.available_bindings = saved_bindings;
|
|
2881
2970
|
|
|
2882
2971
|
const component_element = create_helper_component_element(
|
|
2883
|
-
|
|
2972
|
+
component_id,
|
|
2884
2973
|
helper_bindings,
|
|
2885
2974
|
source_node,
|
|
2886
2975
|
{
|
|
@@ -2911,6 +3000,16 @@ function create_hook_safe_helper(
|
|
|
2911
3000
|
};
|
|
2912
3001
|
}
|
|
2913
3002
|
|
|
3003
|
+
if (use_module_scoped_component) {
|
|
3004
|
+
transform_context.helper_state.helpers.push(
|
|
3005
|
+
create_helper_declaration(component_id, helper_fn, source_node, transform_context),
|
|
3006
|
+
);
|
|
3007
|
+
return {
|
|
3008
|
+
setup_statements: [],
|
|
3009
|
+
component_element,
|
|
3010
|
+
};
|
|
3011
|
+
}
|
|
3012
|
+
|
|
2914
3013
|
const cache_id = create_generated_identifier(
|
|
2915
3014
|
`${transform_context.helper_state.base_name}__${helper_id.name}`,
|
|
2916
3015
|
);
|
|
@@ -4107,30 +4206,79 @@ function inject_try_imports(program, transform_context, platform, suspense_sourc
|
|
|
4107
4206
|
});
|
|
4108
4207
|
}
|
|
4109
4208
|
|
|
4110
|
-
|
|
4111
|
-
|
|
4209
|
+
const merge_refs_source =
|
|
4210
|
+
transform_context.needs_merge_refs && platform.imports.mergeRefs
|
|
4211
|
+
? platform.imports.mergeRefs
|
|
4212
|
+
: null;
|
|
4213
|
+
const ref_prop_source =
|
|
4214
|
+
transform_context.needs_ref_prop && platform.imports.refProp ? platform.imports.refProp : null;
|
|
4215
|
+
const normalize_spread_props_source =
|
|
4216
|
+
transform_context.needs_normalize_spread_props && platform.imports.refProp
|
|
4217
|
+
? platform.imports.refProp
|
|
4218
|
+
: null;
|
|
4219
|
+
|
|
4220
|
+
/** @type {Map<string, any[]>} */
|
|
4221
|
+
const ref_imports = new Map();
|
|
4222
|
+
|
|
4223
|
+
if (merge_refs_source !== null) {
|
|
4224
|
+
add_ref_import_specifier(ref_imports, merge_refs_source, {
|
|
4225
|
+
type: 'ImportSpecifier',
|
|
4226
|
+
imported: {
|
|
4227
|
+
type: 'Identifier',
|
|
4228
|
+
name: 'mergeRefs',
|
|
4229
|
+
metadata: { path: [] },
|
|
4230
|
+
},
|
|
4231
|
+
local: {
|
|
4232
|
+
type: 'Identifier',
|
|
4233
|
+
name: MERGE_REFS_INTERNAL_NAME,
|
|
4234
|
+
metadata: { path: [] },
|
|
4235
|
+
},
|
|
4236
|
+
metadata: { path: [] },
|
|
4237
|
+
});
|
|
4238
|
+
}
|
|
4239
|
+
|
|
4240
|
+
if (ref_prop_source !== null) {
|
|
4241
|
+
add_ref_import_specifier(ref_imports, ref_prop_source, {
|
|
4242
|
+
type: 'ImportSpecifier',
|
|
4243
|
+
imported: {
|
|
4244
|
+
type: 'Identifier',
|
|
4245
|
+
name: 'create_ref_prop',
|
|
4246
|
+
metadata: { path: [] },
|
|
4247
|
+
},
|
|
4248
|
+
local: {
|
|
4249
|
+
type: 'Identifier',
|
|
4250
|
+
name: CREATE_REF_PROP_INTERNAL_NAME,
|
|
4251
|
+
metadata: { path: [] },
|
|
4252
|
+
},
|
|
4253
|
+
metadata: { path: [] },
|
|
4254
|
+
});
|
|
4255
|
+
}
|
|
4256
|
+
|
|
4257
|
+
if (normalize_spread_props_source !== null) {
|
|
4258
|
+
add_ref_import_specifier(ref_imports, normalize_spread_props_source, {
|
|
4259
|
+
type: 'ImportSpecifier',
|
|
4260
|
+
imported: {
|
|
4261
|
+
type: 'Identifier',
|
|
4262
|
+
name: 'normalize_spread_props',
|
|
4263
|
+
metadata: { path: [] },
|
|
4264
|
+
},
|
|
4265
|
+
local: {
|
|
4266
|
+
type: 'Identifier',
|
|
4267
|
+
name: NORMALIZE_SPREAD_PROPS_INTERNAL_NAME,
|
|
4268
|
+
metadata: { path: [] },
|
|
4269
|
+
},
|
|
4270
|
+
metadata: { path: [] },
|
|
4271
|
+
});
|
|
4272
|
+
}
|
|
4273
|
+
|
|
4274
|
+
for (const [source, ref_specifiers] of ref_imports) {
|
|
4112
4275
|
imports.push({
|
|
4113
4276
|
type: 'ImportDeclaration',
|
|
4114
|
-
specifiers:
|
|
4115
|
-
{
|
|
4116
|
-
type: 'ImportSpecifier',
|
|
4117
|
-
imported: {
|
|
4118
|
-
type: 'Identifier',
|
|
4119
|
-
name: 'mergeRefs',
|
|
4120
|
-
metadata: { path: [] },
|
|
4121
|
-
},
|
|
4122
|
-
local: {
|
|
4123
|
-
type: 'Identifier',
|
|
4124
|
-
name: MERGE_REFS_LOCAL_NAME,
|
|
4125
|
-
metadata: { path: [] },
|
|
4126
|
-
},
|
|
4127
|
-
metadata: { path: [] },
|
|
4128
|
-
},
|
|
4129
|
-
],
|
|
4277
|
+
specifiers: ref_specifiers,
|
|
4130
4278
|
source: {
|
|
4131
4279
|
type: 'Literal',
|
|
4132
|
-
value:
|
|
4133
|
-
raw: `'${
|
|
4280
|
+
value: source,
|
|
4281
|
+
raw: `'${source}'`,
|
|
4134
4282
|
},
|
|
4135
4283
|
metadata: { path: [] },
|
|
4136
4284
|
});
|
|
@@ -4141,6 +4289,20 @@ function inject_try_imports(program, transform_context, platform, suspense_sourc
|
|
|
4141
4289
|
}
|
|
4142
4290
|
}
|
|
4143
4291
|
|
|
4292
|
+
/**
|
|
4293
|
+
* @param {Map<string, any[]>} imports
|
|
4294
|
+
* @param {string} source
|
|
4295
|
+
* @param {any} specifier
|
|
4296
|
+
*/
|
|
4297
|
+
function add_ref_import_specifier(imports, source, specifier) {
|
|
4298
|
+
const specifiers = imports.get(source);
|
|
4299
|
+
if (specifiers) {
|
|
4300
|
+
specifiers.push(specifier);
|
|
4301
|
+
} else {
|
|
4302
|
+
imports.set(source, [specifier]);
|
|
4303
|
+
}
|
|
4304
|
+
}
|
|
4305
|
+
|
|
4144
4306
|
/**
|
|
4145
4307
|
* @param {any} node
|
|
4146
4308
|
* @param {TransformContext} transform_context
|
|
@@ -4262,6 +4424,8 @@ function create_render_switch_case(switch_case, transform_context) {
|
|
|
4262
4424
|
|
|
4263
4425
|
if (is_jsx_child(child)) {
|
|
4264
4426
|
render_nodes.push(to_jsx_child(child, transform_context));
|
|
4427
|
+
} else if (is_bare_render_expression(child)) {
|
|
4428
|
+
render_nodes.push(to_jsx_expression_container(child, child));
|
|
4265
4429
|
} else {
|
|
4266
4430
|
case_body.push(child);
|
|
4267
4431
|
}
|
|
@@ -4325,6 +4489,8 @@ function to_jsx_expression_container(expression, source_node = expression) {
|
|
|
4325
4489
|
*/
|
|
4326
4490
|
function transform_element_attributes_dispatch(attrs, transform_context, element) {
|
|
4327
4491
|
validate_at_most_one_ref_attribute(attrs, transform_context);
|
|
4492
|
+
const is_component = is_component_like_element(element);
|
|
4493
|
+
attrs = normalize_named_ref_attributes(attrs, !is_component, transform_context);
|
|
4328
4494
|
const preprocess = transform_context.platform.hooks?.preprocessElementAttributes;
|
|
4329
4495
|
if (preprocess) {
|
|
4330
4496
|
attrs = preprocess(attrs, transform_context, element);
|
|
@@ -4333,7 +4499,238 @@ function transform_element_attributes_dispatch(attrs, transform_context, element
|
|
|
4333
4499
|
const result = hook
|
|
4334
4500
|
? hook(attrs, transform_context, element)
|
|
4335
4501
|
: attrs.map((/** @type {any} */ a) => to_jsx_attribute(a, transform_context));
|
|
4336
|
-
return merge_duplicate_refs(
|
|
4502
|
+
return merge_duplicate_refs(
|
|
4503
|
+
normalize_host_ref_spreads(result, !is_component, transform_context),
|
|
4504
|
+
transform_context,
|
|
4505
|
+
);
|
|
4506
|
+
}
|
|
4507
|
+
|
|
4508
|
+
/**
|
|
4509
|
+
* @param {any} element
|
|
4510
|
+
* @returns {boolean}
|
|
4511
|
+
*/
|
|
4512
|
+
function is_component_like_element(element) {
|
|
4513
|
+
const id = element?.id;
|
|
4514
|
+
if (!id) return false;
|
|
4515
|
+
if (id.type === 'Identifier') return /^[A-Z]/.test(id.name);
|
|
4516
|
+
if (id.type === 'JSXIdentifier') return /^[A-Z]/.test(id.name);
|
|
4517
|
+
if (id.type === 'MemberExpression') return true;
|
|
4518
|
+
if (id.type === 'JSXMemberExpression') return true;
|
|
4519
|
+
return false;
|
|
4520
|
+
}
|
|
4521
|
+
|
|
4522
|
+
/**
|
|
4523
|
+
* @param {any} name
|
|
4524
|
+
* @returns {boolean}
|
|
4525
|
+
*/
|
|
4526
|
+
function is_component_like_jsx_name(name) {
|
|
4527
|
+
if (!name) return false;
|
|
4528
|
+
if (name.type === 'JSXIdentifier') return /^[A-Z]/.test(name.name);
|
|
4529
|
+
if (name.type === 'JSXMemberExpression') return true;
|
|
4530
|
+
return false;
|
|
4531
|
+
}
|
|
4532
|
+
|
|
4533
|
+
/**
|
|
4534
|
+
* @param {any[]} attrs
|
|
4535
|
+
* @param {boolean} is_host
|
|
4536
|
+
* @param {TransformContext} transform_context
|
|
4537
|
+
* @returns {any[]}
|
|
4538
|
+
*/
|
|
4539
|
+
function normalize_named_ref_attributes(attrs, is_host, transform_context) {
|
|
4540
|
+
if (!is_host) return attrs;
|
|
4541
|
+
|
|
4542
|
+
return attrs.map((attr) => {
|
|
4543
|
+
if (!is_named_ref_attribute(attr)) {
|
|
4544
|
+
return attr;
|
|
4545
|
+
}
|
|
4546
|
+
|
|
4547
|
+
if (transform_context.typeOnly) {
|
|
4548
|
+
return mark_type_only_named_ref_attribute(attr);
|
|
4549
|
+
}
|
|
4550
|
+
|
|
4551
|
+
return {
|
|
4552
|
+
...attr,
|
|
4553
|
+
metadata: { ...(attr.metadata || {}), from_ref_keyword: true },
|
|
4554
|
+
name:
|
|
4555
|
+
attr.name?.type === 'JSXIdentifier'
|
|
4556
|
+
? { ...attr.name, name: 'ref' }
|
|
4557
|
+
: { type: 'Identifier', name: 'ref', metadata: { path: [] } },
|
|
4558
|
+
};
|
|
4559
|
+
});
|
|
4560
|
+
}
|
|
4561
|
+
|
|
4562
|
+
/**
|
|
4563
|
+
* @param {any} attr
|
|
4564
|
+
* @returns {any}
|
|
4565
|
+
*/
|
|
4566
|
+
function mark_type_only_named_ref_attribute(attr) {
|
|
4567
|
+
return {
|
|
4568
|
+
...attr,
|
|
4569
|
+
name: attr.name
|
|
4570
|
+
? {
|
|
4571
|
+
...attr.name,
|
|
4572
|
+
metadata: { ...(attr.name.metadata || {}), disable_verification: true },
|
|
4573
|
+
}
|
|
4574
|
+
: attr.name,
|
|
4575
|
+
};
|
|
4576
|
+
}
|
|
4577
|
+
|
|
4578
|
+
/**
|
|
4579
|
+
* @param {any[]} attrs
|
|
4580
|
+
* @param {boolean} is_host
|
|
4581
|
+
* @param {TransformContext} transform_context
|
|
4582
|
+
* @returns {any[]}
|
|
4583
|
+
*/
|
|
4584
|
+
function normalize_host_ref_spreads(attrs, is_host, transform_context) {
|
|
4585
|
+
if (!is_host) return attrs;
|
|
4586
|
+
|
|
4587
|
+
const needs_explicit_spread_ref =
|
|
4588
|
+
transform_context.platform.jsx?.hostSpreadRefStrategy === 'explicit-ref-attr';
|
|
4589
|
+
const ref_exprs = attrs
|
|
4590
|
+
.filter((attr) => is_jsx_ref_attribute(attr))
|
|
4591
|
+
.map((attr) => attr.value.expression);
|
|
4592
|
+
const needs_synthetic_spread_ref = needs_explicit_spread_ref || ref_exprs.length > 0;
|
|
4593
|
+
|
|
4594
|
+
return attrs.flatMap((attr) => {
|
|
4595
|
+
if (!attr || attr.type !== 'JSXSpreadAttribute') {
|
|
4596
|
+
return [attr];
|
|
4597
|
+
}
|
|
4598
|
+
|
|
4599
|
+
transform_context.needs_normalize_spread_props = true;
|
|
4600
|
+
const normalized = b.call(NORMALIZE_SPREAD_PROPS_INTERNAL_NAME, attr.argument);
|
|
4601
|
+
|
|
4602
|
+
if (needs_synthetic_spread_ref) {
|
|
4603
|
+
const normalized_id = create_generated_identifier(
|
|
4604
|
+
create_spread_props_name(transform_context),
|
|
4605
|
+
);
|
|
4606
|
+
const spread = {
|
|
4607
|
+
...attr,
|
|
4608
|
+
argument: clone_identifier(normalized_id),
|
|
4609
|
+
};
|
|
4610
|
+
const ref_attr = b.jsx_attribute(
|
|
4611
|
+
b.jsx_id('ref'),
|
|
4612
|
+
to_jsx_expression_container(b.member(clone_identifier(normalized_id), 'ref'), attr),
|
|
4613
|
+
false,
|
|
4614
|
+
attr,
|
|
4615
|
+
);
|
|
4616
|
+
ref_attr.metadata = { ...(ref_attr.metadata || {}) };
|
|
4617
|
+
/** @type {any} */ (ref_attr.metadata).from_ref_keyword = true;
|
|
4618
|
+
add_jsx_setup_declaration(spread, b.let(clone_identifier(normalized_id), normalized));
|
|
4619
|
+
|
|
4620
|
+
return [spread, ref_attr];
|
|
4621
|
+
}
|
|
4622
|
+
|
|
4623
|
+
return [
|
|
4624
|
+
{
|
|
4625
|
+
...attr,
|
|
4626
|
+
argument: normalized,
|
|
4627
|
+
},
|
|
4628
|
+
];
|
|
4629
|
+
});
|
|
4630
|
+
}
|
|
4631
|
+
|
|
4632
|
+
/**
|
|
4633
|
+
* @param {TransformContext} transform_context
|
|
4634
|
+
* @returns {string}
|
|
4635
|
+
*/
|
|
4636
|
+
function create_spread_props_name(transform_context) {
|
|
4637
|
+
if (transform_context.helper_state) {
|
|
4638
|
+
return create_helper_name(transform_context.helper_state, 'spread_props');
|
|
4639
|
+
}
|
|
4640
|
+
|
|
4641
|
+
transform_context.local_statement_component_index += 1;
|
|
4642
|
+
return `_tsrx_spread_props_${transform_context.local_statement_component_index}`;
|
|
4643
|
+
}
|
|
4644
|
+
|
|
4645
|
+
/**
|
|
4646
|
+
* @param {any} node
|
|
4647
|
+
* @param {any} declaration
|
|
4648
|
+
*/
|
|
4649
|
+
export function add_jsx_setup_declaration(node, declaration) {
|
|
4650
|
+
node.metadata ??= { path: [] };
|
|
4651
|
+
(node.metadata.generated_setup_declarations ??= []).push(declaration);
|
|
4652
|
+
}
|
|
4653
|
+
|
|
4654
|
+
/**
|
|
4655
|
+
* @param {any} node
|
|
4656
|
+
* @param {Set<any>} [seen]
|
|
4657
|
+
* @returns {any[]}
|
|
4658
|
+
*/
|
|
4659
|
+
export function extract_jsx_setup_declarations(node, seen = new Set()) {
|
|
4660
|
+
if (node == null || typeof node !== 'object' || seen.has(node)) {
|
|
4661
|
+
return [];
|
|
4662
|
+
}
|
|
4663
|
+
seen.add(node);
|
|
4664
|
+
|
|
4665
|
+
const declarations = node.metadata?.generated_setup_declarations ?? [];
|
|
4666
|
+
if (node.metadata?.generated_setup_declarations) {
|
|
4667
|
+
delete node.metadata.generated_setup_declarations;
|
|
4668
|
+
}
|
|
4669
|
+
|
|
4670
|
+
for (const key of Object.keys(node)) {
|
|
4671
|
+
if (key === 'loc' || key === 'start' || key === 'end' || key === 'metadata') {
|
|
4672
|
+
continue;
|
|
4673
|
+
}
|
|
4674
|
+
declarations.push(...extract_jsx_setup_declarations(node[key], seen));
|
|
4675
|
+
}
|
|
4676
|
+
|
|
4677
|
+
return declarations;
|
|
4678
|
+
}
|
|
4679
|
+
|
|
4680
|
+
/**
|
|
4681
|
+
* @param {any} expression
|
|
4682
|
+
* @param {boolean} in_jsx_child
|
|
4683
|
+
* @returns {any}
|
|
4684
|
+
*/
|
|
4685
|
+
function wrap_jsx_setup_declarations(expression, in_jsx_child) {
|
|
4686
|
+
const declarations = extract_jsx_setup_declarations(expression);
|
|
4687
|
+
if (declarations.length === 0) {
|
|
4688
|
+
return expression;
|
|
4689
|
+
}
|
|
4690
|
+
|
|
4691
|
+
const return_expression =
|
|
4692
|
+
expression?.type === 'JSXExpressionContainer' ? expression.expression : expression;
|
|
4693
|
+
const call = b.call(
|
|
4694
|
+
b.arrow(
|
|
4695
|
+
[],
|
|
4696
|
+
b.block([...declarations, b.return(return_expression)], expression),
|
|
4697
|
+
false,
|
|
4698
|
+
expression,
|
|
4699
|
+
),
|
|
4700
|
+
);
|
|
4701
|
+
|
|
4702
|
+
return in_jsx_child ? to_jsx_expression_container(call, expression) : call;
|
|
4703
|
+
}
|
|
4704
|
+
|
|
4705
|
+
/**
|
|
4706
|
+
* @param {any} attr
|
|
4707
|
+
* @returns {boolean}
|
|
4708
|
+
*/
|
|
4709
|
+
function is_named_ref_attribute(attr) {
|
|
4710
|
+
return !!(
|
|
4711
|
+
attr &&
|
|
4712
|
+
(attr.type === 'Attribute' || attr.type === 'JSXAttribute') &&
|
|
4713
|
+
attr.name &&
|
|
4714
|
+
((attr.name.type === 'Identifier' && attr.name.name !== 'ref') ||
|
|
4715
|
+
(attr.name.type === 'JSXIdentifier' && attr.name.name !== 'ref')) &&
|
|
4716
|
+
(attr.value?.type === 'RefExpression' ||
|
|
4717
|
+
is_ref_prop_expression(attr.value) ||
|
|
4718
|
+
(attr.value?.type === 'JSXExpressionContainer' &&
|
|
4719
|
+
is_ref_prop_expression(attr.value.expression)))
|
|
4720
|
+
);
|
|
4721
|
+
}
|
|
4722
|
+
|
|
4723
|
+
/**
|
|
4724
|
+
* @param {any} expression
|
|
4725
|
+
* @returns {boolean}
|
|
4726
|
+
*/
|
|
4727
|
+
export function is_ref_prop_expression(expression) {
|
|
4728
|
+
return (
|
|
4729
|
+
expression?.type === 'RefExpression' ||
|
|
4730
|
+
(expression?.type === 'CallExpression' &&
|
|
4731
|
+
expression.callee?.type === 'Identifier' &&
|
|
4732
|
+
expression.callee.name === CREATE_REF_PROP_INTERNAL_NAME)
|
|
4733
|
+
);
|
|
4337
4734
|
}
|
|
4338
4735
|
|
|
4339
4736
|
/**
|
|
@@ -4453,7 +4850,7 @@ export function merge_duplicate_refs(jsx_attrs, transform_context) {
|
|
|
4453
4850
|
type: 'CallExpression',
|
|
4454
4851
|
callee: {
|
|
4455
4852
|
type: 'Identifier',
|
|
4456
|
-
name:
|
|
4853
|
+
name: MERGE_REFS_INTERNAL_NAME,
|
|
4457
4854
|
metadata: { path: [] },
|
|
4458
4855
|
},
|
|
4459
4856
|
arguments: ref_exprs,
|
|
@@ -4514,7 +4911,9 @@ function is_jsx_ref_attribute(attr) {
|
|
|
4514
4911
|
* double-underscore matches the convention for compiler-generated
|
|
4515
4912
|
* identifiers and avoids shadowing user-declared `mergeRefs` symbols.
|
|
4516
4913
|
*/
|
|
4517
|
-
const
|
|
4914
|
+
export const MERGE_REFS_INTERNAL_NAME = '__mergeRefs';
|
|
4915
|
+
export const CREATE_REF_PROP_INTERNAL_NAME = '__create_ref_prop';
|
|
4916
|
+
export const NORMALIZE_SPREAD_PROPS_INTERNAL_NAME = '__normalize_spread_props';
|
|
4518
4917
|
|
|
4519
4918
|
/**
|
|
4520
4919
|
* @param {any} attr
|
|
@@ -4523,7 +4922,31 @@ const MERGE_REFS_LOCAL_NAME = '__mergeRefs';
|
|
|
4523
4922
|
*/
|
|
4524
4923
|
export function to_jsx_attribute(attr, transform_context) {
|
|
4525
4924
|
if (!attr) return attr;
|
|
4526
|
-
if (attr.type === 'JSXAttribute'
|
|
4925
|
+
if (attr.type === 'JSXAttribute') {
|
|
4926
|
+
if (
|
|
4927
|
+
attr.value?.type === 'JSXExpressionContainer' &&
|
|
4928
|
+
attr.value.expression?.type === 'RefExpression'
|
|
4929
|
+
) {
|
|
4930
|
+
return {
|
|
4931
|
+
...attr,
|
|
4932
|
+
value: to_jsx_expression_container(
|
|
4933
|
+
create_ref_prop_call(attr.value.expression, transform_context),
|
|
4934
|
+
),
|
|
4935
|
+
metadata: { ...(attr.metadata || {}), from_ref_keyword: true },
|
|
4936
|
+
};
|
|
4937
|
+
}
|
|
4938
|
+
if (
|
|
4939
|
+
attr.value?.type === 'JSXExpressionContainer' &&
|
|
4940
|
+
is_ref_prop_expression(attr.value.expression)
|
|
4941
|
+
) {
|
|
4942
|
+
return {
|
|
4943
|
+
...attr,
|
|
4944
|
+
metadata: { ...(attr.metadata || {}), from_ref_keyword: true },
|
|
4945
|
+
};
|
|
4946
|
+
}
|
|
4947
|
+
return attr;
|
|
4948
|
+
}
|
|
4949
|
+
if (attr.type === 'JSXSpreadAttribute') {
|
|
4527
4950
|
return attr;
|
|
4528
4951
|
}
|
|
4529
4952
|
if (attr.type === 'SpreadAttribute') {
|
|
@@ -4574,15 +4997,28 @@ export function to_jsx_attribute(attr, transform_context) {
|
|
|
4574
4997
|
attr_name && attr_name.type === 'Identifier' ? identifier_to_jsx_name(attr_name) : attr_name;
|
|
4575
4998
|
|
|
4576
4999
|
let value = attr.value;
|
|
5000
|
+
const is_ref_expression_value =
|
|
5001
|
+
value?.type === 'RefExpression' ||
|
|
5002
|
+
is_ref_prop_expression(value) ||
|
|
5003
|
+
(value?.type === 'JSXExpressionContainer' && is_ref_prop_expression(value.expression));
|
|
4577
5004
|
if (value) {
|
|
4578
5005
|
if (value.type === 'Literal' && typeof value.value === 'string') {
|
|
4579
5006
|
// Keep string literal as attribute string.
|
|
5007
|
+
} else if (value.type === 'RefExpression') {
|
|
5008
|
+
value = to_jsx_expression_container(create_ref_prop_call(value, transform_context));
|
|
4580
5009
|
} else if (value.type !== 'JSXExpressionContainer') {
|
|
4581
5010
|
value = to_jsx_expression_container(value);
|
|
5011
|
+
} else if (value.expression?.type === 'RefExpression') {
|
|
5012
|
+
value = to_jsx_expression_container(
|
|
5013
|
+
create_ref_prop_call(value.expression, transform_context),
|
|
5014
|
+
);
|
|
4582
5015
|
}
|
|
4583
5016
|
}
|
|
4584
5017
|
|
|
4585
5018
|
const jsx_attribute = build_jsx_attribute(name, value || null, attr.shorthand === true);
|
|
5019
|
+
if (is_ref_expression_value) {
|
|
5020
|
+
/** @type {any} */ (jsx_attribute.metadata).from_ref_keyword = true;
|
|
5021
|
+
}
|
|
4586
5022
|
|
|
4587
5023
|
if (value_has_unmappable_jsx_loc(value)) {
|
|
4588
5024
|
/** @type {any} */ (jsx_attribute.metadata).has_unmappable_value = true;
|
|
@@ -4604,6 +5040,35 @@ function value_has_unmappable_jsx_loc(value) {
|
|
|
4604
5040
|
);
|
|
4605
5041
|
}
|
|
4606
5042
|
|
|
5043
|
+
/**
|
|
5044
|
+
* @param {any} node
|
|
5045
|
+
* @param {TransformContext} transform_context
|
|
5046
|
+
* @returns {any}
|
|
5047
|
+
*/
|
|
5048
|
+
function create_ref_prop_call(node, transform_context) {
|
|
5049
|
+
transform_context.needs_ref_prop = true;
|
|
5050
|
+
|
|
5051
|
+
const argument = node.argument;
|
|
5052
|
+
const args = [b.thunk(argument)];
|
|
5053
|
+
|
|
5054
|
+
if (argument.type === 'Identifier' || argument.type === 'MemberExpression') {
|
|
5055
|
+
args.push(
|
|
5056
|
+
b.arrow(
|
|
5057
|
+
[b.id('v')],
|
|
5058
|
+
/** @type {any} */ ({
|
|
5059
|
+
type: 'AssignmentExpression',
|
|
5060
|
+
operator: '=',
|
|
5061
|
+
left: clone_expression_node(argument, false),
|
|
5062
|
+
right: b.id('v'),
|
|
5063
|
+
metadata: { path: [] },
|
|
5064
|
+
}),
|
|
5065
|
+
),
|
|
5066
|
+
);
|
|
5067
|
+
}
|
|
5068
|
+
|
|
5069
|
+
return b.call(CREATE_REF_PROP_INTERNAL_NAME, ...args);
|
|
5070
|
+
}
|
|
5071
|
+
|
|
4607
5072
|
/**
|
|
4608
5073
|
* @param {any} node
|
|
4609
5074
|
* @param {TransformContext} transform_context
|