@tsrx/core 0.1.16 → 0.1.17
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/README.md +4 -3
- package/package.json +1 -1
- package/src/analyze/prune.js +13 -28
- package/src/analyze/validation.js +27 -94
- package/src/diagnostics.js +1 -3
- package/src/index.js +18 -28
- package/src/parse/index.js +37 -4
- package/src/plugin.js +182 -644
- package/src/runtime/ref.js +48 -0
- package/src/scope.js +0 -13
- package/src/transform/await.js +1 -1
- package/src/transform/jsx/ast-builders.js +3 -5
- package/src/transform/jsx/helpers.js +1 -2
- package/src/transform/jsx/index.js +1257 -1491
- package/src/transform/lazy.js +6 -6
- package/src/transform/scoping.js +1 -2
- package/src/transform/segments.js +26 -157
- package/src/transform/style-ref.js +235 -0
- package/src/utils/ast.js +15 -23
- package/src/utils/builders.js +0 -18
- package/types/index.d.ts +32 -74
- package/types/jsx-platform.d.ts +20 -28
- package/types/parse.d.ts +2 -15
- package/types/runtime/ref.d.ts +3 -0
|
@@ -37,21 +37,17 @@ import {
|
|
|
37
37
|
} from '../../utils/builders.js';
|
|
38
38
|
import * as b from '../../utils/builders.js';
|
|
39
39
|
import { apply_lazy_transforms, preallocate_lazy_ids } from '../lazy.js';
|
|
40
|
-
import { find_first_top_level_await_in_component_body } from '../await.js';
|
|
41
40
|
import {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
} from '../scoping.js';
|
|
41
|
+
find_first_top_level_await,
|
|
42
|
+
find_first_top_level_await_in_tsrx_function_body,
|
|
43
|
+
} from '../await.js';
|
|
44
|
+
import { prepare_stylesheet_for_render, annotate_with_hash, is_style_element } from '../scoping.js';
|
|
46
45
|
import {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
validate_component_unsupported_loop_statement,
|
|
53
|
-
} from '../../analyze/validation.js';
|
|
54
|
-
import { get_component_from_path, is_function_or_component_node } from '../../utils/ast.js';
|
|
46
|
+
collect_style_ref_attributes,
|
|
47
|
+
create_style_class_map,
|
|
48
|
+
create_style_ref_setup_statements,
|
|
49
|
+
} from '../style-ref.js';
|
|
50
|
+
import { is_function_or_component_node } from '../../utils/ast.js';
|
|
55
51
|
import {
|
|
56
52
|
is_interleaved_body as is_interleaved_body_core,
|
|
57
53
|
is_capturable_jsx_child,
|
|
@@ -66,43 +62,6 @@ const HOOK_CALLBACK_OUTER_MUTATION_ERROR =
|
|
|
66
62
|
const TEMPLATE_FRAGMENT_ERROR =
|
|
67
63
|
'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>.';
|
|
68
64
|
|
|
69
|
-
/**
|
|
70
|
-
* @param {TransformContext} transform_context
|
|
71
|
-
* @returns {string}
|
|
72
|
-
*/
|
|
73
|
-
export function get_invalid_html_child_error_message(transform_context) {
|
|
74
|
-
return `\`{html ...}\` is only supported as the sole child of an element in ${transform_context.platform.name}.`;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* @param {AST.Node} node
|
|
79
|
-
* @param {TransformContext} transform_context
|
|
80
|
-
*/
|
|
81
|
-
function report_invalid_html_child_error(node, transform_context) {
|
|
82
|
-
error(
|
|
83
|
-
get_invalid_html_child_error_message(transform_context),
|
|
84
|
-
transform_context.filename,
|
|
85
|
-
node,
|
|
86
|
-
transform_context.errors,
|
|
87
|
-
transform_context.comments,
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* In loose/editor mode `error(...)` records the diagnostic and continues, so an
|
|
93
|
-
* invalid standalone `{html ...}` child still needs a valid expression node for
|
|
94
|
-
* the virtual TSX output.
|
|
95
|
-
*
|
|
96
|
-
* @param {any} node
|
|
97
|
-
* @param {TransformContext} transform_context
|
|
98
|
-
* @returns {ESTreeJSX.JSXExpressionContainer}
|
|
99
|
-
*/
|
|
100
|
-
export function recover_invalid_html_child(node, transform_context) {
|
|
101
|
-
report_invalid_html_child_error(node, transform_context);
|
|
102
|
-
const expression = set_loc(clone_expression_node(node.expression), node);
|
|
103
|
-
return to_jsx_expression_container(expression, node);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
65
|
/**
|
|
107
66
|
* @param {AST.Node} node
|
|
108
67
|
* @param {TransformContext} transform_context
|
|
@@ -181,60 +140,16 @@ function is_function_or_class_boundary(node) {
|
|
|
181
140
|
);
|
|
182
141
|
}
|
|
183
142
|
|
|
184
|
-
/**
|
|
185
|
-
* @param {any[]} path
|
|
186
|
-
* @returns {boolean}
|
|
187
|
-
*/
|
|
188
|
-
function is_inside_component_for_of(path) {
|
|
189
|
-
for (let i = path.length - 1; i >= 0; i -= 1) {
|
|
190
|
-
const node = path[i];
|
|
191
|
-
if (is_function_or_class_boundary(node) || node?.type === 'Component') {
|
|
192
|
-
return false;
|
|
193
|
-
}
|
|
194
|
-
if (node?.type === 'ForOfStatement') {
|
|
195
|
-
return true;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* @param {any[]} path
|
|
203
|
-
* @returns {boolean}
|
|
204
|
-
*/
|
|
205
|
-
function break_targets_component_loop(path) {
|
|
206
|
-
for (let i = path.length - 1; i >= 0; i -= 1) {
|
|
207
|
-
const node = path[i];
|
|
208
|
-
if (is_function_or_class_boundary(node) || node?.type === 'Component') {
|
|
209
|
-
return false;
|
|
210
|
-
}
|
|
211
|
-
if (node?.type === 'SwitchStatement') {
|
|
212
|
-
return false;
|
|
213
|
-
}
|
|
214
|
-
if (
|
|
215
|
-
node?.type === 'ForOfStatement' ||
|
|
216
|
-
node?.type === 'ForStatement' ||
|
|
217
|
-
node?.type === 'ForInStatement' ||
|
|
218
|
-
node?.type === 'WhileStatement' ||
|
|
219
|
-
node?.type === 'DoWhileStatement'
|
|
220
|
-
) {
|
|
221
|
-
return true;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
return false;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
143
|
/**
|
|
228
144
|
* Build a `transform()` function for a specific JSX platform (React, Preact,
|
|
229
|
-
* Solid). Given a `JsxPlatform` descriptor, returns a transform that
|
|
230
|
-
*
|
|
231
|
-
* TSX module for that platform.
|
|
145
|
+
* Solid). Given a `JsxPlatform` descriptor, returns a transform that lowers
|
|
146
|
+
* native TSRX template nodes into a plain TSX module for that platform.
|
|
232
147
|
*
|
|
233
|
-
* Any `<style>` element declared inside a
|
|
234
|
-
* via `@tsrx/core`'s stylesheet renderer, and returned alongside the JS
|
|
235
|
-
*
|
|
236
|
-
*
|
|
237
|
-
*
|
|
148
|
+
* Any `<style>` element declared inside a TSRX fragment is collected, rendered
|
|
149
|
+
* via `@tsrx/core`'s stylesheet renderer, and returned alongside the JS output
|
|
150
|
+
* so a downstream plugin can inject it. The compiler also augments every
|
|
151
|
+
* non-style Element in that fragment with the stylesheet's hash class so scoped
|
|
152
|
+
* selectors match correctly.
|
|
238
153
|
*
|
|
239
154
|
* @param {JsxPlatform} platform
|
|
240
155
|
* @returns {(ast: AST.Program, source: string, filename?: string, options?: JsxTransformOptions) => JsxTransformResult}
|
|
@@ -249,13 +164,6 @@ export function createJsxTransform(platform) {
|
|
|
249
164
|
*/
|
|
250
165
|
function transform(ast, source, filename, options) {
|
|
251
166
|
const suspense_source = options?.suspenseSource ?? platform.imports.suspense;
|
|
252
|
-
const should_scan_use_server_directive =
|
|
253
|
-
platform.validation.requireUseServerForAwait &&
|
|
254
|
-
(!platform.hooks?.validateComponentAwait ||
|
|
255
|
-
platform.validation.scanUseServerDirectiveForAwaitWithCustomValidator !== false);
|
|
256
|
-
const module_uses_server_directive = should_scan_use_server_directive
|
|
257
|
-
? has_use_server_directive(ast)
|
|
258
|
-
: true;
|
|
259
167
|
const collect = !!(options?.collect || options?.loose);
|
|
260
168
|
/** @type {any[]} */
|
|
261
169
|
const stylesheets = [];
|
|
@@ -267,18 +175,20 @@ export function createJsxTransform(platform) {
|
|
|
267
175
|
needs_error_boundary: false,
|
|
268
176
|
needs_suspense: false,
|
|
269
177
|
needs_merge_refs: false,
|
|
270
|
-
needs_ref_prop: false,
|
|
271
178
|
needs_normalize_spread_props: false,
|
|
179
|
+
needs_normalize_spread_props_for_ref_attr: false,
|
|
272
180
|
needs_fragment: false,
|
|
273
181
|
needs_for_of_iterable: false,
|
|
274
182
|
needs_iteration_value_type: false,
|
|
183
|
+
stylesheets,
|
|
275
184
|
module_scoped_hook_components:
|
|
276
185
|
options?.moduleScopedHookComponents ?? !!platform.hooks?.moduleScopedHookComponents,
|
|
277
186
|
helper_state: null,
|
|
187
|
+
hook_helpers_enabled: false,
|
|
278
188
|
available_bindings: new Map(),
|
|
279
189
|
lazy_next_id: 0,
|
|
280
|
-
current_css_hash: null,
|
|
281
190
|
filename: filename ?? null,
|
|
191
|
+
source,
|
|
282
192
|
collect,
|
|
283
193
|
errors: collect ? options?.errors : undefined,
|
|
284
194
|
comments: options?.comments,
|
|
@@ -293,197 +203,12 @@ export function createJsxTransform(platform) {
|
|
|
293
203
|
}
|
|
294
204
|
|
|
295
205
|
walk(/** @type {any} */ (ast), transform_context, {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
validate_component_loop_return_statement(
|
|
300
|
-
node,
|
|
301
|
-
filename,
|
|
302
|
-
transform_context.errors,
|
|
303
|
-
transform_context.comments,
|
|
304
|
-
);
|
|
305
|
-
} else {
|
|
306
|
-
validate_component_return_statement(
|
|
307
|
-
node,
|
|
308
|
-
filename,
|
|
309
|
-
transform_context.errors,
|
|
310
|
-
transform_context.comments,
|
|
311
|
-
);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
return next();
|
|
316
|
-
},
|
|
317
|
-
|
|
318
|
-
BreakStatement(node, { next, path }) {
|
|
319
|
-
if (get_component_from_path(path) && break_targets_component_loop(path)) {
|
|
320
|
-
validate_component_loop_break_statement(
|
|
321
|
-
node,
|
|
322
|
-
filename,
|
|
323
|
-
transform_context.errors,
|
|
324
|
-
transform_context.comments,
|
|
325
|
-
);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
return next();
|
|
329
|
-
},
|
|
330
|
-
|
|
331
|
-
ForStatement(node, { next, path }) {
|
|
332
|
-
if (get_component_from_path(path)) {
|
|
333
|
-
validate_component_unsupported_loop_statement(
|
|
334
|
-
node,
|
|
335
|
-
filename,
|
|
336
|
-
transform_context.errors,
|
|
337
|
-
transform_context.comments,
|
|
338
|
-
);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
return next();
|
|
342
|
-
},
|
|
343
|
-
|
|
344
|
-
ForInStatement(node, { next, path }) {
|
|
345
|
-
if (get_component_from_path(path)) {
|
|
346
|
-
validate_component_unsupported_loop_statement(
|
|
347
|
-
node,
|
|
348
|
-
filename,
|
|
349
|
-
transform_context.errors,
|
|
350
|
-
transform_context.comments,
|
|
351
|
-
);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
return next();
|
|
355
|
-
},
|
|
356
|
-
|
|
357
|
-
WhileStatement(node, { next, path }) {
|
|
358
|
-
if (get_component_from_path(path)) {
|
|
359
|
-
validate_component_unsupported_loop_statement(
|
|
360
|
-
node,
|
|
361
|
-
filename,
|
|
362
|
-
transform_context.errors,
|
|
363
|
-
transform_context.comments,
|
|
364
|
-
);
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
return next();
|
|
368
|
-
},
|
|
369
|
-
|
|
370
|
-
DoWhileStatement(node, { next, path }) {
|
|
371
|
-
if (get_component_from_path(path)) {
|
|
372
|
-
validate_component_unsupported_loop_statement(
|
|
373
|
-
node,
|
|
374
|
-
filename,
|
|
375
|
-
transform_context.errors,
|
|
376
|
-
transform_context.comments,
|
|
377
|
-
);
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
return next();
|
|
381
|
-
},
|
|
382
|
-
|
|
383
|
-
ClassBody(node, { next }) {
|
|
384
|
-
validate_class_component_declarations(
|
|
385
|
-
/** @type {any} */ (node),
|
|
386
|
-
filename,
|
|
387
|
-
transform_context.errors,
|
|
388
|
-
transform_context.comments,
|
|
389
|
-
);
|
|
390
|
-
return next();
|
|
391
|
-
},
|
|
392
|
-
|
|
393
|
-
Component(node, { next, state }) {
|
|
394
|
-
const as_any = /** @type {any} */ (node);
|
|
395
|
-
|
|
396
|
-
validate_component_params(
|
|
397
|
-
as_any,
|
|
398
|
-
filename,
|
|
399
|
-
transform_context.errors,
|
|
400
|
-
transform_context.comments,
|
|
401
|
-
);
|
|
402
|
-
|
|
403
|
-
const await_expression = find_first_top_level_await_in_component_body(as_any.body || []);
|
|
404
|
-
|
|
405
|
-
if (await_expression) {
|
|
406
|
-
// Let a platform reject component-level await entirely (solid)
|
|
407
|
-
// or customize the error. Otherwise fall back to the default
|
|
408
|
-
// `requireUseServerForAwait` check.
|
|
409
|
-
if (platform.hooks?.validateComponentAwait) {
|
|
410
|
-
platform.hooks.validateComponentAwait(
|
|
411
|
-
await_expression,
|
|
412
|
-
as_any,
|
|
413
|
-
state,
|
|
414
|
-
module_uses_server_directive,
|
|
415
|
-
source,
|
|
416
|
-
);
|
|
417
|
-
} else if (!module_uses_server_directive) {
|
|
418
|
-
error(
|
|
419
|
-
`${platform.name} components can only use \`await\` when the module has a top-level "use server" directive.`,
|
|
420
|
-
state.filename,
|
|
421
|
-
await_expression,
|
|
422
|
-
state.errors,
|
|
423
|
-
state.comments,
|
|
424
|
-
);
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
as_any.metadata = /** @type {any} */ ({
|
|
428
|
-
...(as_any.metadata || {}),
|
|
429
|
-
contains_top_level_await: true,
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
const css = as_any.css;
|
|
434
|
-
if (css) {
|
|
435
|
-
apply_css_definition_metadata(as_any, css);
|
|
436
|
-
stylesheets.push(css);
|
|
437
|
-
const hash = css.hash;
|
|
438
|
-
annotate_component_with_hash(
|
|
439
|
-
as_any,
|
|
440
|
-
hash,
|
|
441
|
-
platform.jsx.rewriteClassAttr ? 'className' : 'class',
|
|
442
|
-
transform_context.typeOnly,
|
|
443
|
-
);
|
|
444
|
-
}
|
|
445
|
-
return next(state);
|
|
446
|
-
},
|
|
206
|
+
FunctionDeclaration: collect_native_function_tsrx_metadata,
|
|
207
|
+
FunctionExpression: collect_native_function_tsrx_metadata,
|
|
208
|
+
ArrowFunctionExpression: collect_native_function_tsrx_metadata,
|
|
447
209
|
});
|
|
448
210
|
|
|
449
211
|
const transformed = walk(/** @type {any} */ (ast), transform_context, {
|
|
450
|
-
Component(node, { next, state }) {
|
|
451
|
-
const as_any = /** @type {any} */ (node);
|
|
452
|
-
|
|
453
|
-
// Set up helper_state and bindings BEFORE next() so that nested
|
|
454
|
-
// hook_safe_* calls (inside Element children) can register helpers
|
|
455
|
-
// and access available bindings during the bottom-up walk.
|
|
456
|
-
const helper_state = create_helper_state(as_any.id?.name || 'Component');
|
|
457
|
-
const saved_helper_state = state.helper_state;
|
|
458
|
-
const saved_bindings = state.available_bindings;
|
|
459
|
-
const saved_css_hash = state.current_css_hash;
|
|
460
|
-
state.helper_state = helper_state;
|
|
461
|
-
state.current_css_hash = as_any.css ? as_any.css.hash : null;
|
|
462
|
-
|
|
463
|
-
// Pre-collect component body bindings (params + top-level statements)
|
|
464
|
-
// so Element children processed during the bottom-up walk can see
|
|
465
|
-
// component-scope names. Hook-safe helpers filter this set down to
|
|
466
|
-
// the names their body actually references before generating props.
|
|
467
|
-
const body_bindings = collect_param_bindings(as_any.params || []);
|
|
468
|
-
const body = as_any.body || [];
|
|
469
|
-
const split_index = find_hook_safe_split_index(body, state);
|
|
470
|
-
const collect_end = split_index === -1 ? body.length : split_index;
|
|
471
|
-
for (let i = 0; i < collect_end; i += 1) {
|
|
472
|
-
collect_statement_bindings(body[i], body_bindings);
|
|
473
|
-
}
|
|
474
|
-
state.available_bindings = body_bindings;
|
|
475
|
-
|
|
476
|
-
const inner = /** @type {any} */ (next() ?? node);
|
|
477
|
-
|
|
478
|
-
// Restore context
|
|
479
|
-
state.helper_state = saved_helper_state;
|
|
480
|
-
state.available_bindings = saved_bindings;
|
|
481
|
-
state.current_css_hash = saved_css_hash;
|
|
482
|
-
|
|
483
|
-
const convert = platform.hooks?.componentToFunction ?? component_to_function_declaration;
|
|
484
|
-
return /** @type {any} */ (convert(inner, state, helper_state));
|
|
485
|
-
},
|
|
486
|
-
|
|
487
212
|
Tsx(node, { next, path }) {
|
|
488
213
|
const inner = /** @type {any} */ (next() ?? node);
|
|
489
214
|
const in_jsx_child = in_jsx_child_context(path);
|
|
@@ -493,7 +218,19 @@ export function createJsxTransform(platform) {
|
|
|
493
218
|
},
|
|
494
219
|
|
|
495
220
|
Tsrx(node, { next, path, state }) {
|
|
496
|
-
|
|
221
|
+
/** @type {{ css: any, style_refs: any[] } | null} */
|
|
222
|
+
let style_context = null;
|
|
223
|
+
const inner = with_tsrx_fragment_styles(node, state, (context) => {
|
|
224
|
+
style_context = context;
|
|
225
|
+
return next() ?? node;
|
|
226
|
+
});
|
|
227
|
+
for (const statement of create_tsrx_style_ref_setup_statements(
|
|
228
|
+
node,
|
|
229
|
+
style_context,
|
|
230
|
+
state,
|
|
231
|
+
)) {
|
|
232
|
+
add_jsx_setup_declaration(inner, statement);
|
|
233
|
+
}
|
|
497
234
|
const in_jsx_child = in_jsx_child_context(path);
|
|
498
235
|
return /** @type {any} */ (
|
|
499
236
|
wrap_jsx_setup_declarations(
|
|
@@ -519,7 +256,9 @@ export function createJsxTransform(platform) {
|
|
|
519
256
|
// platform hook (e.g. Solid's textContent optimization) can
|
|
520
257
|
// inspect the original Text / TSRXExpression nodes rather than
|
|
521
258
|
// their walker-lowered JSXExpressionContainer equivalents.
|
|
522
|
-
const raw_children = /** @type {any} */ (node
|
|
259
|
+
const raw_children = /** @type {any} */ (node.children || []).map(
|
|
260
|
+
(/** @type {any} */ child) => (child && typeof child === 'object' ? { ...child } : child),
|
|
261
|
+
);
|
|
523
262
|
const inner = /** @type {any} */ (next() ?? node);
|
|
524
263
|
const hook = platform.hooks?.transformElement;
|
|
525
264
|
if (hook) return /** @type {any} */ (hook(inner, state, raw_children));
|
|
@@ -538,48 +277,25 @@ export function createJsxTransform(platform) {
|
|
|
538
277
|
return /** @type {any} */ (to_jsx_expression_container(inner.expression, inner));
|
|
539
278
|
},
|
|
540
279
|
|
|
541
|
-
Style(node, { state, path }) {
|
|
542
|
-
validate_style_directive(node, state, path);
|
|
543
|
-
const class_name = typeof node.value.value === 'string' ? node.value.value : '';
|
|
544
|
-
const value = state.current_css_hash
|
|
545
|
-
? `${state.current_css_hash} ${class_name}`
|
|
546
|
-
: class_name;
|
|
547
|
-
return b.literal(value, undefined, node);
|
|
548
|
-
},
|
|
549
|
-
|
|
550
280
|
// Default .metadata on every function-like node so downstream consumers
|
|
551
|
-
//
|
|
552
|
-
//
|
|
553
|
-
//
|
|
554
|
-
//
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
FunctionExpression: transform_function_with_hook_helpers,
|
|
559
|
-
ArrowFunctionExpression: transform_function_with_hook_helpers,
|
|
560
|
-
|
|
561
|
-
RefExpression(node) {
|
|
562
|
-
return create_ref_prop_call(node, transform_context);
|
|
563
|
-
},
|
|
281
|
+
// do not trip on an undefined metadata object. Ripple's analyze phase
|
|
282
|
+
// does this via visit_function; tsrx-react has no analyze phase.
|
|
283
|
+
// If an uppercase JS function contains hook-bearing TSRX, give it a
|
|
284
|
+
// temporary helper scope so extracted hook helpers get stable identities.
|
|
285
|
+
FunctionDeclaration: transform_function,
|
|
286
|
+
FunctionExpression: transform_function,
|
|
287
|
+
ArrowFunctionExpression: transform_function,
|
|
564
288
|
|
|
565
289
|
JSXOpeningElement(node, { next }) {
|
|
566
|
-
const visited = next() || node;
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
visited.attributes || [],
|
|
570
|
-
!is_component,
|
|
571
|
-
transform_context,
|
|
572
|
-
);
|
|
573
|
-
if (transform_context.typeOnly) {
|
|
574
|
-
add_ref_target_type_to_ref_prop_attributes(
|
|
575
|
-
attrs,
|
|
576
|
-
!is_component ? create_element_ref_target_type(visited) : null,
|
|
577
|
-
);
|
|
290
|
+
const visited = /** @type {any} */ (next() || node);
|
|
291
|
+
if (visited.metadata?.native_tsrx_pretransformed) {
|
|
292
|
+
return visited;
|
|
578
293
|
}
|
|
294
|
+
const is_component = is_component_like_jsx_name(visited.name);
|
|
579
295
|
return {
|
|
580
296
|
...visited,
|
|
581
297
|
attributes: merge_duplicate_refs(
|
|
582
|
-
normalize_host_ref_spreads(
|
|
298
|
+
normalize_host_ref_spreads(visited.attributes || [], !is_component, transform_context),
|
|
583
299
|
transform_context,
|
|
584
300
|
),
|
|
585
301
|
};
|
|
@@ -594,9 +310,7 @@ export function createJsxTransform(platform) {
|
|
|
594
310
|
}
|
|
595
311
|
|
|
596
312
|
// Apply lazy destructuring transforms to module-level code (top-level function
|
|
597
|
-
// declarations, arrow functions, etc.).
|
|
598
|
-
// transformed inside component_to_function_declaration; this catches plain
|
|
599
|
-
// functions outside components and any lazy patterns in module scope.
|
|
313
|
+
// declarations, arrow functions, etc.).
|
|
600
314
|
// In type-only mode, the lazy patterns survive untouched: esrap ignores the
|
|
601
315
|
// non-standard `lazy` flag, so `&{ a, b }` prints as `{ a, b }`, `let &[a]
|
|
602
316
|
// = expr` prints as `let [a] = expr`, and the bare statement-level form
|
|
@@ -629,18 +343,30 @@ export function createJsxTransform(platform) {
|
|
|
629
343
|
*
|
|
630
344
|
* @param {any} component
|
|
631
345
|
* @param {any} css
|
|
346
|
+
* @param {boolean} [export_top_scoped_classes]
|
|
632
347
|
* @returns {void}
|
|
633
348
|
*/
|
|
634
|
-
function apply_css_definition_metadata(component, css) {
|
|
349
|
+
function apply_css_definition_metadata(component, css, export_top_scoped_classes = false) {
|
|
635
350
|
analyze_css(css);
|
|
636
351
|
|
|
637
352
|
const metadata = component.metadata || (component.metadata = { path: [] });
|
|
638
353
|
const style_classes = metadata.styleClasses || (metadata.styleClasses = new Map());
|
|
639
354
|
const top_scoped_classes = metadata.topScopedClasses || new Map();
|
|
640
|
-
const elements = collect_css_prunable_elements(component.body || []);
|
|
355
|
+
const elements = collect_css_prunable_elements(component.body || component.children || []);
|
|
641
356
|
|
|
642
|
-
|
|
643
|
-
|
|
357
|
+
const prune = () => {
|
|
358
|
+
for (const element of elements) {
|
|
359
|
+
prune_css(css, element, style_classes, top_scoped_classes);
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
prune();
|
|
364
|
+
|
|
365
|
+
if (export_top_scoped_classes) {
|
|
366
|
+
for (const [class_name, class_info] of top_scoped_classes) {
|
|
367
|
+
style_classes.set(class_name, class_info.selector ?? class_info);
|
|
368
|
+
}
|
|
369
|
+
prune();
|
|
644
370
|
}
|
|
645
371
|
|
|
646
372
|
if (top_scoped_classes.size > 0) {
|
|
@@ -668,8 +394,7 @@ function collect_css_prunable_elements(value, elements = []) {
|
|
|
668
394
|
if (
|
|
669
395
|
value.type === 'FunctionDeclaration' ||
|
|
670
396
|
value.type === 'FunctionExpression' ||
|
|
671
|
-
value.type === 'ArrowFunctionExpression'
|
|
672
|
-
value.type === 'Component'
|
|
397
|
+
value.type === 'ArrowFunctionExpression'
|
|
673
398
|
) {
|
|
674
399
|
return elements;
|
|
675
400
|
}
|
|
@@ -690,127 +415,6 @@ function collect_css_prunable_elements(value, elements = []) {
|
|
|
690
415
|
return elements;
|
|
691
416
|
}
|
|
692
417
|
|
|
693
|
-
/**
|
|
694
|
-
* Detect a top-level `"use server"` directive. Used by platforms whose
|
|
695
|
-
* validation rule requires the directive to enable top-level `await`
|
|
696
|
-
* in components (currently: Preact).
|
|
697
|
-
*
|
|
698
|
-
* @param {AST.Program} program
|
|
699
|
-
* @returns {boolean}
|
|
700
|
-
*/
|
|
701
|
-
function has_use_server_directive(program) {
|
|
702
|
-
for (const statement of program.body || []) {
|
|
703
|
-
const directive = /** @type {any} */ (statement).directive;
|
|
704
|
-
|
|
705
|
-
if (directive === 'use server') {
|
|
706
|
-
return true;
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
if (
|
|
710
|
-
statement.type === 'ExpressionStatement' &&
|
|
711
|
-
statement.expression?.type === 'Literal' &&
|
|
712
|
-
statement.expression.value === 'use server'
|
|
713
|
-
) {
|
|
714
|
-
return true;
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
if (directive == null) {
|
|
718
|
-
break;
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
return false;
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
/**
|
|
726
|
-
* Lower a TSRX `Component` node into the shared function-declaration form used
|
|
727
|
-
* by the default JSX targets. Platform hooks can reuse this helper and wrap the
|
|
728
|
-
* resulting function in another declaration shape without reimplementing
|
|
729
|
-
* component body lowering, lazy destructuring, helper generation, or top-level
|
|
730
|
-
* await handling.
|
|
731
|
-
*
|
|
732
|
-
* @param {any} component
|
|
733
|
-
* @param {TransformContext} transform_context
|
|
734
|
-
* @param {{ base_name: string, next_id: number, helpers: AST.FunctionDeclaration[], statics: any[] }} [walk_helper_state]
|
|
735
|
-
* @returns {AST.FunctionDeclaration | AST.FunctionExpression | AST.ArrowFunctionExpression}
|
|
736
|
-
*/
|
|
737
|
-
export function component_to_function_declaration(component, transform_context, walk_helper_state) {
|
|
738
|
-
const helper_state = walk_helper_state || create_helper_state(component.id?.name || 'Component');
|
|
739
|
-
const params = component.params || [];
|
|
740
|
-
const body = /** @type {any[]} */ (component.body || []);
|
|
741
|
-
const is_async_component =
|
|
742
|
-
!!component?.metadata?.contains_top_level_await ||
|
|
743
|
-
find_first_top_level_await_in_component_body(body) !== null;
|
|
744
|
-
|
|
745
|
-
// Collect param bindings from original patterns (lazy patterns still intact).
|
|
746
|
-
const param_bindings = collect_param_bindings(params);
|
|
747
|
-
|
|
748
|
-
// Save and set context for this component scope
|
|
749
|
-
const saved_helper_state = transform_context.helper_state;
|
|
750
|
-
const saved_bindings = transform_context.available_bindings;
|
|
751
|
-
transform_context.helper_state = helper_state;
|
|
752
|
-
transform_context.available_bindings = new Map(param_bindings);
|
|
753
|
-
|
|
754
|
-
const body_statements = build_component_statements(body, transform_context);
|
|
755
|
-
const body_block = b.block(body_statements);
|
|
756
|
-
|
|
757
|
-
/** @type {AST.FunctionDeclaration | AST.FunctionExpression | AST.ArrowFunctionExpression} */
|
|
758
|
-
let fn;
|
|
759
|
-
|
|
760
|
-
if (component.id) {
|
|
761
|
-
fn = b.function_declaration(
|
|
762
|
-
component.id,
|
|
763
|
-
params,
|
|
764
|
-
body_block,
|
|
765
|
-
is_async_component,
|
|
766
|
-
component.typeParameters,
|
|
767
|
-
);
|
|
768
|
-
} else if (component.metadata?.arrow) {
|
|
769
|
-
fn = b.arrow(params, body_block, is_async_component, component.typeParameters);
|
|
770
|
-
} else {
|
|
771
|
-
fn = b.function(null, params, body_block, is_async_component, component.typeParameters);
|
|
772
|
-
}
|
|
773
|
-
/** @type {any} */ (fn.metadata).is_component = true;
|
|
774
|
-
|
|
775
|
-
// `preallocate_lazy_ids` stamped `has_lazy_descendants` on the source
|
|
776
|
-
// `Component` node; the freshly-built `fn` shares the same params/body
|
|
777
|
-
// subtree, so the flag is equally applicable. Propagating it lets
|
|
778
|
-
// `apply_lazy_transforms` honor its constant-time early-return path.
|
|
779
|
-
if (/** @type {any} */ (component).metadata?.has_lazy_descendants) {
|
|
780
|
-
/** @type {any} */ (fn.metadata).has_lazy_descendants = true;
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
// Apply lazy `&{}` / `&[]` rewrites end-to-end: the function-handler in
|
|
784
|
-
// `apply_lazy_transforms` collects param bindings, merges with body bindings
|
|
785
|
-
// discovered by the BlockStatement handler, replaces lazy params with their
|
|
786
|
-
// `__lazyN` ids, and rewrites every reference. Constant-time fast-path for
|
|
787
|
-
// functions whose subtrees contain no lazy patterns (flagged ahead of time
|
|
788
|
-
// by `preallocate_lazy_ids`). In type-only mode the rewrite is skipped so
|
|
789
|
-
// destructuring patterns survive into the virtual TSX and TypeScript can
|
|
790
|
-
// flow real types.
|
|
791
|
-
if (!transform_context.typeOnly) {
|
|
792
|
-
fn = /** @type {typeof fn} */ (apply_lazy_transforms(fn, new Map()));
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
// Restore context
|
|
796
|
-
transform_context.helper_state = saved_helper_state;
|
|
797
|
-
transform_context.available_bindings = saved_bindings;
|
|
798
|
-
|
|
799
|
-
const fn_metadata = /** @type {any} */ (fn.metadata);
|
|
800
|
-
fn_metadata.generated_helpers = helper_state.helpers;
|
|
801
|
-
fn_metadata.generated_statics = helper_state.statics;
|
|
802
|
-
|
|
803
|
-
if (fn.type === 'FunctionDeclaration' && fn.id) {
|
|
804
|
-
fn.id.metadata = /** @type {AST.Identifier['metadata']} */ ({
|
|
805
|
-
...fn.id.metadata,
|
|
806
|
-
is_component: true,
|
|
807
|
-
});
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
setLocation(fn, /** @type {any} */ (component), true);
|
|
811
|
-
return fn;
|
|
812
|
-
}
|
|
813
|
-
|
|
814
418
|
/**
|
|
815
419
|
* @param {any[]} body_nodes
|
|
816
420
|
* @param {TransformContext} transform_context
|
|
@@ -842,16 +446,12 @@ function build_render_statements(body_nodes, return_null_when_empty, transform_c
|
|
|
842
446
|
// any JSX is constructed, and every JSX child would observe the final
|
|
843
447
|
// state of mutable variables.
|
|
844
448
|
const interleaved = is_interleaved_body(body_nodes);
|
|
845
|
-
const capture_static_early_return_nodes =
|
|
846
|
-
!interleaved &&
|
|
847
|
-
!transform_context.platform.hooks?.isTopLevelSetupCall &&
|
|
848
|
-
body_nodes.filter(is_returning_if_statement).length > 1;
|
|
849
449
|
let capture_index = 0;
|
|
850
450
|
|
|
851
451
|
for (let i = 0; i < body_nodes.length; i += 1) {
|
|
852
452
|
const child = body_nodes[i];
|
|
853
453
|
|
|
854
|
-
if (
|
|
454
|
+
if (is_loop_skip_return_statement(child)) {
|
|
855
455
|
statements.push(create_component_return_statement(render_nodes, child));
|
|
856
456
|
render_nodes.length = 0;
|
|
857
457
|
has_terminal_return = true;
|
|
@@ -864,92 +464,17 @@ function build_render_statements(body_nodes, return_null_when_empty, transform_c
|
|
|
864
464
|
continue;
|
|
865
465
|
}
|
|
866
466
|
|
|
867
|
-
if (
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
transform_context,
|
|
876
|
-
true,
|
|
877
|
-
);
|
|
878
|
-
|
|
879
|
-
if (capture_static_early_return_nodes) {
|
|
880
|
-
capture_index = capture_static_early_return_render_nodes(
|
|
881
|
-
render_nodes,
|
|
882
|
-
statements,
|
|
883
|
-
capture_index,
|
|
884
|
-
transform_context,
|
|
885
|
-
);
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
if (branch_has_hooks || continuation_has_hooks) {
|
|
889
|
-
if (transform_context.platform.hooks?.isTopLevelSetupCall) {
|
|
890
|
-
statements.push(
|
|
891
|
-
...create_setup_once_helper_split_returning_if_statements(
|
|
892
|
-
child,
|
|
893
|
-
body_nodes.slice(i + 1),
|
|
894
|
-
render_nodes,
|
|
895
|
-
transform_context,
|
|
896
|
-
),
|
|
897
|
-
);
|
|
898
|
-
transform_context.available_bindings = saved_bindings;
|
|
899
|
-
return statements;
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
statements.push(
|
|
903
|
-
...create_component_helper_split_returning_if_statements(
|
|
904
|
-
child,
|
|
905
|
-
body_nodes.slice(i + 1),
|
|
906
|
-
render_nodes,
|
|
907
|
-
transform_context,
|
|
908
|
-
),
|
|
467
|
+
if (is_loop_skip_if_statement(child)) {
|
|
468
|
+
if (transform_context.platform.hooks?.isTopLevelSetupCall) {
|
|
469
|
+
const continuation_body = body_nodes.slice(i + 1);
|
|
470
|
+
const continuation_has_setup_statements = continuation_body.some(
|
|
471
|
+
(node) =>
|
|
472
|
+
!is_loop_skip_return_statement(node) &&
|
|
473
|
+
!is_loop_skip_if_statement(node) &&
|
|
474
|
+
!is_jsx_child(node),
|
|
909
475
|
);
|
|
910
|
-
transform_context.available_bindings = saved_bindings;
|
|
911
|
-
return statements;
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
if (is_lone_return_if_statement(child)) {
|
|
915
|
-
// On platforms where setup runs once (Vue Vapor), an early
|
|
916
|
-
// `if (cond) return;` placed at setup level is non-reactive:
|
|
917
|
-
// `cond` is evaluated only when setup runs and never again.
|
|
918
|
-
// Inline the rest of the body as a render-time ternary so the
|
|
919
|
-
// conditional re-evaluates when `cond` changes after mount.
|
|
920
|
-
// React/Preact/Solid re-run the component body on every render,
|
|
921
|
-
// so the old setup-time early return is already reactive there
|
|
922
|
-
// and we keep it to avoid gratuitous output changes.
|
|
923
|
-
if (transform_context.platform.hooks?.isTopLevelSetupCall) {
|
|
924
|
-
const continuation_body = body_nodes.slice(i + 1);
|
|
925
|
-
|
|
926
|
-
// Render-time inlining unconditionally lifts continuation
|
|
927
|
-
// statements (provide/watch/declarations/etc.) into the
|
|
928
|
-
// parent setup, which would run them regardless of the
|
|
929
|
-
// early-return condition — wrong when the user wrote them
|
|
930
|
-
// after `if (cond) return;`. Fall back to helper-split if
|
|
931
|
-
// the continuation has any non-render statements so they
|
|
932
|
-
// stay scoped to the helper's lifecycle.
|
|
933
|
-
const continuation_has_setup_statements = continuation_body.some(
|
|
934
|
-
(node) =>
|
|
935
|
-
!is_bare_return_statement(node) &&
|
|
936
|
-
!is_returning_if_statement(node) &&
|
|
937
|
-
!is_jsx_child(node),
|
|
938
|
-
);
|
|
939
|
-
|
|
940
|
-
if (continuation_has_setup_statements) {
|
|
941
|
-
statements.push(
|
|
942
|
-
...create_setup_once_helper_split_returning_if_statements(
|
|
943
|
-
child,
|
|
944
|
-
continuation_body,
|
|
945
|
-
render_nodes,
|
|
946
|
-
transform_context,
|
|
947
|
-
),
|
|
948
|
-
);
|
|
949
|
-
transform_context.available_bindings = saved_bindings;
|
|
950
|
-
return statements;
|
|
951
|
-
}
|
|
952
476
|
|
|
477
|
+
if (!continuation_has_setup_statements) {
|
|
953
478
|
const continuation_statements = build_render_statements(
|
|
954
479
|
continuation_body,
|
|
955
480
|
false,
|
|
@@ -979,13 +504,10 @@ function build_render_statements(body_nodes, return_null_when_empty, transform_c
|
|
|
979
504
|
|
|
980
505
|
break;
|
|
981
506
|
}
|
|
982
|
-
|
|
983
|
-
statements.push(create_component_lone_return_if_statement(child, render_nodes));
|
|
984
|
-
continue;
|
|
985
507
|
}
|
|
986
508
|
|
|
987
509
|
statements.push(
|
|
988
|
-
|
|
510
|
+
create_component_loop_skip_if_statement(child, render_nodes, transform_context),
|
|
989
511
|
);
|
|
990
512
|
continue;
|
|
991
513
|
}
|
|
@@ -993,6 +515,7 @@ function build_render_statements(body_nodes, return_null_when_empty, transform_c
|
|
|
993
515
|
if (
|
|
994
516
|
child.type === 'ForOfStatement' &&
|
|
995
517
|
!child.await &&
|
|
518
|
+
should_extract_hook_helpers(transform_context) &&
|
|
996
519
|
!transform_context.platform.hooks?.isTopLevelSetupCall &&
|
|
997
520
|
!transform_context.platform.hooks?.controlFlow?.forOf &&
|
|
998
521
|
body_contains_top_level_hook_call(
|
|
@@ -1047,19 +570,60 @@ function build_render_statements(body_nodes, return_null_when_empty, transform_c
|
|
|
1047
570
|
}
|
|
1048
571
|
|
|
1049
572
|
/**
|
|
1050
|
-
* React-specific wrapper around the core `isInterleavedBody` helper that
|
|
1051
|
-
* ignores bare `return` / lone return-if statements. Those are rewriting
|
|
1052
|
-
* signals rather than user-visible side effects, so JSX children around
|
|
1053
|
-
* them don't need capturing.
|
|
1054
|
-
*
|
|
1055
573
|
* @param {any[]} body_nodes
|
|
1056
574
|
* @returns {boolean}
|
|
1057
575
|
*/
|
|
1058
576
|
function is_interleaved_body(body_nodes) {
|
|
1059
|
-
|
|
1060
|
-
|
|
577
|
+
return is_interleaved_body_core(body_nodes, is_jsx_child);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* @param {any} node
|
|
582
|
+
* @param {TransformContext} transform_context
|
|
583
|
+
* @returns {boolean}
|
|
584
|
+
*/
|
|
585
|
+
function function_needs_component_body_hook_split(node, transform_context) {
|
|
586
|
+
return (
|
|
587
|
+
transform_context.platform.hooks?.componentBodyHookHelpers === true &&
|
|
588
|
+
node.body?.type === 'BlockStatement' &&
|
|
589
|
+
find_component_body_hook_split_index(node.body.body || [], transform_context) !== -1
|
|
590
|
+
);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* @param {any} node
|
|
595
|
+
* @param {TransformContext} transform_context
|
|
596
|
+
* @returns {void}
|
|
597
|
+
*/
|
|
598
|
+
function rewrite_component_body_conditional_hook_splits(node, transform_context) {
|
|
599
|
+
if (
|
|
600
|
+
transform_context.platform.hooks?.componentBodyHookHelpers !== true ||
|
|
601
|
+
!should_extract_hook_helpers(transform_context) ||
|
|
602
|
+
node.body?.type !== 'BlockStatement'
|
|
603
|
+
) {
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
const body = node.body.body || [];
|
|
608
|
+
const split_index = find_component_body_hook_split_index(body, transform_context);
|
|
609
|
+
if (split_index === -1) {
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
const split_statement = body[split_index];
|
|
614
|
+
const continuation_body = body.slice(split_index + 1);
|
|
615
|
+
const helper = create_hook_safe_helper(
|
|
616
|
+
continuation_body,
|
|
617
|
+
undefined,
|
|
618
|
+
get_body_source_node(continuation_body) || split_statement,
|
|
619
|
+
transform_context,
|
|
1061
620
|
);
|
|
1062
|
-
|
|
621
|
+
|
|
622
|
+
node.body.body = [
|
|
623
|
+
...body.slice(0, split_index + 1),
|
|
624
|
+
...helper.setup_statements,
|
|
625
|
+
set_loc(b.return(helper.component_element), split_statement),
|
|
626
|
+
];
|
|
1063
627
|
}
|
|
1064
628
|
|
|
1065
629
|
/**
|
|
@@ -1067,9 +631,9 @@ function is_interleaved_body(body_nodes) {
|
|
|
1067
631
|
* @param {TransformContext} transform_context
|
|
1068
632
|
* @returns {number}
|
|
1069
633
|
*/
|
|
1070
|
-
function
|
|
634
|
+
function find_component_body_hook_split_index(body_nodes, transform_context) {
|
|
1071
635
|
for (let i = 0; i < body_nodes.length; i += 1) {
|
|
1072
|
-
if (!
|
|
636
|
+
if (!is_component_body_conditional_return_statement(body_nodes[i])) {
|
|
1073
637
|
continue;
|
|
1074
638
|
}
|
|
1075
639
|
|
|
@@ -1081,56 +645,120 @@ function find_hook_safe_split_index(body_nodes, transform_context) {
|
|
|
1081
645
|
return -1;
|
|
1082
646
|
}
|
|
1083
647
|
|
|
1084
|
-
/**
|
|
1085
|
-
* @param {any[]} body_nodes
|
|
1086
|
-
* @param {TransformContext} transform_context
|
|
1087
|
-
* @param {boolean} include_platform_setup
|
|
1088
|
-
* @returns {boolean}
|
|
1089
|
-
*/
|
|
1090
|
-
function body_contains_top_level_hook_call(
|
|
1091
|
-
body_nodes,
|
|
1092
|
-
transform_context,
|
|
1093
|
-
include_platform_setup = false,
|
|
1094
|
-
) {
|
|
1095
|
-
return body_nodes.some((node) =>
|
|
1096
|
-
statement_contains_top_level_hook_call(node, transform_context, include_platform_setup),
|
|
1097
|
-
);
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
648
|
/**
|
|
1101
649
|
* @param {any} node
|
|
1102
|
-
* @param {TransformContext} transform_context
|
|
1103
|
-
* @param {boolean} include_platform_setup
|
|
1104
650
|
* @returns {boolean}
|
|
1105
651
|
*/
|
|
1106
|
-
function
|
|
1107
|
-
|
|
652
|
+
function is_component_body_conditional_return_statement(node) {
|
|
653
|
+
if (node?.type !== 'IfStatement') {
|
|
654
|
+
return false;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
return (
|
|
658
|
+
statement_contains_component_body_return(node.consequent) ||
|
|
659
|
+
statement_contains_component_body_return(node.alternate)
|
|
660
|
+
);
|
|
1108
661
|
}
|
|
1109
662
|
|
|
1110
663
|
/**
|
|
1111
664
|
* @param {any} node
|
|
1112
|
-
* @param {boolean} inside_nested_function
|
|
1113
|
-
* @param {TransformContext} transform_context
|
|
1114
|
-
* @param {boolean} include_platform_setup
|
|
1115
665
|
* @returns {boolean}
|
|
1116
666
|
*/
|
|
1117
|
-
function
|
|
1118
|
-
node,
|
|
1119
|
-
inside_nested_function,
|
|
1120
|
-
transform_context,
|
|
1121
|
-
include_platform_setup,
|
|
1122
|
-
) {
|
|
667
|
+
function statement_contains_component_body_return(node) {
|
|
1123
668
|
if (!node || typeof node !== 'object') {
|
|
1124
669
|
return false;
|
|
1125
670
|
}
|
|
1126
671
|
|
|
1127
|
-
if (
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
672
|
+
if (node.type === 'ReturnStatement') {
|
|
673
|
+
return true;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
if (is_function_or_class_boundary(node)) {
|
|
677
|
+
return false;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
if (Array.isArray(node)) {
|
|
681
|
+
return node.some(statement_contains_component_body_return);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
if (node.type === 'BlockStatement') {
|
|
685
|
+
return (node.body || []).some(statement_contains_component_body_return);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
if (node.type === 'IfStatement') {
|
|
689
|
+
return (
|
|
690
|
+
statement_contains_component_body_return(node.consequent) ||
|
|
691
|
+
statement_contains_component_body_return(node.alternate)
|
|
692
|
+
);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
if (node.type === 'SwitchStatement') {
|
|
696
|
+
return (node.cases || []).some((/** @type {any} */ switch_case) =>
|
|
697
|
+
statement_contains_component_body_return(switch_case.consequent || []),
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
if (node.type === 'TryStatement') {
|
|
702
|
+
return (
|
|
703
|
+
statement_contains_component_body_return(node.block) ||
|
|
704
|
+
statement_contains_component_body_return(node.handler?.body) ||
|
|
705
|
+
statement_contains_component_body_return(node.finalizer)
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
return false;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
/**
|
|
713
|
+
* @param {any[]} body_nodes
|
|
714
|
+
* @param {TransformContext} transform_context
|
|
715
|
+
* @param {boolean} include_platform_setup
|
|
716
|
+
* @returns {boolean}
|
|
717
|
+
*/
|
|
718
|
+
function body_contains_top_level_hook_call(
|
|
719
|
+
body_nodes,
|
|
720
|
+
transform_context,
|
|
721
|
+
include_platform_setup = false,
|
|
722
|
+
) {
|
|
723
|
+
return body_nodes.some((node) =>
|
|
724
|
+
statement_contains_top_level_hook_call(node, transform_context, include_platform_setup),
|
|
725
|
+
);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
/**
|
|
729
|
+
* @param {any} node
|
|
730
|
+
* @param {TransformContext} transform_context
|
|
731
|
+
* @param {boolean} include_platform_setup
|
|
732
|
+
* @returns {boolean}
|
|
733
|
+
*/
|
|
734
|
+
function statement_contains_top_level_hook_call(node, transform_context, include_platform_setup) {
|
|
735
|
+
return node_contains_top_level_hook_call(node, false, transform_context, include_platform_setup);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* @param {any} node
|
|
740
|
+
* @param {boolean} inside_nested_function
|
|
741
|
+
* @param {TransformContext} transform_context
|
|
742
|
+
* @param {boolean} include_platform_setup
|
|
743
|
+
* @returns {boolean}
|
|
744
|
+
*/
|
|
745
|
+
function node_contains_top_level_hook_call(
|
|
746
|
+
node,
|
|
747
|
+
inside_nested_function,
|
|
748
|
+
transform_context,
|
|
749
|
+
include_platform_setup,
|
|
750
|
+
) {
|
|
751
|
+
if (!node || typeof node !== 'object') {
|
|
752
|
+
return false;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
if (
|
|
756
|
+
inside_nested_function &&
|
|
757
|
+
(node.type === 'FunctionDeclaration' ||
|
|
758
|
+
node.type === 'FunctionExpression' ||
|
|
759
|
+
node.type === 'ArrowFunctionExpression')
|
|
760
|
+
) {
|
|
761
|
+
return false;
|
|
1134
762
|
}
|
|
1135
763
|
|
|
1136
764
|
if (
|
|
@@ -1280,85 +908,834 @@ function create_helper_component_element(helper_id, bindings, source_node, mappi
|
|
|
1280
908
|
mapWrapper ? set_loc(opening_element, source_node) : opening_element,
|
|
1281
909
|
);
|
|
1282
910
|
|
|
1283
|
-
return mapWrapper ? set_loc(element, source_node) : element;
|
|
911
|
+
return mapWrapper ? set_loc(element, source_node) : element;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* @param {{ base_name: string, next_id: number, helpers: any[], statics: any[] }} helper_state
|
|
916
|
+
* @param {string} suffix
|
|
917
|
+
* @returns {string}
|
|
918
|
+
*/
|
|
919
|
+
function create_helper_name(helper_state, suffix) {
|
|
920
|
+
helper_state.next_id += 1;
|
|
921
|
+
return `${helper_state.base_name}__${suffix}${helper_state.next_id}`;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
/**
|
|
925
|
+
* @param {string} base_name
|
|
926
|
+
* @returns {{ base_name: string, next_id: number, helpers: any[], statics: any[] }}
|
|
927
|
+
*/
|
|
928
|
+
function create_helper_state(base_name) {
|
|
929
|
+
return {
|
|
930
|
+
base_name,
|
|
931
|
+
next_id: 0,
|
|
932
|
+
helpers: [],
|
|
933
|
+
statics: [],
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
/**
|
|
938
|
+
* @param {any} node
|
|
939
|
+
* @param {{ next: (state?: TransformContext) => any, state: TransformContext }} context
|
|
940
|
+
* @returns {any}
|
|
941
|
+
*/
|
|
942
|
+
function collect_native_function_tsrx_metadata(node, { next, state }) {
|
|
943
|
+
if (!function_has_native_tsrx_return(node)) {
|
|
944
|
+
return next(state);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
node.metadata = {
|
|
948
|
+
...(node.metadata || {}),
|
|
949
|
+
native_tsrx_function: true,
|
|
950
|
+
};
|
|
951
|
+
|
|
952
|
+
return next(state);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
/**
|
|
956
|
+
* @param {any} node
|
|
957
|
+
* @param {{ next: () => any, state: TransformContext, path: AST.Node[] }} context
|
|
958
|
+
* @returns {any}
|
|
959
|
+
*/
|
|
960
|
+
function transform_function(node, context) {
|
|
961
|
+
if (node.metadata?.native_tsrx_function || function_has_native_tsrx_return(node)) {
|
|
962
|
+
return transform_native_tsrx_function(node, context);
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
return transform_function_with_hook_helpers(node, context);
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
/**
|
|
969
|
+
* @param {any} node
|
|
970
|
+
* @param {{ next: () => any, state: TransformContext, path: AST.Node[] }} context
|
|
971
|
+
* @returns {any}
|
|
972
|
+
*/
|
|
973
|
+
function transform_native_tsrx_function(node, { next, state, path }) {
|
|
974
|
+
const helper_state =
|
|
975
|
+
state.helper_state || create_helper_state(get_function_helper_base_name(node, path));
|
|
976
|
+
const saved_helper_state = state.helper_state;
|
|
977
|
+
const saved_bindings = state.available_bindings;
|
|
978
|
+
const saved_hook_helpers_enabled = state.hook_helpers_enabled;
|
|
979
|
+
|
|
980
|
+
state.helper_state = helper_state;
|
|
981
|
+
state.hook_helpers_enabled = is_uppercase_function_like(node, path);
|
|
982
|
+
state.available_bindings = merge_binding_maps(
|
|
983
|
+
saved_bindings,
|
|
984
|
+
collect_function_scope_bindings(node),
|
|
985
|
+
);
|
|
986
|
+
|
|
987
|
+
validate_native_tsrx_function_await(node, state);
|
|
988
|
+
expand_native_tsrx_function_returns(node, state);
|
|
989
|
+
rewrite_component_body_conditional_hook_splits(node, state);
|
|
990
|
+
|
|
991
|
+
const inner = /** @type {any} */ (next() ?? node);
|
|
992
|
+
|
|
993
|
+
state.helper_state = saved_helper_state;
|
|
994
|
+
state.available_bindings = saved_bindings;
|
|
995
|
+
state.hook_helpers_enabled = saved_hook_helpers_enabled;
|
|
996
|
+
|
|
997
|
+
ensure_function_metadata(inner, { next: () => inner });
|
|
998
|
+
inner.metadata = {
|
|
999
|
+
...(inner.metadata || {}),
|
|
1000
|
+
native_tsrx_function: true,
|
|
1001
|
+
};
|
|
1002
|
+
if (!saved_helper_state && (helper_state.helpers.length || helper_state.statics.length)) {
|
|
1003
|
+
inner.metadata.generated_helpers = helper_state.helpers;
|
|
1004
|
+
inner.metadata.generated_statics = helper_state.statics;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
const wrapped = state.platform.hooks?.wrapNativeFunctionComponent?.(inner, state, path);
|
|
1008
|
+
if (wrapped) {
|
|
1009
|
+
return wrapped;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
return inner;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
/**
|
|
1016
|
+
* @param {any} node
|
|
1017
|
+
* @param {TransformContext} transform_context
|
|
1018
|
+
* @returns {void}
|
|
1019
|
+
*/
|
|
1020
|
+
function validate_native_tsrx_function_await(node, transform_context) {
|
|
1021
|
+
const await_node = find_first_top_level_await_in_native_tsrx_function(node);
|
|
1022
|
+
if (!await_node) {
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
const validator = transform_context.platform.hooks?.validateComponentAwait;
|
|
1027
|
+
if (validator) {
|
|
1028
|
+
validator(await_node, node, transform_context, false, transform_context.source || '');
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
if (transform_context.platform.validation.requireUseServerForAwait) {
|
|
1033
|
+
error(
|
|
1034
|
+
'Top-level `await` in TSRX functions requires a module-level `"use server"` directive.',
|
|
1035
|
+
transform_context.filename,
|
|
1036
|
+
await_node,
|
|
1037
|
+
transform_context.errors,
|
|
1038
|
+
transform_context.comments,
|
|
1039
|
+
);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
/**
|
|
1044
|
+
* @param {any} node
|
|
1045
|
+
* @returns {any | null}
|
|
1046
|
+
*/
|
|
1047
|
+
function find_first_top_level_await_in_native_tsrx_function(node) {
|
|
1048
|
+
if (
|
|
1049
|
+
node.type === 'ArrowFunctionExpression' &&
|
|
1050
|
+
node.body?.type !== 'BlockStatement' &&
|
|
1051
|
+
node_contains_native_tsrx_template(node.body)
|
|
1052
|
+
) {
|
|
1053
|
+
return find_first_top_level_await(node.body, false);
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
const body = node.body?.type === 'BlockStatement' ? node.body.body || [] : [];
|
|
1057
|
+
return find_first_top_level_await_in_native_tsrx_statements(body);
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
/**
|
|
1061
|
+
* @param {any[]} statements
|
|
1062
|
+
* @returns {any | null}
|
|
1063
|
+
*/
|
|
1064
|
+
function find_first_top_level_await_in_native_tsrx_statements(statements) {
|
|
1065
|
+
for (const statement of statements) {
|
|
1066
|
+
const found = find_first_top_level_await_in_native_tsrx_statement(statement);
|
|
1067
|
+
if (found) return found;
|
|
1068
|
+
}
|
|
1069
|
+
return null;
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
/**
|
|
1073
|
+
* @param {any} statement
|
|
1074
|
+
* @returns {any | null}
|
|
1075
|
+
*/
|
|
1076
|
+
function find_first_top_level_await_in_native_tsrx_statement(statement) {
|
|
1077
|
+
if (!statement || typeof statement !== 'object') return null;
|
|
1078
|
+
|
|
1079
|
+
if (statement.type === 'ReturnStatement' && statement.argument?.type === 'Tsrx') {
|
|
1080
|
+
return find_first_top_level_await_in_tsrx_function_body(statement.argument.children || []);
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
if (
|
|
1084
|
+
statement.type === 'ReturnStatement' &&
|
|
1085
|
+
node_contains_native_tsrx_template(statement.argument)
|
|
1086
|
+
) {
|
|
1087
|
+
return find_first_top_level_await(statement.argument, false);
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
if (is_function_or_class_boundary(statement)) {
|
|
1091
|
+
return null;
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
if (statement.type === 'BlockStatement') {
|
|
1095
|
+
return find_first_top_level_await_in_native_tsrx_statements(statement.body || []);
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
if (statement.type === 'IfStatement') {
|
|
1099
|
+
return (
|
|
1100
|
+
find_first_top_level_await_in_native_tsrx_statement(statement.consequent) ||
|
|
1101
|
+
find_first_top_level_await_in_native_tsrx_statement(statement.alternate)
|
|
1102
|
+
);
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
if (statement.type === 'SwitchStatement') {
|
|
1106
|
+
for (const switch_case of statement.cases || []) {
|
|
1107
|
+
const found = find_first_top_level_await_in_native_tsrx_statements(
|
|
1108
|
+
switch_case.consequent || [],
|
|
1109
|
+
);
|
|
1110
|
+
if (found) return found;
|
|
1111
|
+
}
|
|
1112
|
+
return null;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
if (statement.type === 'TryStatement') {
|
|
1116
|
+
return (
|
|
1117
|
+
find_first_top_level_await_in_native_tsrx_statement(statement.block) ||
|
|
1118
|
+
find_first_top_level_await_in_native_tsrx_statement(statement.handler?.body) ||
|
|
1119
|
+
find_first_top_level_await_in_native_tsrx_statement(statement.finalizer)
|
|
1120
|
+
);
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
return null;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
/**
|
|
1127
|
+
* @param {any} node
|
|
1128
|
+
* @param {{ next: () => any, state: TransformContext, path: AST.Node[] }} context
|
|
1129
|
+
* @returns {any}
|
|
1130
|
+
*/
|
|
1131
|
+
function transform_function_with_hook_helpers(node, { next, state, path }) {
|
|
1132
|
+
const has_hook_bearing_tsrx = function_contains_hook_bearing_tsrx(node, state);
|
|
1133
|
+
const has_component_body_hook_split = function_needs_component_body_hook_split(node, state);
|
|
1134
|
+
if (
|
|
1135
|
+
state.helper_state ||
|
|
1136
|
+
!is_uppercase_function_like(node, path) ||
|
|
1137
|
+
(!has_hook_bearing_tsrx && !has_component_body_hook_split)
|
|
1138
|
+
) {
|
|
1139
|
+
return ensure_function_metadata(node, { next });
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
const helper_state = create_helper_state(get_function_helper_base_name(node, path));
|
|
1143
|
+
const saved_helper_state = state.helper_state;
|
|
1144
|
+
const saved_bindings = state.available_bindings;
|
|
1145
|
+
const saved_hook_helpers_enabled = state.hook_helpers_enabled;
|
|
1146
|
+
|
|
1147
|
+
state.helper_state = helper_state;
|
|
1148
|
+
state.hook_helpers_enabled = true;
|
|
1149
|
+
state.available_bindings = collect_function_scope_bindings(node);
|
|
1150
|
+
|
|
1151
|
+
if (has_component_body_hook_split) {
|
|
1152
|
+
rewrite_component_body_conditional_hook_splits(node, state);
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
const inner = /** @type {any} */ (next() ?? node);
|
|
1156
|
+
|
|
1157
|
+
state.helper_state = saved_helper_state;
|
|
1158
|
+
state.available_bindings = saved_bindings;
|
|
1159
|
+
state.hook_helpers_enabled = saved_hook_helpers_enabled;
|
|
1160
|
+
|
|
1161
|
+
ensure_function_metadata(inner, { next: () => inner });
|
|
1162
|
+
if (helper_state.helpers.length || helper_state.statics.length) {
|
|
1163
|
+
inner.metadata = {
|
|
1164
|
+
...(inner.metadata || {}),
|
|
1165
|
+
generated_helpers: helper_state.helpers,
|
|
1166
|
+
generated_statics: helper_state.statics,
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
return inner;
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
/**
|
|
1174
|
+
* @param {any} node
|
|
1175
|
+
* @param {AST.Node[]} [path]
|
|
1176
|
+
* @returns {string}
|
|
1177
|
+
*/
|
|
1178
|
+
function get_function_helper_base_name(node, path = []) {
|
|
1179
|
+
return get_function_like_name(node, path) || 'Tsrx';
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
/**
|
|
1183
|
+
* @param {any} node
|
|
1184
|
+
* @param {AST.Node[]} path
|
|
1185
|
+
* @returns {boolean}
|
|
1186
|
+
*/
|
|
1187
|
+
function is_uppercase_function_like(node, path) {
|
|
1188
|
+
const name = get_function_like_name(node, path);
|
|
1189
|
+
return !!(name && /^[A-Z]/.test(name));
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
/**
|
|
1193
|
+
* @param {any} node
|
|
1194
|
+
* @param {AST.Node[]} path
|
|
1195
|
+
* @returns {string | null}
|
|
1196
|
+
*/
|
|
1197
|
+
function get_function_like_name(node, path) {
|
|
1198
|
+
if (node.id?.type === 'Identifier') {
|
|
1199
|
+
return node.id.name;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
const parent = /** @type {any} */ (path.at(-1));
|
|
1203
|
+
if (!parent) return null;
|
|
1204
|
+
|
|
1205
|
+
if (parent.type === 'VariableDeclarator' && parent.init === node) {
|
|
1206
|
+
return get_static_binding_name(parent.id);
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
if (parent.type === 'Property' && parent.value === node) {
|
|
1210
|
+
return get_static_property_name(parent.key);
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
if (parent.type === 'MethodDefinition' && parent.value === node) {
|
|
1214
|
+
return get_static_property_name(parent.key);
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
if (parent.type === 'AssignmentExpression' && parent.right === node) {
|
|
1218
|
+
return get_static_binding_name(parent.left);
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
return null;
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
/**
|
|
1225
|
+
* @param {any} node
|
|
1226
|
+
* @returns {string | null}
|
|
1227
|
+
*/
|
|
1228
|
+
function get_static_binding_name(node) {
|
|
1229
|
+
if (node?.type === 'Identifier') {
|
|
1230
|
+
return node.name;
|
|
1231
|
+
}
|
|
1232
|
+
if (node?.type === 'MemberExpression' && !node.computed) {
|
|
1233
|
+
return get_static_property_name(node.property);
|
|
1234
|
+
}
|
|
1235
|
+
return null;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
/**
|
|
1239
|
+
* @param {any} key
|
|
1240
|
+
* @returns {string | null}
|
|
1241
|
+
*/
|
|
1242
|
+
function get_static_property_name(key) {
|
|
1243
|
+
if (key?.type === 'Identifier') {
|
|
1244
|
+
return key.name;
|
|
1245
|
+
}
|
|
1246
|
+
if (key?.type === 'Literal' && typeof key.value === 'string') {
|
|
1247
|
+
return key.value;
|
|
1248
|
+
}
|
|
1249
|
+
return null;
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
/**
|
|
1253
|
+
* @param {any} node
|
|
1254
|
+
* @returns {Map<string, AST.Identifier>}
|
|
1255
|
+
*/
|
|
1256
|
+
function collect_function_scope_bindings(node) {
|
|
1257
|
+
const bindings = collect_param_bindings(node.params || []);
|
|
1258
|
+
if (node.body?.type === 'BlockStatement') {
|
|
1259
|
+
for (const statement of node.body.body || []) {
|
|
1260
|
+
if (statement.type === 'ReturnStatement' && statement.argument?.type === 'Tsrx') {
|
|
1261
|
+
for (const child of get_tsrx_render_children(statement.argument)) {
|
|
1262
|
+
collect_statement_bindings(child, bindings);
|
|
1263
|
+
}
|
|
1264
|
+
} else {
|
|
1265
|
+
collect_statement_bindings(statement, bindings);
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
return bindings;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
/**
|
|
1273
|
+
* @param {Map<string, AST.Identifier>} outer
|
|
1274
|
+
* @param {Map<string, AST.Identifier>} inner
|
|
1275
|
+
* @returns {Map<string, AST.Identifier>}
|
|
1276
|
+
*/
|
|
1277
|
+
function merge_binding_maps(outer, inner) {
|
|
1278
|
+
const merged = new Map(outer);
|
|
1279
|
+
for (const [name, binding] of inner) {
|
|
1280
|
+
merged.set(name, binding);
|
|
1281
|
+
}
|
|
1282
|
+
return merged;
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
/**
|
|
1286
|
+
* @param {any} node
|
|
1287
|
+
* @returns {boolean}
|
|
1288
|
+
*/
|
|
1289
|
+
function function_has_native_tsrx_return(node) {
|
|
1290
|
+
if (!node) return false;
|
|
1291
|
+
|
|
1292
|
+
if (node.type === 'ArrowFunctionExpression' && node.body?.type !== 'BlockStatement') {
|
|
1293
|
+
return node_contains_native_tsrx_template(node.body);
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
const body = node.body?.type === 'BlockStatement' ? node.body.body : [];
|
|
1297
|
+
return statements_contain_native_tsrx_return(body);
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
/**
|
|
1301
|
+
* @param {any[]} statements
|
|
1302
|
+
* @returns {boolean}
|
|
1303
|
+
*/
|
|
1304
|
+
function statements_contain_native_tsrx_return(statements) {
|
|
1305
|
+
return statements.some((statement) => statement_contains_native_tsrx_return(statement));
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
/**
|
|
1309
|
+
* @param {any} statement
|
|
1310
|
+
* @returns {boolean}
|
|
1311
|
+
*/
|
|
1312
|
+
function statement_contains_native_tsrx_return(statement) {
|
|
1313
|
+
if (!statement || typeof statement !== 'object') return false;
|
|
1314
|
+
|
|
1315
|
+
if (statement.type === 'ReturnStatement') {
|
|
1316
|
+
return node_contains_native_tsrx_template(statement.argument);
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
if (is_function_or_class_boundary(statement)) {
|
|
1320
|
+
return false;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
if (statement.type === 'BlockStatement') {
|
|
1324
|
+
return statements_contain_native_tsrx_return(statement.body || []);
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
if (statement.type === 'IfStatement') {
|
|
1328
|
+
return (
|
|
1329
|
+
statement_contains_native_tsrx_return(statement.consequent) ||
|
|
1330
|
+
statement_contains_native_tsrx_return(statement.alternate)
|
|
1331
|
+
);
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
if (statement.type === 'SwitchStatement') {
|
|
1335
|
+
return (statement.cases || []).some((/** @type {any} */ c) =>
|
|
1336
|
+
statements_contain_native_tsrx_return(c.consequent || []),
|
|
1337
|
+
);
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
if (statement.type === 'TryStatement') {
|
|
1341
|
+
return (
|
|
1342
|
+
statement_contains_native_tsrx_return(statement.block) ||
|
|
1343
|
+
statement_contains_native_tsrx_return(statement.handler?.body) ||
|
|
1344
|
+
statement_contains_native_tsrx_return(statement.finalizer)
|
|
1345
|
+
);
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
for (const key of Object.keys(statement)) {
|
|
1349
|
+
if (key === 'loc' || key === 'start' || key === 'end' || key === 'metadata') {
|
|
1350
|
+
continue;
|
|
1351
|
+
}
|
|
1352
|
+
const value = statement[key];
|
|
1353
|
+
if (Array.isArray(value)) {
|
|
1354
|
+
if (statements_contain_native_tsrx_return(value)) return true;
|
|
1355
|
+
} else if (statement_contains_native_tsrx_return(value)) {
|
|
1356
|
+
return true;
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
return false;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
/**
|
|
1364
|
+
* @param {any} node
|
|
1365
|
+
* @returns {boolean}
|
|
1366
|
+
*/
|
|
1367
|
+
function node_contains_native_tsrx_template(node) {
|
|
1368
|
+
if (!node || typeof node !== 'object') return false;
|
|
1369
|
+
if (node.type === 'Element' || node.type === 'Tsrx') return true;
|
|
1370
|
+
|
|
1371
|
+
if (is_function_or_class_boundary(node)) {
|
|
1372
|
+
return false;
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
if (Array.isArray(node)) {
|
|
1376
|
+
return node.some(node_contains_native_tsrx_template);
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
for (const key of Object.keys(node)) {
|
|
1380
|
+
if (key === 'loc' || key === 'start' || key === 'end' || key === 'metadata') {
|
|
1381
|
+
continue;
|
|
1382
|
+
}
|
|
1383
|
+
if (node_contains_native_tsrx_template(node[key])) {
|
|
1384
|
+
return true;
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
return false;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
/**
|
|
1392
|
+
* @param {any} node
|
|
1393
|
+
* @returns {any}
|
|
1394
|
+
*/
|
|
1395
|
+
function collect_tsrx_stylesheet(node) {
|
|
1396
|
+
/** @type {any[]} */
|
|
1397
|
+
const styles = [];
|
|
1398
|
+
collect_style_elements(node.children || [], styles);
|
|
1399
|
+
|
|
1400
|
+
if (styles.length === 0) return null;
|
|
1401
|
+
if (styles.length > 1) {
|
|
1402
|
+
throw new Error('TSRX fragments can only have one style tag');
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
return styles[0];
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
/**
|
|
1409
|
+
* @param {any} node
|
|
1410
|
+
* @param {TransformContext} transform_context
|
|
1411
|
+
* @returns {{ css: any, style_refs: any[] } | null}
|
|
1412
|
+
*/
|
|
1413
|
+
function prepare_tsrx_fragment_styles(node, transform_context) {
|
|
1414
|
+
const css = collect_tsrx_stylesheet(node);
|
|
1415
|
+
if (!css) return null;
|
|
1416
|
+
|
|
1417
|
+
const style_refs = collect_style_ref_attributes(node);
|
|
1418
|
+
apply_css_definition_metadata(node, css, style_refs.length > 0);
|
|
1419
|
+
transform_context.stylesheets.push(css);
|
|
1420
|
+
annotate_tsrx_with_hash(
|
|
1421
|
+
node,
|
|
1422
|
+
css.hash,
|
|
1423
|
+
transform_context.platform.jsx.rewriteClassAttr ? 'className' : 'class',
|
|
1424
|
+
transform_context.typeOnly,
|
|
1425
|
+
);
|
|
1426
|
+
return { css, style_refs };
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
/**
|
|
1430
|
+
* @template T
|
|
1431
|
+
* @param {any} node
|
|
1432
|
+
* @param {TransformContext} transform_context
|
|
1433
|
+
* @param {(style_context: { css: any, style_refs: any[] } | null) => T} callback
|
|
1434
|
+
* @returns {T}
|
|
1435
|
+
*/
|
|
1436
|
+
function with_tsrx_fragment_styles(node, transform_context, callback) {
|
|
1437
|
+
const style_context = prepare_tsrx_fragment_styles(node, transform_context);
|
|
1438
|
+
return callback(style_context);
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
/**
|
|
1442
|
+
* @param {any} fragment
|
|
1443
|
+
* @param {{ css: any, style_refs: any[] } | null} style_context
|
|
1444
|
+
* @param {TransformContext} transform_context
|
|
1445
|
+
* @returns {AST.Statement[]}
|
|
1446
|
+
*/
|
|
1447
|
+
function create_tsrx_style_ref_setup_statements(fragment, style_context, transform_context) {
|
|
1448
|
+
if (!style_context || style_context.style_refs.length === 0) {
|
|
1449
|
+
return [];
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
return create_style_ref_setup_statements(
|
|
1453
|
+
style_context.style_refs,
|
|
1454
|
+
create_style_class_map(fragment, style_context.css),
|
|
1455
|
+
{
|
|
1456
|
+
allowMutableRefTarget: transform_context.platform.jsx.multiRefStrategy === 'array',
|
|
1457
|
+
createTempIdentifier: () =>
|
|
1458
|
+
create_generated_identifier(create_style_ref_temp_name(transform_context)),
|
|
1459
|
+
},
|
|
1460
|
+
);
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
/**
|
|
1464
|
+
* @param {TransformContext} transform_context
|
|
1465
|
+
* @returns {string}
|
|
1466
|
+
*/
|
|
1467
|
+
function create_style_ref_temp_name(transform_context) {
|
|
1468
|
+
if (transform_context.helper_state) {
|
|
1469
|
+
return create_helper_name(transform_context.helper_state, 'style_ref');
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
transform_context.local_statement_component_index += 1;
|
|
1473
|
+
return `_tsrx_style_ref_${transform_context.local_statement_component_index}`;
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
/**
|
|
1477
|
+
* @param {any} node
|
|
1478
|
+
* @param {any[]} styles
|
|
1479
|
+
* @returns {void}
|
|
1480
|
+
*/
|
|
1481
|
+
function collect_style_elements(node, styles) {
|
|
1482
|
+
if (!node || typeof node !== 'object') return;
|
|
1483
|
+
|
|
1484
|
+
if (Array.isArray(node)) {
|
|
1485
|
+
for (const child of node) {
|
|
1486
|
+
collect_style_elements(child, styles);
|
|
1487
|
+
}
|
|
1488
|
+
return;
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
if (is_style_element(node)) {
|
|
1492
|
+
const stylesheet = node.children?.find(
|
|
1493
|
+
(/** @type {any} */ child) => child.type === 'StyleSheet',
|
|
1494
|
+
);
|
|
1495
|
+
if (stylesheet) {
|
|
1496
|
+
styles.push(stylesheet);
|
|
1497
|
+
}
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
if (is_function_or_class_boundary(node) || node.type === 'Tsrx') {
|
|
1502
|
+
return;
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
for (const key of Object.keys(node)) {
|
|
1506
|
+
if (key === 'loc' || key === 'start' || key === 'end' || key === 'metadata') {
|
|
1507
|
+
continue;
|
|
1508
|
+
}
|
|
1509
|
+
collect_style_elements(node[key], styles);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
/**
|
|
1514
|
+
* @param {any} node
|
|
1515
|
+
* @param {string} hash
|
|
1516
|
+
* @param {'class' | 'className'} jsx_class_attr_name
|
|
1517
|
+
* @param {boolean} preserve_style_elements
|
|
1518
|
+
* @returns {void}
|
|
1519
|
+
*/
|
|
1520
|
+
function annotate_tsrx_with_hash(node, hash, jsx_class_attr_name, preserve_style_elements) {
|
|
1521
|
+
node.children = (node.children || []).map((/** @type {any} */ statement) =>
|
|
1522
|
+
annotate_with_hash(statement, hash, jsx_class_attr_name, preserve_style_elements),
|
|
1523
|
+
);
|
|
1524
|
+
if (!preserve_style_elements) {
|
|
1525
|
+
node.children = strip_style_elements(node.children);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
/**
|
|
1530
|
+
* @param {any} node
|
|
1531
|
+
* @returns {any}
|
|
1532
|
+
*/
|
|
1533
|
+
function strip_style_elements(node) {
|
|
1534
|
+
if (!node || typeof node !== 'object') return node;
|
|
1535
|
+
|
|
1536
|
+
if (Array.isArray(node)) {
|
|
1537
|
+
return node
|
|
1538
|
+
.filter((child) => !is_style_element(child))
|
|
1539
|
+
.map((child) => strip_style_elements(child))
|
|
1540
|
+
.filter(Boolean);
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
if (is_style_element(node)) {
|
|
1544
|
+
return null;
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
if (is_function_or_class_boundary(node)) {
|
|
1548
|
+
return node;
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
for (const key of Object.keys(node)) {
|
|
1552
|
+
if (key === 'loc' || key === 'start' || key === 'end' || key === 'metadata' || key === 'css') {
|
|
1553
|
+
continue;
|
|
1554
|
+
}
|
|
1555
|
+
const value = node[key];
|
|
1556
|
+
if (Array.isArray(value)) {
|
|
1557
|
+
node[key] = strip_style_elements(value);
|
|
1558
|
+
} else if (value && typeof value === 'object') {
|
|
1559
|
+
const stripped = strip_style_elements(value);
|
|
1560
|
+
if (stripped) {
|
|
1561
|
+
node[key] = stripped;
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
return node;
|
|
1284
1567
|
}
|
|
1285
1568
|
|
|
1286
1569
|
/**
|
|
1287
|
-
* @param {
|
|
1288
|
-
* @param {
|
|
1289
|
-
* @returns {
|
|
1570
|
+
* @param {any} node
|
|
1571
|
+
* @param {TransformContext} transform_context
|
|
1572
|
+
* @returns {void}
|
|
1290
1573
|
*/
|
|
1291
|
-
function
|
|
1292
|
-
|
|
1293
|
-
|
|
1574
|
+
function expand_native_tsrx_function_returns(node, transform_context) {
|
|
1575
|
+
if (node.type === 'ArrowFunctionExpression' && node.body?.type === 'Tsrx') {
|
|
1576
|
+
const body = node.body;
|
|
1577
|
+
const statements = with_tsrx_fragment_styles(body, transform_context, (style_context) => {
|
|
1578
|
+
return [
|
|
1579
|
+
...create_tsrx_style_ref_setup_statements(body, style_context, transform_context),
|
|
1580
|
+
...build_render_statements(get_tsrx_render_children(body), true, transform_context),
|
|
1581
|
+
];
|
|
1582
|
+
});
|
|
1583
|
+
node.body = b.block(mark_native_pretransformed_jsx(statements), body);
|
|
1584
|
+
node.expression = false;
|
|
1585
|
+
return;
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
if (node.body?.type !== 'BlockStatement') {
|
|
1589
|
+
return;
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
node.body.body = expand_native_tsrx_return_statement_list(
|
|
1593
|
+
node.body.body || [],
|
|
1594
|
+
transform_context,
|
|
1595
|
+
);
|
|
1294
1596
|
}
|
|
1295
1597
|
|
|
1296
1598
|
/**
|
|
1297
|
-
* @param {
|
|
1298
|
-
* @
|
|
1599
|
+
* @param {any[]} statements
|
|
1600
|
+
* @param {TransformContext} transform_context
|
|
1601
|
+
* @returns {any[]}
|
|
1299
1602
|
*/
|
|
1300
|
-
function
|
|
1301
|
-
return
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
helpers: [],
|
|
1305
|
-
statics: [],
|
|
1306
|
-
};
|
|
1603
|
+
function expand_native_tsrx_return_statement_list(statements, transform_context) {
|
|
1604
|
+
return statements.flatMap((statement) =>
|
|
1605
|
+
expand_native_tsrx_return_statement(statement, transform_context),
|
|
1606
|
+
);
|
|
1307
1607
|
}
|
|
1308
1608
|
|
|
1309
1609
|
/**
|
|
1310
|
-
* @param {any}
|
|
1311
|
-
* @param {
|
|
1312
|
-
* @returns {any}
|
|
1610
|
+
* @param {any} statement
|
|
1611
|
+
* @param {TransformContext} transform_context
|
|
1612
|
+
* @returns {any[]}
|
|
1313
1613
|
*/
|
|
1314
|
-
function
|
|
1315
|
-
if (
|
|
1316
|
-
|
|
1614
|
+
function expand_native_tsrx_return_statement(statement, transform_context) {
|
|
1615
|
+
if (!statement || typeof statement !== 'object') return [statement];
|
|
1616
|
+
|
|
1617
|
+
if (statement.type === 'ReturnStatement' && statement.argument?.type === 'Tsrx') {
|
|
1618
|
+
const fragment = statement.argument;
|
|
1619
|
+
return with_tsrx_fragment_styles(fragment, transform_context, (style_context) => {
|
|
1620
|
+
return mark_native_pretransformed_jsx([
|
|
1621
|
+
...create_tsrx_style_ref_setup_statements(fragment, style_context, transform_context),
|
|
1622
|
+
...build_render_statements(get_tsrx_render_children(fragment), true, transform_context),
|
|
1623
|
+
]);
|
|
1624
|
+
});
|
|
1317
1625
|
}
|
|
1318
1626
|
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1627
|
+
if (is_function_or_class_boundary(statement)) {
|
|
1628
|
+
return [statement];
|
|
1629
|
+
}
|
|
1322
1630
|
|
|
1323
|
-
|
|
1324
|
-
|
|
1631
|
+
if (statement.type === 'BlockStatement') {
|
|
1632
|
+
statement.body = expand_native_tsrx_return_statement_list(
|
|
1633
|
+
statement.body || [],
|
|
1634
|
+
transform_context,
|
|
1635
|
+
);
|
|
1636
|
+
return [statement];
|
|
1637
|
+
}
|
|
1325
1638
|
|
|
1326
|
-
|
|
1639
|
+
if (statement.type === 'IfStatement') {
|
|
1640
|
+
statement.consequent = expand_embedded_native_return_statement(
|
|
1641
|
+
statement.consequent,
|
|
1642
|
+
transform_context,
|
|
1643
|
+
);
|
|
1644
|
+
if (statement.alternate) {
|
|
1645
|
+
statement.alternate = expand_embedded_native_return_statement(
|
|
1646
|
+
statement.alternate,
|
|
1647
|
+
transform_context,
|
|
1648
|
+
);
|
|
1649
|
+
}
|
|
1650
|
+
return [statement];
|
|
1651
|
+
}
|
|
1327
1652
|
|
|
1328
|
-
|
|
1329
|
-
|
|
1653
|
+
if (statement.type === 'SwitchStatement') {
|
|
1654
|
+
for (const switch_case of statement.cases || []) {
|
|
1655
|
+
switch_case.consequent = expand_native_tsrx_return_statement_list(
|
|
1656
|
+
switch_case.consequent || [],
|
|
1657
|
+
transform_context,
|
|
1658
|
+
);
|
|
1659
|
+
}
|
|
1660
|
+
return [statement];
|
|
1661
|
+
}
|
|
1330
1662
|
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1663
|
+
if (statement.type === 'TryStatement') {
|
|
1664
|
+
statement.block = expand_embedded_native_return_statement(statement.block, transform_context);
|
|
1665
|
+
if (statement.handler?.body) {
|
|
1666
|
+
statement.handler.body = expand_embedded_native_return_statement(
|
|
1667
|
+
statement.handler.body,
|
|
1668
|
+
transform_context,
|
|
1669
|
+
);
|
|
1670
|
+
}
|
|
1671
|
+
if (statement.finalizer) {
|
|
1672
|
+
statement.finalizer = expand_embedded_native_return_statement(
|
|
1673
|
+
statement.finalizer,
|
|
1674
|
+
transform_context,
|
|
1675
|
+
);
|
|
1676
|
+
}
|
|
1677
|
+
return [statement];
|
|
1338
1678
|
}
|
|
1339
1679
|
|
|
1340
|
-
return
|
|
1680
|
+
return [statement];
|
|
1341
1681
|
}
|
|
1342
1682
|
|
|
1343
1683
|
/**
|
|
1344
|
-
* @param {any}
|
|
1345
|
-
* @
|
|
1684
|
+
* @param {any} statement
|
|
1685
|
+
* @param {TransformContext} transform_context
|
|
1686
|
+
* @returns {any}
|
|
1346
1687
|
*/
|
|
1347
|
-
function
|
|
1348
|
-
|
|
1349
|
-
|
|
1688
|
+
function expand_embedded_native_return_statement(statement, transform_context) {
|
|
1689
|
+
const expanded = expand_native_tsrx_return_statement(statement, transform_context);
|
|
1690
|
+
return expanded.length === 1 ? expanded[0] : b.block(expanded, statement);
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
/**
|
|
1694
|
+
* @template T
|
|
1695
|
+
* @param {T} node
|
|
1696
|
+
* @param {Set<any>} [seen]
|
|
1697
|
+
* @returns {T}
|
|
1698
|
+
*/
|
|
1699
|
+
function mark_native_pretransformed_jsx(node, seen = new Set()) {
|
|
1700
|
+
if (node == null || typeof node !== 'object' || seen.has(node)) {
|
|
1701
|
+
return node;
|
|
1702
|
+
}
|
|
1703
|
+
seen.add(node);
|
|
1704
|
+
|
|
1705
|
+
if (Array.isArray(node)) {
|
|
1706
|
+
for (const item of node) mark_native_pretransformed_jsx(item, seen);
|
|
1707
|
+
return node;
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
const as_node = /** @type {any} */ (node);
|
|
1711
|
+
if (as_node.type === 'JSXOpeningElement') {
|
|
1712
|
+
as_node.metadata = {
|
|
1713
|
+
...(as_node.metadata || {}),
|
|
1714
|
+
native_tsrx_pretransformed: true,
|
|
1715
|
+
};
|
|
1350
1716
|
}
|
|
1351
|
-
|
|
1717
|
+
|
|
1718
|
+
for (const key of Object.keys(as_node)) {
|
|
1719
|
+
if (key === 'loc' || key === 'start' || key === 'end' || key === 'metadata') {
|
|
1720
|
+
continue;
|
|
1721
|
+
}
|
|
1722
|
+
mark_native_pretransformed_jsx(as_node[key], seen);
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
return node;
|
|
1352
1726
|
}
|
|
1353
1727
|
|
|
1354
1728
|
/**
|
|
1355
1729
|
* @param {any} node
|
|
1356
|
-
* @returns {
|
|
1730
|
+
* @returns {any[]}
|
|
1357
1731
|
*/
|
|
1358
|
-
function
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1732
|
+
function get_tsrx_render_children(node) {
|
|
1733
|
+
return (node.children || []).filter(
|
|
1734
|
+
(/** @type {any} */ child) =>
|
|
1735
|
+
child &&
|
|
1736
|
+
child.type !== 'EmptyStatement' &&
|
|
1737
|
+
(child.type !== 'JSXText' || child.value.trim() !== ''),
|
|
1738
|
+
);
|
|
1362
1739
|
}
|
|
1363
1740
|
|
|
1364
1741
|
/**
|
|
@@ -1387,8 +1764,7 @@ function collect_descendant_declaration_bindings(node, bindings) {
|
|
|
1387
1764
|
if (
|
|
1388
1765
|
node.type === 'FunctionDeclaration' ||
|
|
1389
1766
|
node.type === 'FunctionExpression' ||
|
|
1390
|
-
node.type === 'ArrowFunctionExpression'
|
|
1391
|
-
node.type === 'Component'
|
|
1767
|
+
node.type === 'ArrowFunctionExpression'
|
|
1392
1768
|
) {
|
|
1393
1769
|
return;
|
|
1394
1770
|
}
|
|
@@ -1438,8 +1814,7 @@ function node_contains_hook_bearing_tsrx(node, transform_context) {
|
|
|
1438
1814
|
if (
|
|
1439
1815
|
node.type === 'FunctionDeclaration' ||
|
|
1440
1816
|
node.type === 'FunctionExpression' ||
|
|
1441
|
-
node.type === 'ArrowFunctionExpression'
|
|
1442
|
-
node.type === 'Component'
|
|
1817
|
+
node.type === 'ArrowFunctionExpression'
|
|
1443
1818
|
) {
|
|
1444
1819
|
return false;
|
|
1445
1820
|
}
|
|
@@ -1464,6 +1839,14 @@ function should_use_module_scoped_hook_components(transform_context) {
|
|
|
1464
1839
|
return !!(transform_context.helper_state && transform_context.module_scoped_hook_components);
|
|
1465
1840
|
}
|
|
1466
1841
|
|
|
1842
|
+
/**
|
|
1843
|
+
* @param {TransformContext} transform_context
|
|
1844
|
+
* @returns {boolean}
|
|
1845
|
+
*/
|
|
1846
|
+
function should_extract_hook_helpers(transform_context) {
|
|
1847
|
+
return !!transform_context.hook_helpers_enabled;
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1467
1850
|
/**
|
|
1468
1851
|
* @param {AST.Identifier} helper_id
|
|
1469
1852
|
* @param {TransformContext} transform_context
|
|
@@ -1471,7 +1854,7 @@ function should_use_module_scoped_hook_components(transform_context) {
|
|
|
1471
1854
|
*/
|
|
1472
1855
|
function create_module_scoped_hook_component_id(helper_id, transform_context) {
|
|
1473
1856
|
return create_generated_identifier(
|
|
1474
|
-
`${transform_context.helper_state?.base_name || '
|
|
1857
|
+
`${transform_context.helper_state?.base_name || 'Tsrx'}__${helper_id.name}`,
|
|
1475
1858
|
);
|
|
1476
1859
|
}
|
|
1477
1860
|
|
|
@@ -1670,59 +2053,6 @@ function is_bare_component_invocation(node) {
|
|
|
1670
2053
|
return is_component_jsx_name(opening.name);
|
|
1671
2054
|
}
|
|
1672
2055
|
|
|
1673
|
-
/**
|
|
1674
|
-
* Static JSX that appears before multiple early-return guards is otherwise
|
|
1675
|
-
* cloned into every generated return. Capture it once at its source position
|
|
1676
|
-
* and reuse the reference, matching the interleaved-statement capture path
|
|
1677
|
-
* without moving dynamic render-time expressions across guards.
|
|
1678
|
-
*
|
|
1679
|
-
* @param {any[]} render_nodes
|
|
1680
|
-
* @param {any[]} statements
|
|
1681
|
-
* @param {number} capture_index
|
|
1682
|
-
* @param {TransformContext} transform_context
|
|
1683
|
-
* @returns {number}
|
|
1684
|
-
*/
|
|
1685
|
-
function capture_static_early_return_render_nodes(
|
|
1686
|
-
render_nodes,
|
|
1687
|
-
statements,
|
|
1688
|
-
capture_index,
|
|
1689
|
-
transform_context,
|
|
1690
|
-
) {
|
|
1691
|
-
for (let i = 0; i < render_nodes.length; i += 1) {
|
|
1692
|
-
const node = render_nodes[i];
|
|
1693
|
-
if (!is_static_early_return_capture_node(node, transform_context)) {
|
|
1694
|
-
continue;
|
|
1695
|
-
}
|
|
1696
|
-
|
|
1697
|
-
const { declaration, reference } = captureJsxChild(node, capture_index++);
|
|
1698
|
-
statements.push(declaration);
|
|
1699
|
-
render_nodes[i] = reference;
|
|
1700
|
-
}
|
|
1701
|
-
|
|
1702
|
-
return capture_index;
|
|
1703
|
-
}
|
|
1704
|
-
|
|
1705
|
-
/**
|
|
1706
|
-
* @param {any} node
|
|
1707
|
-
* @param {TransformContext} transform_context
|
|
1708
|
-
* @returns {boolean}
|
|
1709
|
-
*/
|
|
1710
|
-
function is_static_early_return_capture_node(node, transform_context) {
|
|
1711
|
-
if (node?.type !== 'JSXElement' && node?.type !== 'JSXFragment') {
|
|
1712
|
-
return false;
|
|
1713
|
-
}
|
|
1714
|
-
if (!is_hoist_safe_jsx_node(node)) {
|
|
1715
|
-
return false;
|
|
1716
|
-
}
|
|
1717
|
-
if (
|
|
1718
|
-
transform_context.platform.hooks?.canHoistStaticNode &&
|
|
1719
|
-
!transform_context.platform.hooks.canHoistStaticNode(node, transform_context)
|
|
1720
|
-
) {
|
|
1721
|
-
return false;
|
|
1722
|
-
}
|
|
1723
|
-
return !references_scope_bindings(node, transform_context.available_bindings);
|
|
1724
|
-
}
|
|
1725
|
-
|
|
1726
2056
|
/**
|
|
1727
2057
|
* @param {AST.Program} program
|
|
1728
2058
|
* @returns {AST.Program}
|
|
@@ -1743,11 +2073,9 @@ function expand_component_helpers(program) {
|
|
|
1743
2073
|
}
|
|
1744
2074
|
|
|
1745
2075
|
/**
|
|
1746
|
-
*
|
|
1747
|
-
* variable
|
|
1748
|
-
*
|
|
1749
|
-
* the hook returns, so helper expansion must read metadata from that broader
|
|
1750
|
-
* set.
|
|
2076
|
+
* Generated helper/statics metadata can be carried on function declarations,
|
|
2077
|
+
* variable declarations, object literal members, or export-safe expressions,
|
|
2078
|
+
* so helper expansion reads metadata from that broader set.
|
|
1751
2079
|
*
|
|
1752
2080
|
* @param {any} node
|
|
1753
2081
|
* @returns {{ generated_helpers?: any[], generated_statics?: any[] }[]}
|
|
@@ -1803,112 +2131,164 @@ function get_generated_component_metadata_list(node) {
|
|
|
1803
2131
|
return metas;
|
|
1804
2132
|
}
|
|
1805
2133
|
|
|
2134
|
+
/**
|
|
2135
|
+
* @param {any[]} render_nodes
|
|
2136
|
+
* @param {any} source_node
|
|
2137
|
+
* @param {boolean} [map_render_node_locations]
|
|
2138
|
+
* @returns {any}
|
|
2139
|
+
*/
|
|
2140
|
+
function create_component_return_statement(
|
|
2141
|
+
render_nodes,
|
|
2142
|
+
source_node,
|
|
2143
|
+
map_render_node_locations = true,
|
|
2144
|
+
) {
|
|
2145
|
+
const cloned = render_nodes.map((node) =>
|
|
2146
|
+
map_render_node_locations ? clone_expression_node(node) : clone_expression_node(node, false),
|
|
2147
|
+
);
|
|
2148
|
+
|
|
2149
|
+
return set_loc(b.return(build_return_expression(cloned) || create_null_literal()), source_node);
|
|
2150
|
+
}
|
|
2151
|
+
|
|
1806
2152
|
/**
|
|
1807
2153
|
* @param {any} node
|
|
1808
2154
|
* @returns {boolean}
|
|
1809
2155
|
*/
|
|
1810
|
-
function
|
|
1811
|
-
return
|
|
2156
|
+
function is_loop_skip_return_statement(node) {
|
|
2157
|
+
return (
|
|
2158
|
+
node?.type === 'ReturnStatement' &&
|
|
2159
|
+
node.argument == null &&
|
|
2160
|
+
node.metadata?.generated_loop_continue_return === true
|
|
2161
|
+
);
|
|
1812
2162
|
}
|
|
1813
2163
|
|
|
1814
2164
|
/**
|
|
1815
2165
|
* @param {any} node
|
|
1816
2166
|
* @returns {boolean}
|
|
1817
2167
|
*/
|
|
1818
|
-
function
|
|
2168
|
+
function is_loop_skip_if_statement(node) {
|
|
2169
|
+
return get_loop_skip_if_consequent_body(node) !== null;
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
/**
|
|
2173
|
+
* @param {any} node
|
|
2174
|
+
* @returns {any[] | null}
|
|
2175
|
+
*/
|
|
2176
|
+
function get_loop_skip_if_consequent_body(node) {
|
|
1819
2177
|
if (node?.type !== 'IfStatement' || node.alternate) {
|
|
1820
|
-
return
|
|
2178
|
+
return null;
|
|
1821
2179
|
}
|
|
1822
2180
|
|
|
1823
|
-
const consequent_body =
|
|
2181
|
+
const consequent_body =
|
|
2182
|
+
node.consequent.type === 'BlockStatement' ? node.consequent.body : [node.consequent];
|
|
1824
2183
|
|
|
1825
|
-
return consequent_body.
|
|
2184
|
+
return consequent_body.some(is_loop_skip_return_statement) ? consequent_body : null;
|
|
1826
2185
|
}
|
|
1827
2186
|
|
|
1828
2187
|
/**
|
|
1829
2188
|
* @param {any} node
|
|
1830
|
-
* @
|
|
2189
|
+
* @param {any[]} render_nodes
|
|
2190
|
+
* @param {TransformContext} transform_context
|
|
2191
|
+
* @returns {any}
|
|
1831
2192
|
*/
|
|
1832
|
-
function
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
2193
|
+
function create_component_loop_skip_if_statement(node, render_nodes, transform_context) {
|
|
2194
|
+
const consequent_body = /** @type {any[]} */ (get_loop_skip_if_consequent_body(node));
|
|
2195
|
+
const branch_statements = build_render_statements(consequent_body, true, transform_context);
|
|
2196
|
+
prepend_render_nodes_to_return_statements(branch_statements, render_nodes);
|
|
1836
2197
|
|
|
1837
|
-
return
|
|
2198
|
+
return set_loc(b.if(node.test, set_loc(b.block(branch_statements), node.consequent), null), node);
|
|
1838
2199
|
}
|
|
1839
2200
|
|
|
1840
2201
|
/**
|
|
1841
|
-
* @param {any}
|
|
1842
|
-
* @
|
|
2202
|
+
* @param {any[]} statements
|
|
2203
|
+
* @param {any[]} render_nodes
|
|
2204
|
+
* @returns {void}
|
|
1843
2205
|
*/
|
|
1844
|
-
function
|
|
1845
|
-
|
|
2206
|
+
function prepend_render_nodes_to_return_statements(statements, render_nodes) {
|
|
2207
|
+
if (render_nodes.length === 0) {
|
|
2208
|
+
return;
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2211
|
+
for (const statement of statements) {
|
|
2212
|
+
prepend_render_nodes_to_return_statement(statement, render_nodes, false);
|
|
2213
|
+
}
|
|
1846
2214
|
}
|
|
1847
2215
|
|
|
1848
2216
|
/**
|
|
2217
|
+
* @param {any} node
|
|
1849
2218
|
* @param {any[]} render_nodes
|
|
1850
|
-
* @param {
|
|
1851
|
-
* @
|
|
1852
|
-
* @returns {any}
|
|
2219
|
+
* @param {boolean} inside_nested_function
|
|
2220
|
+
* @returns {void}
|
|
1853
2221
|
*/
|
|
1854
|
-
function
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
2222
|
+
function prepend_render_nodes_to_return_statement(node, render_nodes, inside_nested_function) {
|
|
2223
|
+
if (!node || typeof node !== 'object') {
|
|
2224
|
+
return;
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2227
|
+
if (
|
|
2228
|
+
node.type === 'FunctionDeclaration' ||
|
|
2229
|
+
node.type === 'FunctionExpression' ||
|
|
2230
|
+
node.type === 'ArrowFunctionExpression'
|
|
2231
|
+
) {
|
|
2232
|
+
inside_nested_function = true;
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
if (!inside_nested_function && node.type === 'ReturnStatement') {
|
|
2236
|
+
node.argument = combine_render_return_argument(render_nodes, node.argument);
|
|
2237
|
+
return;
|
|
2238
|
+
}
|
|
2239
|
+
|
|
2240
|
+
if (Array.isArray(node)) {
|
|
2241
|
+
for (const child of node) {
|
|
2242
|
+
prepend_render_nodes_to_return_statement(child, render_nodes, inside_nested_function);
|
|
2243
|
+
}
|
|
2244
|
+
return;
|
|
2245
|
+
}
|
|
1862
2246
|
|
|
1863
|
-
|
|
2247
|
+
for (const key of Object.keys(node)) {
|
|
2248
|
+
if (key === 'loc' || key === 'start' || key === 'end' || key === 'metadata') {
|
|
2249
|
+
continue;
|
|
2250
|
+
}
|
|
2251
|
+
prepend_render_nodes_to_return_statement(node[key], render_nodes, inside_nested_function);
|
|
2252
|
+
}
|
|
1864
2253
|
}
|
|
1865
2254
|
|
|
1866
2255
|
/**
|
|
1867
|
-
* @param {any} node
|
|
1868
2256
|
* @param {any[]} render_nodes
|
|
2257
|
+
* @param {any} return_argument
|
|
1869
2258
|
* @returns {any}
|
|
1870
2259
|
*/
|
|
1871
|
-
function
|
|
1872
|
-
const
|
|
2260
|
+
function combine_render_return_argument(render_nodes, return_argument) {
|
|
2261
|
+
const combined = render_nodes.map((node) => clone_expression_node(node, false));
|
|
1873
2262
|
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
node.consequent,
|
|
1880
|
-
),
|
|
1881
|
-
null,
|
|
1882
|
-
),
|
|
1883
|
-
node,
|
|
1884
|
-
);
|
|
2263
|
+
if (return_argument != null && !is_null_literal(return_argument)) {
|
|
2264
|
+
combined.push(return_argument_to_render_node(return_argument));
|
|
2265
|
+
}
|
|
2266
|
+
|
|
2267
|
+
return build_return_expression(combined) || create_null_literal();
|
|
1885
2268
|
}
|
|
1886
2269
|
|
|
1887
2270
|
/**
|
|
1888
|
-
* @param {any}
|
|
1889
|
-
* @param {any[]} render_nodes
|
|
1890
|
-
* @param {TransformContext} transform_context
|
|
2271
|
+
* @param {any} argument
|
|
1891
2272
|
* @returns {any}
|
|
1892
2273
|
*/
|
|
1893
|
-
function
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
2274
|
+
function return_argument_to_render_node(argument) {
|
|
2275
|
+
if (
|
|
2276
|
+
argument?.type === 'JSXElement' ||
|
|
2277
|
+
argument?.type === 'JSXFragment' ||
|
|
2278
|
+
argument?.type === 'JSXExpressionContainer'
|
|
2279
|
+
) {
|
|
2280
|
+
return argument;
|
|
2281
|
+
}
|
|
1897
2282
|
|
|
1898
|
-
return
|
|
2283
|
+
return to_jsx_expression_container(argument);
|
|
1899
2284
|
}
|
|
1900
2285
|
|
|
1901
2286
|
/**
|
|
1902
|
-
*
|
|
1903
|
-
*
|
|
1904
|
-
* get dropped on the lift path.
|
|
1905
|
-
*
|
|
1906
|
-
* @param {any[]} render_nodes
|
|
1907
|
-
* @param {any} jsx_child
|
|
1908
|
-
* @returns {any}
|
|
2287
|
+
* @param {any} node
|
|
2288
|
+
* @returns {boolean}
|
|
1909
2289
|
*/
|
|
1910
|
-
function
|
|
1911
|
-
return
|
|
2290
|
+
function is_null_literal(node) {
|
|
2291
|
+
return node?.type === 'Literal' && node.value == null;
|
|
1912
2292
|
}
|
|
1913
2293
|
|
|
1914
2294
|
/**
|
|
@@ -1932,51 +2312,6 @@ function build_array_normalization_decls(source_id, source_expr) {
|
|
|
1932
2312
|
return { source_decl, source_normalize_decl };
|
|
1933
2313
|
}
|
|
1934
2314
|
|
|
1935
|
-
/**
|
|
1936
|
-
* @param {any} node
|
|
1937
|
-
* @param {any[]} continuation_body
|
|
1938
|
-
* @param {any[]} render_nodes
|
|
1939
|
-
* @param {TransformContext} transform_context
|
|
1940
|
-
* @returns {any[]}
|
|
1941
|
-
*/
|
|
1942
|
-
function create_component_helper_split_returning_if_statements(
|
|
1943
|
-
node,
|
|
1944
|
-
continuation_body,
|
|
1945
|
-
render_nodes,
|
|
1946
|
-
transform_context,
|
|
1947
|
-
) {
|
|
1948
|
-
const consequent_body = get_if_consequent_body(node);
|
|
1949
|
-
const return_index = consequent_body.findIndex(is_bare_return_statement);
|
|
1950
|
-
const branch_body =
|
|
1951
|
-
return_index === -1 ? consequent_body : consequent_body.slice(0, return_index);
|
|
1952
|
-
const branch_helper = create_hook_safe_helper(
|
|
1953
|
-
branch_body,
|
|
1954
|
-
undefined,
|
|
1955
|
-
node.consequent,
|
|
1956
|
-
transform_context,
|
|
1957
|
-
);
|
|
1958
|
-
const continuation_helper = create_hook_safe_helper(
|
|
1959
|
-
continuation_body,
|
|
1960
|
-
undefined,
|
|
1961
|
-
node,
|
|
1962
|
-
transform_context,
|
|
1963
|
-
);
|
|
1964
|
-
|
|
1965
|
-
const branch_block = set_loc(
|
|
1966
|
-
b.block([
|
|
1967
|
-
...branch_helper.setup_statements,
|
|
1968
|
-
combined_return_statement(render_nodes, branch_helper.component_element),
|
|
1969
|
-
]),
|
|
1970
|
-
node.consequent,
|
|
1971
|
-
);
|
|
1972
|
-
|
|
1973
|
-
return [
|
|
1974
|
-
set_loc(b.if(node.test, branch_block, null), node),
|
|
1975
|
-
...continuation_helper.setup_statements,
|
|
1976
|
-
combined_return_statement(render_nodes, continuation_helper.component_element),
|
|
1977
|
-
];
|
|
1978
|
-
}
|
|
1979
|
-
|
|
1980
2315
|
/**
|
|
1981
2316
|
* Hoist the helper for a hook-bearing for-of body out of the iteration
|
|
1982
2317
|
* callback so the helper is declared once per render rather than re-bound on
|
|
@@ -2088,7 +2423,7 @@ function build_hoisted_for_of_with_hooks(node, transform_context) {
|
|
|
2088
2423
|
transform_context.available_bindings = fn_saved_bindings;
|
|
2089
2424
|
|
|
2090
2425
|
const helper_fn = b.function(clone_identifier(component_id), params, b.block(fn_body_statements));
|
|
2091
|
-
helper_fn.metadata = { path: [],
|
|
2426
|
+
helper_fn.metadata = { path: [], is_method: false };
|
|
2092
2427
|
|
|
2093
2428
|
let helper_decl;
|
|
2094
2429
|
if (transform_context.helper_state && use_module_scoped_component) {
|
|
@@ -2236,142 +2571,6 @@ function create_helper_props_type_literal_with_typeof_flags(bindings, aliases, u
|
|
|
2236
2571
|
);
|
|
2237
2572
|
}
|
|
2238
2573
|
|
|
2239
|
-
/**
|
|
2240
|
-
* @param {any} node
|
|
2241
|
-
* @param {any[]} continuation_body
|
|
2242
|
-
* @param {any[]} render_nodes
|
|
2243
|
-
* @param {TransformContext} transform_context
|
|
2244
|
-
* @returns {any[]}
|
|
2245
|
-
*/
|
|
2246
|
-
function create_setup_once_helper_split_returning_if_statements(
|
|
2247
|
-
node,
|
|
2248
|
-
continuation_body,
|
|
2249
|
-
render_nodes,
|
|
2250
|
-
transform_context,
|
|
2251
|
-
) {
|
|
2252
|
-
const consequent_body = get_if_consequent_body(node);
|
|
2253
|
-
const return_index = consequent_body.findIndex(is_bare_return_statement);
|
|
2254
|
-
const branch_body =
|
|
2255
|
-
return_index === -1 ? consequent_body : consequent_body.slice(0, return_index);
|
|
2256
|
-
const branch_helper = branch_body.length
|
|
2257
|
-
? create_hook_safe_helper(branch_body, undefined, node.consequent, transform_context)
|
|
2258
|
-
: { setup_statements: [], component_element: create_null_literal() };
|
|
2259
|
-
const continuation_helper = continuation_body.length
|
|
2260
|
-
? create_hook_safe_helper(continuation_body, undefined, node, transform_context)
|
|
2261
|
-
: { setup_statements: [], component_element: create_null_literal() };
|
|
2262
|
-
|
|
2263
|
-
return [
|
|
2264
|
-
...branch_helper.setup_statements,
|
|
2265
|
-
...continuation_helper.setup_statements,
|
|
2266
|
-
b.return(
|
|
2267
|
-
combine_render_return_argument(
|
|
2268
|
-
render_nodes,
|
|
2269
|
-
set_loc(
|
|
2270
|
-
b.conditional(
|
|
2271
|
-
node.test,
|
|
2272
|
-
branch_helper.component_element,
|
|
2273
|
-
continuation_helper.component_element,
|
|
2274
|
-
),
|
|
2275
|
-
node,
|
|
2276
|
-
),
|
|
2277
|
-
),
|
|
2278
|
-
),
|
|
2279
|
-
];
|
|
2280
|
-
}
|
|
2281
|
-
|
|
2282
|
-
/**
|
|
2283
|
-
* @param {any[]} statements
|
|
2284
|
-
* @param {any[]} render_nodes
|
|
2285
|
-
* @returns {void}
|
|
2286
|
-
*/
|
|
2287
|
-
function prepend_render_nodes_to_return_statements(statements, render_nodes) {
|
|
2288
|
-
if (render_nodes.length === 0) {
|
|
2289
|
-
return;
|
|
2290
|
-
}
|
|
2291
|
-
|
|
2292
|
-
for (const statement of statements) {
|
|
2293
|
-
prepend_render_nodes_to_return_statement(statement, render_nodes, false);
|
|
2294
|
-
}
|
|
2295
|
-
}
|
|
2296
|
-
|
|
2297
|
-
/**
|
|
2298
|
-
* @param {any} node
|
|
2299
|
-
* @param {any[]} render_nodes
|
|
2300
|
-
* @param {boolean} inside_nested_function
|
|
2301
|
-
* @returns {void}
|
|
2302
|
-
*/
|
|
2303
|
-
function prepend_render_nodes_to_return_statement(node, render_nodes, inside_nested_function) {
|
|
2304
|
-
if (!node || typeof node !== 'object') {
|
|
2305
|
-
return;
|
|
2306
|
-
}
|
|
2307
|
-
|
|
2308
|
-
if (
|
|
2309
|
-
node.type === 'FunctionDeclaration' ||
|
|
2310
|
-
node.type === 'FunctionExpression' ||
|
|
2311
|
-
node.type === 'ArrowFunctionExpression'
|
|
2312
|
-
) {
|
|
2313
|
-
inside_nested_function = true;
|
|
2314
|
-
}
|
|
2315
|
-
|
|
2316
|
-
if (!inside_nested_function && node.type === 'ReturnStatement') {
|
|
2317
|
-
node.argument = combine_render_return_argument(render_nodes, node.argument);
|
|
2318
|
-
return;
|
|
2319
|
-
}
|
|
2320
|
-
|
|
2321
|
-
if (Array.isArray(node)) {
|
|
2322
|
-
for (const child of node) {
|
|
2323
|
-
prepend_render_nodes_to_return_statement(child, render_nodes, inside_nested_function);
|
|
2324
|
-
}
|
|
2325
|
-
return;
|
|
2326
|
-
}
|
|
2327
|
-
|
|
2328
|
-
for (const key of Object.keys(node)) {
|
|
2329
|
-
if (key === 'loc' || key === 'start' || key === 'end' || key === 'metadata') {
|
|
2330
|
-
continue;
|
|
2331
|
-
}
|
|
2332
|
-
prepend_render_nodes_to_return_statement(node[key], render_nodes, inside_nested_function);
|
|
2333
|
-
}
|
|
2334
|
-
}
|
|
2335
|
-
|
|
2336
|
-
/**
|
|
2337
|
-
* @param {any[]} render_nodes
|
|
2338
|
-
* @param {any} return_argument
|
|
2339
|
-
* @returns {any}
|
|
2340
|
-
*/
|
|
2341
|
-
function combine_render_return_argument(render_nodes, return_argument) {
|
|
2342
|
-
const combined = render_nodes.map((node) => clone_expression_node(node, false));
|
|
2343
|
-
|
|
2344
|
-
if (return_argument != null && !is_null_literal(return_argument)) {
|
|
2345
|
-
combined.push(return_argument_to_render_node(return_argument));
|
|
2346
|
-
}
|
|
2347
|
-
|
|
2348
|
-
return build_return_expression(combined) || create_null_literal();
|
|
2349
|
-
}
|
|
2350
|
-
|
|
2351
|
-
/**
|
|
2352
|
-
* @param {any} argument
|
|
2353
|
-
* @returns {any}
|
|
2354
|
-
*/
|
|
2355
|
-
function return_argument_to_render_node(argument) {
|
|
2356
|
-
if (
|
|
2357
|
-
argument?.type === 'JSXElement' ||
|
|
2358
|
-
argument?.type === 'JSXFragment' ||
|
|
2359
|
-
argument?.type === 'JSXExpressionContainer'
|
|
2360
|
-
) {
|
|
2361
|
-
return argument;
|
|
2362
|
-
}
|
|
2363
|
-
|
|
2364
|
-
return to_jsx_expression_container(argument);
|
|
2365
|
-
}
|
|
2366
|
-
|
|
2367
|
-
/**
|
|
2368
|
-
* @param {any} node
|
|
2369
|
-
* @returns {boolean}
|
|
2370
|
-
*/
|
|
2371
|
-
function is_null_literal(node) {
|
|
2372
|
-
return node?.type === 'Literal' && node.value == null;
|
|
2373
|
-
}
|
|
2374
|
-
|
|
2375
2574
|
/**
|
|
2376
2575
|
* @param {any} node
|
|
2377
2576
|
* @param {TransformContext} transform_context
|
|
@@ -2410,163 +2609,40 @@ function to_jsx_element(node, transform_context, raw_children = node.children ||
|
|
|
2410
2609
|
raw_children,
|
|
2411
2610
|
attributes,
|
|
2412
2611
|
transform_context,
|
|
2413
|
-
);
|
|
2414
|
-
|
|
2415
|
-
if (child_transform) {
|
|
2416
|
-
children = child_transform.children;
|
|
2417
|
-
if (typeof child_transform.selfClosing === 'boolean') {
|
|
2418
|
-
selfClosing = child_transform.selfClosing;
|
|
2419
|
-
}
|
|
2420
|
-
} else {
|
|
2421
|
-
const html_child_transform = rewrite_host_html_children(
|
|
2422
|
-
node,
|
|
2423
|
-
walked_children,
|
|
2424
|
-
raw_children,
|
|
2425
|
-
attributes,
|
|
2426
|
-
transform_context,
|
|
2427
|
-
);
|
|
2428
|
-
if (html_child_transform) {
|
|
2429
|
-
children = html_child_transform.children;
|
|
2430
|
-
selfClosing = html_child_transform.selfClosing;
|
|
2431
|
-
} else {
|
|
2432
|
-
children = create_element_children(walked_children, transform_context);
|
|
2433
|
-
}
|
|
2434
|
-
}
|
|
2435
|
-
const has_unmappable_attribute = attributes.some(
|
|
2436
|
-
(/** @type {any} */ attribute) => attribute?.metadata?.has_unmappable_value,
|
|
2437
|
-
);
|
|
2438
|
-
|
|
2439
|
-
const opening_element_node = b.jsx_opening_element(
|
|
2440
|
-
name,
|
|
2441
|
-
attributes,
|
|
2442
|
-
selfClosing,
|
|
2443
|
-
node.openingElement?.typeArguments,
|
|
2444
|
-
);
|
|
2445
|
-
const openingElement = has_unmappable_attribute
|
|
2446
|
-
? opening_element_node
|
|
2447
|
-
: set_loc(opening_element_node, node.openingElement || node);
|
|
2448
|
-
|
|
2449
|
-
const closingElement = selfClosing
|
|
2450
|
-
? null
|
|
2451
|
-
: set_loc(
|
|
2452
|
-
b.jsx_closing_element(
|
|
2453
|
-
clone_jsx_name(name, node.closingElement?.name || node.closingElement || node),
|
|
2454
|
-
),
|
|
2455
|
-
node.closingElement || node,
|
|
2456
|
-
);
|
|
2457
|
-
|
|
2458
|
-
return set_loc(b.jsx_element_fresh(openingElement, closingElement, children), node);
|
|
2459
|
-
}
|
|
2460
|
-
|
|
2461
|
-
/**
|
|
2462
|
-
* @param {any} node
|
|
2463
|
-
* @param {any[]} walked_children
|
|
2464
|
-
* @param {any[]} raw_children
|
|
2465
|
-
* @param {any[]} attributes
|
|
2466
|
-
* @param {TransformContext} transform_context
|
|
2467
|
-
* @returns {{ children: any[]; selfClosing: boolean } | null}
|
|
2468
|
-
*/
|
|
2469
|
-
export function rewrite_host_html_children(
|
|
2470
|
-
node,
|
|
2471
|
-
walked_children,
|
|
2472
|
-
raw_children,
|
|
2473
|
-
attributes,
|
|
2474
|
-
transform_context,
|
|
2475
|
-
) {
|
|
2476
|
-
const source_children = raw_children || walked_children;
|
|
2477
|
-
const source_html_index = source_children.findIndex((child) => child?.type === 'Html');
|
|
2478
|
-
if (source_html_index === -1) {
|
|
2479
|
-
return null;
|
|
2480
|
-
}
|
|
2481
|
-
const source_html = source_children[source_html_index];
|
|
2482
|
-
const walked_html =
|
|
2483
|
-
walked_children[source_html_index]?.type === 'Html'
|
|
2484
|
-
? walked_children[source_html_index]
|
|
2485
|
-
: source_html;
|
|
2486
|
-
|
|
2487
|
-
if (is_component_like_element(node) || source_children.length !== 1) {
|
|
2488
|
-
report_invalid_html_child_error(source_html, transform_context);
|
|
2489
|
-
}
|
|
2490
|
-
|
|
2491
|
-
const conflicting_attribute = get_host_html_conflicting_attribute(attributes, transform_context);
|
|
2492
|
-
if (conflicting_attribute !== null) {
|
|
2493
|
-
error(
|
|
2494
|
-
create_host_html_conflict_error(conflicting_attribute, transform_context),
|
|
2495
|
-
transform_context.filename,
|
|
2496
|
-
source_html,
|
|
2497
|
-
transform_context.errors,
|
|
2498
|
-
transform_context.comments,
|
|
2499
|
-
);
|
|
2500
|
-
}
|
|
2501
|
-
|
|
2502
|
-
attributes.push(create_host_html_attribute(walked_html, source_html, transform_context));
|
|
2503
|
-
|
|
2504
|
-
return { children: [], selfClosing: true };
|
|
2505
|
-
}
|
|
2506
|
-
|
|
2507
|
-
/**
|
|
2508
|
-
* @param {any[]} attributes
|
|
2509
|
-
* @param {TransformContext} transform_context
|
|
2510
|
-
* @returns {{ kind: 'attribute'; name: string } | null}
|
|
2511
|
-
*/
|
|
2512
|
-
export function get_host_html_conflicting_attribute(attributes, transform_context) {
|
|
2513
|
-
const conflicting_attributes = get_host_html_conflicting_attribute_names(transform_context);
|
|
2514
|
-
for (const name of conflicting_attributes) {
|
|
2515
|
-
if (has_jsx_attribute(attributes, name)) {
|
|
2516
|
-
return { kind: 'attribute', name };
|
|
2612
|
+
);
|
|
2613
|
+
|
|
2614
|
+
if (child_transform) {
|
|
2615
|
+
children = child_transform.children;
|
|
2616
|
+
if (typeof child_transform.selfClosing === 'boolean') {
|
|
2617
|
+
selfClosing = child_transform.selfClosing;
|
|
2517
2618
|
}
|
|
2619
|
+
} else {
|
|
2620
|
+
children = create_element_children(walked_children, transform_context);
|
|
2518
2621
|
}
|
|
2622
|
+
const has_unmappable_attribute = attributes.some(
|
|
2623
|
+
(/** @type {any} */ attribute) => attribute?.metadata?.has_unmappable_value,
|
|
2624
|
+
);
|
|
2519
2625
|
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
const html_attribute = get_host_html_attribute_name(transform_context);
|
|
2530
|
-
return `\`{html ...}\` lowers to \`${html_attribute}\` on the ${transform_context.platform.name} target and cannot be combined with an existing \`${conflicting_attribute.name}\` attribute.`;
|
|
2531
|
-
}
|
|
2532
|
-
|
|
2533
|
-
/**
|
|
2534
|
-
* @param {TransformContext} transform_context
|
|
2535
|
-
* @returns {string[]}
|
|
2536
|
-
*/
|
|
2537
|
-
function get_host_html_conflicting_attribute_names(transform_context) {
|
|
2538
|
-
switch (transform_context.platform.name) {
|
|
2539
|
-
case 'Solid':
|
|
2540
|
-
return ['innerHTML', 'textContent'];
|
|
2541
|
-
case 'Vue':
|
|
2542
|
-
return ['innerHTML'];
|
|
2543
|
-
default:
|
|
2544
|
-
return [get_host_html_attribute_name(transform_context)];
|
|
2545
|
-
}
|
|
2546
|
-
}
|
|
2626
|
+
const opening_element_node = b.jsx_opening_element(
|
|
2627
|
+
name,
|
|
2628
|
+
attributes,
|
|
2629
|
+
selfClosing,
|
|
2630
|
+
node.openingElement?.typeArguments,
|
|
2631
|
+
);
|
|
2632
|
+
const openingElement = has_unmappable_attribute
|
|
2633
|
+
? opening_element_node
|
|
2634
|
+
: set_loc(opening_element_node, node.openingElement || node);
|
|
2547
2635
|
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
}
|
|
2636
|
+
const closingElement = selfClosing
|
|
2637
|
+
? null
|
|
2638
|
+
: set_loc(
|
|
2639
|
+
b.jsx_closing_element(
|
|
2640
|
+
clone_jsx_name(name, node.closingElement?.name || node.closingElement || node),
|
|
2641
|
+
),
|
|
2642
|
+
node.closingElement || node,
|
|
2643
|
+
);
|
|
2557
2644
|
|
|
2558
|
-
|
|
2559
|
-
* @param {any[]} attributes
|
|
2560
|
-
* @param {string} name
|
|
2561
|
-
* @returns {boolean}
|
|
2562
|
-
*/
|
|
2563
|
-
function has_jsx_attribute(attributes, name) {
|
|
2564
|
-
return attributes.some(
|
|
2565
|
-
(attr) =>
|
|
2566
|
-
attr?.type === 'JSXAttribute' &&
|
|
2567
|
-
attr.name?.type === 'JSXIdentifier' &&
|
|
2568
|
-
attr.name.name === name,
|
|
2569
|
-
);
|
|
2645
|
+
return set_loc(b.jsx_element_fresh(openingElement, closingElement, children), node);
|
|
2570
2646
|
}
|
|
2571
2647
|
|
|
2572
2648
|
/**
|
|
@@ -2616,18 +2692,14 @@ function child_contains_return_semantics(node) {
|
|
|
2616
2692
|
return false;
|
|
2617
2693
|
}
|
|
2618
2694
|
|
|
2619
|
-
if (
|
|
2620
|
-
(node.type === 'ReturnStatement' && node.argument == null) ||
|
|
2621
|
-
is_lone_return_if_statement(node)
|
|
2622
|
-
) {
|
|
2695
|
+
if (node.type === 'ReturnStatement') {
|
|
2623
2696
|
return true;
|
|
2624
2697
|
}
|
|
2625
2698
|
|
|
2626
2699
|
if (
|
|
2627
2700
|
node.type === 'FunctionDeclaration' ||
|
|
2628
2701
|
node.type === 'FunctionExpression' ||
|
|
2629
|
-
node.type === 'ArrowFunctionExpression'
|
|
2630
|
-
node.type === 'Component'
|
|
2702
|
+
node.type === 'ArrowFunctionExpression'
|
|
2631
2703
|
) {
|
|
2632
2704
|
return false;
|
|
2633
2705
|
}
|
|
@@ -2662,7 +2734,10 @@ function is_inline_element_child(node) {
|
|
|
2662
2734
|
* @returns {ESTreeJSX.JSXExpressionContainer}
|
|
2663
2735
|
*/
|
|
2664
2736
|
function statement_body_to_jsx_child(body_nodes, transform_context) {
|
|
2665
|
-
if (
|
|
2737
|
+
if (
|
|
2738
|
+
should_extract_hook_helpers(transform_context) &&
|
|
2739
|
+
body_contains_top_level_hook_call(body_nodes, transform_context, true)
|
|
2740
|
+
) {
|
|
2666
2741
|
return hook_safe_statement_body_to_jsx_child(body_nodes, transform_context);
|
|
2667
2742
|
}
|
|
2668
2743
|
|
|
@@ -3223,8 +3298,7 @@ function references_name_in_set(node, names) {
|
|
|
3223
3298
|
if (
|
|
3224
3299
|
node.type === 'FunctionDeclaration' ||
|
|
3225
3300
|
node.type === 'FunctionExpression' ||
|
|
3226
|
-
node.type === 'ArrowFunctionExpression'
|
|
3227
|
-
node.type === 'Component'
|
|
3301
|
+
node.type === 'ArrowFunctionExpression'
|
|
3228
3302
|
) {
|
|
3229
3303
|
return false;
|
|
3230
3304
|
}
|
|
@@ -3369,8 +3443,7 @@ function find_first_hook_call_name(node) {
|
|
|
3369
3443
|
if (
|
|
3370
3444
|
node.type === 'FunctionDeclaration' ||
|
|
3371
3445
|
node.type === 'FunctionExpression' ||
|
|
3372
|
-
node.type === 'ArrowFunctionExpression'
|
|
3373
|
-
node.type === 'Component'
|
|
3446
|
+
node.type === 'ArrowFunctionExpression'
|
|
3374
3447
|
) {
|
|
3375
3448
|
return null;
|
|
3376
3449
|
}
|
|
@@ -3477,7 +3550,6 @@ export function create_hook_safe_helper(
|
|
|
3477
3550
|
params,
|
|
3478
3551
|
b.block(build_render_statements(body_nodes, true, transform_context)),
|
|
3479
3552
|
);
|
|
3480
|
-
helper_fn.metadata.is_component = true;
|
|
3481
3553
|
helper_fn.metadata.is_method = false;
|
|
3482
3554
|
|
|
3483
3555
|
transform_context.available_bindings = saved_bindings;
|
|
@@ -3697,108 +3769,6 @@ function get_body_source_node(body_nodes) {
|
|
|
3697
3769
|
return first;
|
|
3698
3770
|
}
|
|
3699
3771
|
|
|
3700
|
-
/**
|
|
3701
|
-
* @param {any} node
|
|
3702
|
-
* @param {TransformContext} transform_context
|
|
3703
|
-
* @param {any[]} path
|
|
3704
|
-
*/
|
|
3705
|
-
function validate_style_directive(node, transform_context, path) {
|
|
3706
|
-
const { attribute, element } = get_style_attribute_context(node, path);
|
|
3707
|
-
|
|
3708
|
-
if (!attribute) {
|
|
3709
|
-
error(
|
|
3710
|
-
'`{style "class_name"}` can only be used as an element attribute value.',
|
|
3711
|
-
transform_context.filename,
|
|
3712
|
-
node,
|
|
3713
|
-
transform_context.errors,
|
|
3714
|
-
transform_context.comments,
|
|
3715
|
-
);
|
|
3716
|
-
}
|
|
3717
|
-
|
|
3718
|
-
if (element && is_dom_style_target(element)) {
|
|
3719
|
-
error(
|
|
3720
|
-
'`{style "class_name"}` cannot be used directly on DOM elements. Pass the class to a child component instead.',
|
|
3721
|
-
transform_context.filename,
|
|
3722
|
-
node,
|
|
3723
|
-
transform_context.errors,
|
|
3724
|
-
transform_context.comments,
|
|
3725
|
-
);
|
|
3726
|
-
}
|
|
3727
|
-
|
|
3728
|
-
if (!transform_context.current_css_hash) {
|
|
3729
|
-
error(
|
|
3730
|
-
'`{style "class_name"}` requires a <style> block in the current component.',
|
|
3731
|
-
transform_context.filename,
|
|
3732
|
-
node,
|
|
3733
|
-
transform_context.errors,
|
|
3734
|
-
transform_context.comments,
|
|
3735
|
-
);
|
|
3736
|
-
}
|
|
3737
|
-
}
|
|
3738
|
-
|
|
3739
|
-
/**
|
|
3740
|
-
* @param {any} node
|
|
3741
|
-
* @param {any[]} path
|
|
3742
|
-
* @returns {{ attribute: any, element: any }}
|
|
3743
|
-
*/
|
|
3744
|
-
function get_style_attribute_context(node, path) {
|
|
3745
|
-
const parent = path.at(-1);
|
|
3746
|
-
const attribute =
|
|
3747
|
-
parent?.type === 'Attribute' && parent.value === node
|
|
3748
|
-
? parent
|
|
3749
|
-
: path
|
|
3750
|
-
.findLast((ancestor) => ancestor?.type === 'Element')
|
|
3751
|
-
?.attributes?.find(
|
|
3752
|
-
(/** @type {any} */ attr) =>
|
|
3753
|
-
attr?.type === 'Attribute' &&
|
|
3754
|
-
(attr.value === node || node_contains(attr.value, node)),
|
|
3755
|
-
);
|
|
3756
|
-
const element = path.findLast(
|
|
3757
|
-
(ancestor) =>
|
|
3758
|
-
ancestor?.type === 'Element' &&
|
|
3759
|
-
(!attribute || ancestor.attributes?.some((/** @type {any} */ attr) => attr === attribute)),
|
|
3760
|
-
);
|
|
3761
|
-
|
|
3762
|
-
return { attribute: attribute ?? null, element: element ?? null };
|
|
3763
|
-
}
|
|
3764
|
-
|
|
3765
|
-
/**
|
|
3766
|
-
* @param {any} root
|
|
3767
|
-
* @param {any} target
|
|
3768
|
-
* @returns {boolean}
|
|
3769
|
-
*/
|
|
3770
|
-
function node_contains(root, target) {
|
|
3771
|
-
if (!root || typeof root !== 'object') {
|
|
3772
|
-
return false;
|
|
3773
|
-
}
|
|
3774
|
-
if (root === target) {
|
|
3775
|
-
return true;
|
|
3776
|
-
}
|
|
3777
|
-
if (Array.isArray(root)) {
|
|
3778
|
-
return root.some((child) => node_contains(child, target));
|
|
3779
|
-
}
|
|
3780
|
-
for (const key of Object.keys(root)) {
|
|
3781
|
-
if (key === 'loc' || key === 'start' || key === 'end' || key === 'metadata') {
|
|
3782
|
-
continue;
|
|
3783
|
-
}
|
|
3784
|
-
if (node_contains(root[key], target)) {
|
|
3785
|
-
return true;
|
|
3786
|
-
}
|
|
3787
|
-
}
|
|
3788
|
-
return false;
|
|
3789
|
-
}
|
|
3790
|
-
|
|
3791
|
-
/**
|
|
3792
|
-
* @param {any} element
|
|
3793
|
-
* @returns {boolean}
|
|
3794
|
-
*/
|
|
3795
|
-
function is_dom_style_target(element) {
|
|
3796
|
-
if (!element?.id || is_dynamic_element_id(element.id)) {
|
|
3797
|
-
return false;
|
|
3798
|
-
}
|
|
3799
|
-
return element.id.type === 'Identifier' && /^[a-z]/.test(element.id.name);
|
|
3800
|
-
}
|
|
3801
|
-
|
|
3802
3772
|
/**
|
|
3803
3773
|
* @param {any} node
|
|
3804
3774
|
* @param {TransformContext} transform_context
|
|
@@ -3821,8 +3791,6 @@ function to_jsx_child(node, transform_context) {
|
|
|
3821
3791
|
return to_jsx_expression_container(to_text_expression(node.expression, node), node);
|
|
3822
3792
|
case 'TSRXExpression':
|
|
3823
3793
|
return to_jsx_expression_container(node.expression, node);
|
|
3824
|
-
case 'Html':
|
|
3825
|
-
return recover_invalid_html_child(node, transform_context);
|
|
3826
3794
|
case 'IfStatement':
|
|
3827
3795
|
return (
|
|
3828
3796
|
transform_context.platform.hooks?.controlFlow?.ifStatement ?? if_statement_to_jsx_child
|
|
@@ -3846,7 +3814,7 @@ function to_jsx_child(node, transform_context) {
|
|
|
3846
3814
|
}
|
|
3847
3815
|
|
|
3848
3816
|
/**
|
|
3849
|
-
* Lower a
|
|
3817
|
+
* Lower a native TSRX fragment body to a JSX expression.
|
|
3850
3818
|
* Unlike `<tsx>`, children have already been parsed and transformed through
|
|
3851
3819
|
* the normal TSRX Element/Text/control-flow visitors.
|
|
3852
3820
|
*
|
|
@@ -3902,7 +3870,7 @@ function tsrx_node_to_jsx_expression(node, transform_context, in_jsx_child = fal
|
|
|
3902
3870
|
}
|
|
3903
3871
|
|
|
3904
3872
|
/**
|
|
3905
|
-
* Explicit return values inside expression-position
|
|
3873
|
+
* Explicit return values inside expression-position native templates are JavaScript
|
|
3906
3874
|
* values, so keep them out of platform render control flow.
|
|
3907
3875
|
*
|
|
3908
3876
|
* @param {any[]} body_nodes
|
|
@@ -3958,8 +3926,7 @@ function body_contains_top_level_return_value(node) {
|
|
|
3958
3926
|
node.type === 'FunctionExpression' ||
|
|
3959
3927
|
node.type === 'ArrowFunctionExpression' ||
|
|
3960
3928
|
node.type === 'ClassDeclaration' ||
|
|
3961
|
-
node.type === 'ClassExpression'
|
|
3962
|
-
node.type === 'Component'
|
|
3929
|
+
node.type === 'ClassExpression'
|
|
3963
3930
|
) {
|
|
3964
3931
|
return false;
|
|
3965
3932
|
}
|
|
@@ -4153,7 +4120,12 @@ function find_key_expression_in_body(body_nodes) {
|
|
|
4153
4120
|
* @returns {any}
|
|
4154
4121
|
*/
|
|
4155
4122
|
function continue_to_bare_return(source_node) {
|
|
4156
|
-
|
|
4123
|
+
const node = set_loc(b.return(null), source_node);
|
|
4124
|
+
node.metadata = {
|
|
4125
|
+
...(node.metadata || {}),
|
|
4126
|
+
generated_loop_continue_return: true,
|
|
4127
|
+
};
|
|
4128
|
+
return node;
|
|
4157
4129
|
}
|
|
4158
4130
|
|
|
4159
4131
|
/**
|
|
@@ -4214,7 +4186,7 @@ function is_loop_statement(node) {
|
|
|
4214
4186
|
function for_of_statement_to_jsx_child(node, transform_context) {
|
|
4215
4187
|
if (node.await) {
|
|
4216
4188
|
error(
|
|
4217
|
-
`${transform_context.platform.name} TSRX does not support \`for await...of\` in
|
|
4189
|
+
`${transform_context.platform.name} TSRX does not support \`for await...of\` in TSRX templates.`,
|
|
4218
4190
|
transform_context.filename,
|
|
4219
4191
|
node,
|
|
4220
4192
|
transform_context.errors,
|
|
@@ -4228,7 +4200,9 @@ function for_of_statement_to_jsx_child(node, transform_context) {
|
|
|
4228
4200
|
node.body.type === 'BlockStatement' ? node.body.body : [node.body],
|
|
4229
4201
|
)
|
|
4230
4202
|
);
|
|
4231
|
-
const has_hooks =
|
|
4203
|
+
const has_hooks =
|
|
4204
|
+
should_extract_hook_helpers(transform_context) &&
|
|
4205
|
+
body_contains_top_level_hook_call(loop_body, transform_context, true);
|
|
4232
4206
|
const body_key_expression = find_key_expression_in_body(loop_body);
|
|
4233
4207
|
const explicit_key_expression =
|
|
4234
4208
|
body_key_expression ?? (node.key ? clone_expression_node(node.key) : undefined);
|
|
@@ -4457,7 +4431,7 @@ function try_statement_to_jsx_child(node, transform_context) {
|
|
|
4457
4431
|
|
|
4458
4432
|
if (finalizer) {
|
|
4459
4433
|
error(
|
|
4460
|
-
`${transform_context.platform.name} TSRX does not support JavaScript \`try/finally\` in
|
|
4434
|
+
`${transform_context.platform.name} TSRX does not support JavaScript \`try/finally\` in TSRX templates. \`finally\` is not part of TSRX control flow; move the try/finally into a function if you need cleanup logic.`,
|
|
4461
4435
|
transform_context.filename,
|
|
4462
4436
|
finalizer,
|
|
4463
4437
|
transform_context.errors,
|
|
@@ -4467,7 +4441,7 @@ function try_statement_to_jsx_child(node, transform_context) {
|
|
|
4467
4441
|
|
|
4468
4442
|
if (!pending && !handler) {
|
|
4469
4443
|
error(
|
|
4470
|
-
'
|
|
4444
|
+
'TSRX try statements must have a `pending` or `catch` block.',
|
|
4471
4445
|
transform_context.filename,
|
|
4472
4446
|
node,
|
|
4473
4447
|
transform_context.errors,
|
|
@@ -4491,7 +4465,7 @@ function try_statement_to_jsx_child(node, transform_context) {
|
|
|
4491
4465
|
const try_body = node.block.body || [];
|
|
4492
4466
|
if (!try_body.some(is_jsx_child)) {
|
|
4493
4467
|
error(
|
|
4494
|
-
'
|
|
4468
|
+
'TSRX try statements must contain a template in their main body. Move the try statement into a function if it does not render anything.',
|
|
4495
4469
|
transform_context.filename,
|
|
4496
4470
|
node.block,
|
|
4497
4471
|
transform_context.errors,
|
|
@@ -4501,7 +4475,7 @@ function try_statement_to_jsx_child(node, transform_context) {
|
|
|
4501
4475
|
const pending_body = pending.body || [];
|
|
4502
4476
|
if (pending_body.length > 0 && !pending_body.some(is_jsx_child)) {
|
|
4503
4477
|
error(
|
|
4504
|
-
'
|
|
4478
|
+
'TSRX try statements must contain a template in their "pending" body. Rendering a pending fallback is required to have a template.',
|
|
4505
4479
|
transform_context.filename,
|
|
4506
4480
|
pending,
|
|
4507
4481
|
transform_context.errors,
|
|
@@ -4714,12 +4688,14 @@ function inject_try_imports(program, transform_context, platform, suspense_sourc
|
|
|
4714
4688
|
transform_context.needs_merge_refs && platform.imports.mergeRefs
|
|
4715
4689
|
? platform.imports.mergeRefs
|
|
4716
4690
|
: null;
|
|
4717
|
-
const ref_prop_source =
|
|
4718
|
-
transform_context.needs_ref_prop && platform.imports.refProp ? platform.imports.refProp : null;
|
|
4719
4691
|
const normalize_spread_props_source =
|
|
4720
4692
|
transform_context.needs_normalize_spread_props && platform.imports.refProp
|
|
4721
4693
|
? platform.imports.refProp
|
|
4722
4694
|
: null;
|
|
4695
|
+
const normalize_spread_props_for_ref_attr_source =
|
|
4696
|
+
transform_context.needs_normalize_spread_props_for_ref_attr && platform.imports.refProp
|
|
4697
|
+
? platform.imports.refProp
|
|
4698
|
+
: null;
|
|
4723
4699
|
|
|
4724
4700
|
/** @type {Map<string, any[]>} */
|
|
4725
4701
|
const ref_imports = new Map();
|
|
@@ -4732,19 +4708,22 @@ function inject_try_imports(program, transform_context, platform, suspense_sourc
|
|
|
4732
4708
|
);
|
|
4733
4709
|
}
|
|
4734
4710
|
|
|
4735
|
-
if (
|
|
4711
|
+
if (normalize_spread_props_source !== null) {
|
|
4736
4712
|
add_ref_import_specifier(
|
|
4737
4713
|
ref_imports,
|
|
4738
|
-
|
|
4739
|
-
b.import_specifier('
|
|
4714
|
+
normalize_spread_props_source,
|
|
4715
|
+
b.import_specifier('normalize_spread_props', NORMALIZE_SPREAD_PROPS_INTERNAL_NAME),
|
|
4740
4716
|
);
|
|
4741
4717
|
}
|
|
4742
4718
|
|
|
4743
|
-
if (
|
|
4719
|
+
if (normalize_spread_props_for_ref_attr_source !== null) {
|
|
4744
4720
|
add_ref_import_specifier(
|
|
4745
4721
|
ref_imports,
|
|
4746
|
-
|
|
4747
|
-
b.import_specifier(
|
|
4722
|
+
normalize_spread_props_for_ref_attr_source,
|
|
4723
|
+
b.import_specifier(
|
|
4724
|
+
'normalize_spread_props_for_ref_attr',
|
|
4725
|
+
NORMALIZE_SPREAD_PROPS_FOR_REF_ATTR_INTERNAL_NAME,
|
|
4726
|
+
),
|
|
4748
4727
|
);
|
|
4749
4728
|
}
|
|
4750
4729
|
|
|
@@ -4779,11 +4758,9 @@ function add_ref_import_specifier(imports, source, specifier) {
|
|
|
4779
4758
|
function create_render_if_statement(node, transform_context) {
|
|
4780
4759
|
const consequent_body =
|
|
4781
4760
|
node.consequent.type === 'BlockStatement' ? node.consequent.body : [node.consequent];
|
|
4782
|
-
const consequent_has_hooks =
|
|
4783
|
-
|
|
4784
|
-
transform_context,
|
|
4785
|
-
true,
|
|
4786
|
-
);
|
|
4761
|
+
const consequent_has_hooks =
|
|
4762
|
+
should_extract_hook_helpers(transform_context) &&
|
|
4763
|
+
body_contains_top_level_hook_call(consequent_body, transform_context, true);
|
|
4787
4764
|
|
|
4788
4765
|
let alternate = null;
|
|
4789
4766
|
if (node.alternate) {
|
|
@@ -4791,11 +4768,9 @@ function create_render_if_statement(node, transform_context) {
|
|
|
4791
4768
|
alternate = create_render_if_statement(node.alternate, transform_context);
|
|
4792
4769
|
} else {
|
|
4793
4770
|
const alternate_body = node.alternate.body || [node.alternate];
|
|
4794
|
-
const alternate_has_hooks =
|
|
4795
|
-
|
|
4796
|
-
transform_context,
|
|
4797
|
-
true,
|
|
4798
|
-
);
|
|
4771
|
+
const alternate_has_hooks =
|
|
4772
|
+
should_extract_hook_helpers(transform_context) &&
|
|
4773
|
+
body_contains_top_level_hook_call(alternate_body, transform_context, true);
|
|
4799
4774
|
alternate = set_loc(
|
|
4800
4775
|
b.block(
|
|
4801
4776
|
alternate_has_hooks
|
|
@@ -4912,7 +4887,10 @@ export function plan_switch_lift(switch_node, transform_context) {
|
|
|
4912
4887
|
const needs_helper = case_info.map(
|
|
4913
4888
|
(/** @type {{ own_body: any[], has_terminator: boolean }} */ info, /** @type {number} */ k) => {
|
|
4914
4889
|
if (info.own_body.length === 0) return false;
|
|
4915
|
-
if (
|
|
4890
|
+
if (
|
|
4891
|
+
should_extract_hook_helpers(transform_context) &&
|
|
4892
|
+
body_contains_top_level_hook_call(info.own_body, transform_context, true)
|
|
4893
|
+
) {
|
|
4916
4894
|
return true;
|
|
4917
4895
|
}
|
|
4918
4896
|
if (k === 0) return false;
|
|
@@ -5052,7 +5030,7 @@ function build_switch_with_lift(switch_node, transform_context) {
|
|
|
5052
5030
|
let has_terminal = false;
|
|
5053
5031
|
|
|
5054
5032
|
for (const child of own_body) {
|
|
5055
|
-
if (
|
|
5033
|
+
if (is_loop_skip_return_statement(child)) {
|
|
5056
5034
|
case_body.push(create_component_return_statement(render_nodes, child));
|
|
5057
5035
|
has_terminal = true;
|
|
5058
5036
|
break;
|
|
@@ -5155,13 +5133,13 @@ function to_jsx_expression_container(expression, source_node = expression) {
|
|
|
5155
5133
|
* the default "map over `to_jsx_attribute`" via
|
|
5156
5134
|
* `hooks.transformElementAttributes`. Whether or not the hook is used,
|
|
5157
5135
|
* the result is run through `merge_duplicate_refs` so platforms with a
|
|
5158
|
-
* `multiRefStrategy`
|
|
5136
|
+
* `multiRefStrategy` can compose an explicit `ref={...}` with compiler-
|
|
5137
|
+
* synthesized refs created for host spreads.
|
|
5159
5138
|
*
|
|
5160
5139
|
* Before lowering, the raw attribute list is validated to reject elements
|
|
5161
5140
|
* with more than one TSX-style `ref={...}` attribute — that shape produces
|
|
5162
5141
|
* duplicate JSX props which the JSX runtime collapses to last-wins (and
|
|
5163
|
-
* which TypeScript can't type cleanly).
|
|
5164
|
-
* keyword-form refs remain valid and merge into a single ref attribute.
|
|
5142
|
+
* which TypeScript can't type cleanly).
|
|
5165
5143
|
*
|
|
5166
5144
|
* @param {any[]} attrs
|
|
5167
5145
|
* @param {TransformContext} transform_context
|
|
@@ -5171,7 +5149,6 @@ function to_jsx_expression_container(expression, source_node = expression) {
|
|
|
5171
5149
|
function transform_element_attributes_dispatch(attrs, transform_context, element) {
|
|
5172
5150
|
validate_at_most_one_ref_attribute(attrs, transform_context);
|
|
5173
5151
|
const is_component = is_component_like_element(element);
|
|
5174
|
-
attrs = normalize_named_ref_attributes(attrs, !is_component, transform_context);
|
|
5175
5152
|
const preprocess = transform_context.platform.hooks?.preprocessElementAttributes;
|
|
5176
5153
|
if (preprocess) {
|
|
5177
5154
|
attrs = preprocess(attrs, transform_context, element);
|
|
@@ -5180,43 +5157,12 @@ function transform_element_attributes_dispatch(attrs, transform_context, element
|
|
|
5180
5157
|
const result = hook
|
|
5181
5158
|
? hook(attrs, transform_context, element)
|
|
5182
5159
|
: attrs.map((/** @type {any} */ a) => to_jsx_attribute(a, transform_context));
|
|
5183
|
-
if (transform_context.typeOnly) {
|
|
5184
|
-
add_ref_target_type_to_ref_prop_attributes(
|
|
5185
|
-
result,
|
|
5186
|
-
!is_component ? create_element_ref_target_type(element) : null,
|
|
5187
|
-
);
|
|
5188
|
-
}
|
|
5189
5160
|
return merge_duplicate_refs(
|
|
5190
5161
|
normalize_host_ref_spreads(result, !is_component, transform_context),
|
|
5191
5162
|
transform_context,
|
|
5192
5163
|
);
|
|
5193
5164
|
}
|
|
5194
5165
|
|
|
5195
|
-
/**
|
|
5196
|
-
* @param {any[]} attrs
|
|
5197
|
-
* @param {AST.TypeNode | null} ref_target_type
|
|
5198
|
-
* @returns {void}
|
|
5199
|
-
*/
|
|
5200
|
-
export function add_ref_target_type_to_ref_prop_attributes(attrs, ref_target_type) {
|
|
5201
|
-
if (!ref_target_type) return;
|
|
5202
|
-
for (const attr of attrs) {
|
|
5203
|
-
const expression =
|
|
5204
|
-
attr?.type === 'JSXAttribute' &&
|
|
5205
|
-
attr.value?.type === 'JSXExpressionContainer' &&
|
|
5206
|
-
attr.value.expression?.type !== 'JSXEmptyExpression'
|
|
5207
|
-
? attr.value.expression
|
|
5208
|
-
: null;
|
|
5209
|
-
if (
|
|
5210
|
-
expression?.type === 'CallExpression' &&
|
|
5211
|
-
expression.callee?.type === 'Identifier' &&
|
|
5212
|
-
expression.callee.name === CREATE_REF_PROP_INTERNAL_NAME &&
|
|
5213
|
-
!expression.typeArguments
|
|
5214
|
-
) {
|
|
5215
|
-
expression.typeArguments = b.ts_type_parameter_instantiation([ref_target_type]);
|
|
5216
|
-
}
|
|
5217
|
-
}
|
|
5218
|
-
}
|
|
5219
|
-
|
|
5220
5166
|
/**
|
|
5221
5167
|
* @param {any} element
|
|
5222
5168
|
* @returns {boolean}
|
|
@@ -5242,48 +5188,6 @@ function is_component_like_jsx_name(name) {
|
|
|
5242
5188
|
return false;
|
|
5243
5189
|
}
|
|
5244
5190
|
|
|
5245
|
-
/**
|
|
5246
|
-
* @param {any[]} attrs
|
|
5247
|
-
* @param {boolean} is_host
|
|
5248
|
-
* @param {TransformContext} transform_context
|
|
5249
|
-
* @returns {any[]}
|
|
5250
|
-
*/
|
|
5251
|
-
function normalize_named_ref_attributes(attrs, is_host, transform_context) {
|
|
5252
|
-
if (!is_host) return attrs;
|
|
5253
|
-
|
|
5254
|
-
return attrs.map((attr) => {
|
|
5255
|
-
if (!is_named_ref_attribute(attr)) {
|
|
5256
|
-
return attr;
|
|
5257
|
-
}
|
|
5258
|
-
|
|
5259
|
-
if (transform_context.typeOnly) {
|
|
5260
|
-
return mark_type_only_named_ref_attribute(attr);
|
|
5261
|
-
}
|
|
5262
|
-
|
|
5263
|
-
return {
|
|
5264
|
-
...attr,
|
|
5265
|
-
metadata: { ...(attr.metadata || {}), from_ref_keyword: true },
|
|
5266
|
-
name: attr.name?.type === 'JSXIdentifier' ? { ...attr.name, name: 'ref' } : b.id('ref'),
|
|
5267
|
-
};
|
|
5268
|
-
});
|
|
5269
|
-
}
|
|
5270
|
-
|
|
5271
|
-
/**
|
|
5272
|
-
* @param {any} attr
|
|
5273
|
-
* @returns {any}
|
|
5274
|
-
*/
|
|
5275
|
-
function mark_type_only_named_ref_attribute(attr) {
|
|
5276
|
-
return {
|
|
5277
|
-
...attr,
|
|
5278
|
-
name: attr.name
|
|
5279
|
-
? {
|
|
5280
|
-
...attr.name,
|
|
5281
|
-
metadata: { ...(attr.name.metadata || {}), disable_verification: true },
|
|
5282
|
-
}
|
|
5283
|
-
: attr.name,
|
|
5284
|
-
};
|
|
5285
|
-
}
|
|
5286
|
-
|
|
5287
5191
|
/**
|
|
5288
5192
|
* @param {any[]} attrs
|
|
5289
5193
|
* @param {boolean} is_host
|
|
@@ -5305,8 +5209,15 @@ function normalize_host_ref_spreads(attrs, is_host, transform_context) {
|
|
|
5305
5209
|
return [attr];
|
|
5306
5210
|
}
|
|
5307
5211
|
|
|
5308
|
-
|
|
5309
|
-
|
|
5212
|
+
const normalize_helper = needs_synthetic_spread_ref
|
|
5213
|
+
? NORMALIZE_SPREAD_PROPS_FOR_REF_ATTR_INTERNAL_NAME
|
|
5214
|
+
: NORMALIZE_SPREAD_PROPS_INTERNAL_NAME;
|
|
5215
|
+
if (needs_synthetic_spread_ref) {
|
|
5216
|
+
transform_context.needs_normalize_spread_props_for_ref_attr = true;
|
|
5217
|
+
} else {
|
|
5218
|
+
transform_context.needs_normalize_spread_props = true;
|
|
5219
|
+
}
|
|
5220
|
+
const normalized = b.call(normalize_helper, attr.argument);
|
|
5310
5221
|
|
|
5311
5222
|
if (needs_synthetic_spread_ref) {
|
|
5312
5223
|
const normalized_id = create_generated_identifier(
|
|
@@ -5323,7 +5234,7 @@ function normalize_host_ref_spreads(attrs, is_host, transform_context) {
|
|
|
5323
5234
|
attr,
|
|
5324
5235
|
);
|
|
5325
5236
|
ref_attr.metadata = { ...(ref_attr.metadata || {}) };
|
|
5326
|
-
/** @type {any} */ (ref_attr.metadata).
|
|
5237
|
+
/** @type {any} */ (ref_attr.metadata).synthetic_ref = true;
|
|
5327
5238
|
add_jsx_setup_declaration(spread, b.let(clone_identifier(normalized_id), normalized));
|
|
5328
5239
|
|
|
5329
5240
|
return [spread, ref_attr];
|
|
@@ -5412,69 +5323,10 @@ function wrap_jsx_setup_declarations(expression, in_jsx_child) {
|
|
|
5412
5323
|
return in_jsx_child ? to_jsx_expression_container(call, expression) : call;
|
|
5413
5324
|
}
|
|
5414
5325
|
|
|
5415
|
-
/**
|
|
5416
|
-
* @param {any} attr
|
|
5417
|
-
* @returns {boolean}
|
|
5418
|
-
*/
|
|
5419
|
-
function is_named_ref_attribute(attr) {
|
|
5420
|
-
return !!(
|
|
5421
|
-
attr &&
|
|
5422
|
-
(attr.type === 'Attribute' || attr.type === 'JSXAttribute') &&
|
|
5423
|
-
attr.name &&
|
|
5424
|
-
((attr.name.type === 'Identifier' && attr.name.name !== 'ref') ||
|
|
5425
|
-
(attr.name.type === 'JSXIdentifier' && attr.name.name !== 'ref')) &&
|
|
5426
|
-
(attr.value?.type === 'RefExpression' ||
|
|
5427
|
-
is_ref_prop_expression(attr.value) ||
|
|
5428
|
-
(attr.value?.type === 'JSXExpressionContainer' &&
|
|
5429
|
-
is_ref_prop_expression(attr.value.expression)))
|
|
5430
|
-
);
|
|
5431
|
-
}
|
|
5432
|
-
|
|
5433
|
-
/**
|
|
5434
|
-
* @param {any} html_expression
|
|
5435
|
-
* @param {any} source_attr
|
|
5436
|
-
* @param {TransformContext} transform_context
|
|
5437
|
-
* @returns {any}
|
|
5438
|
-
*/
|
|
5439
|
-
export function create_host_html_attribute(html_expression, source_attr, transform_context) {
|
|
5440
|
-
const expression =
|
|
5441
|
-
html_expression?.type === 'Html' ? html_expression.expression : html_expression;
|
|
5442
|
-
const name = get_host_html_attribute_name(transform_context);
|
|
5443
|
-
const value =
|
|
5444
|
-
name === 'dangerouslySetInnerHTML'
|
|
5445
|
-
? set_loc(b.object([b.prop('init', b.id('__html'), expression)]), source_attr)
|
|
5446
|
-
: expression;
|
|
5447
|
-
const value_container = to_jsx_expression_container(value, source_attr);
|
|
5448
|
-
if (name !== 'dangerouslySetInnerHTML') {
|
|
5449
|
-
setLocation(value_container, source_attr, true);
|
|
5450
|
-
}
|
|
5451
|
-
|
|
5452
|
-
return set_loc(
|
|
5453
|
-
build_jsx_attribute(b.jsx_id(name), value_container, false, source_attr),
|
|
5454
|
-
source_attr,
|
|
5455
|
-
);
|
|
5456
|
-
}
|
|
5457
|
-
|
|
5458
|
-
/**
|
|
5459
|
-
* @param {any} expression
|
|
5460
|
-
* @returns {boolean}
|
|
5461
|
-
*/
|
|
5462
|
-
export function is_ref_prop_expression(expression) {
|
|
5463
|
-
return (
|
|
5464
|
-
expression?.type === 'RefExpression' ||
|
|
5465
|
-
(expression?.type === 'CallExpression' &&
|
|
5466
|
-
expression.callee?.type === 'Identifier' &&
|
|
5467
|
-
expression.callee.name === CREATE_REF_PROP_INTERNAL_NAME)
|
|
5468
|
-
);
|
|
5469
|
-
}
|
|
5470
|
-
|
|
5471
5326
|
/**
|
|
5472
5327
|
* Reject elements with more than one TSX-style `ref={...}` attribute.
|
|
5473
|
-
*
|
|
5474
|
-
*
|
|
5475
|
-
* feature that compose via the merge pass. This validator runs over the
|
|
5476
|
-
* raw, pre-lowering attribute list so each shape is still distinguishable
|
|
5477
|
-
* by `type`. Ripple `Element` attributes have type `Attribute` with an
|
|
5328
|
+
* This validator runs over the raw, pre-lowering attribute list so each
|
|
5329
|
+
* shape is still distinguishable by `type`. Ripple `Element` attributes have type `Attribute` with an
|
|
5478
5330
|
* `Identifier` name (the parser normalizes `JSXAttribute`/`JSXIdentifier`
|
|
5479
5331
|
* for non-Tsx elements); inside `<tsx:react>` compat blocks they retain
|
|
5480
5332
|
* the original `JSXAttribute`/`JSXIdentifier` shape, so we accept both.
|
|
@@ -5510,7 +5362,7 @@ export function validate_at_most_one_ref_attribute(raw_attrs, transform_context)
|
|
|
5510
5362
|
}
|
|
5511
5363
|
error(
|
|
5512
5364
|
'Element has multiple `ref={...}` attributes; an element may have at most one. ' +
|
|
5513
|
-
|
|
5365
|
+
'Use a single array-valued ref such as `ref={[a, b]}` where the target framework supports multiple refs.',
|
|
5514
5366
|
transform_context?.filename ?? null,
|
|
5515
5367
|
node,
|
|
5516
5368
|
transform_context?.errors,
|
|
@@ -5520,11 +5372,9 @@ export function validate_at_most_one_ref_attribute(raw_attrs, transform_context)
|
|
|
5520
5372
|
}
|
|
5521
5373
|
|
|
5522
5374
|
/**
|
|
5523
|
-
* Collapse
|
|
5524
|
-
*
|
|
5525
|
-
*
|
|
5526
|
-
* by `to_jsx_attribute` (Ripple) or the parser (TSX-style). The shape of
|
|
5527
|
-
* the merged value depends on `platform.jsx.multiRefStrategy`:
|
|
5375
|
+
* Collapse an explicit `ref={...}` plus compiler-synthesized spread refs into
|
|
5376
|
+
* one attribute. The shape of the merged value depends on
|
|
5377
|
+
* `platform.jsx.multiRefStrategy`:
|
|
5528
5378
|
*
|
|
5529
5379
|
* - `'merge-refs'` — emit `ref={__mergeRefs(a, b, ...)}` and flag
|
|
5530
5380
|
* `needs_merge_refs` so an import is injected later. React and Preact
|
|
@@ -5550,7 +5400,7 @@ export function merge_duplicate_refs(jsx_attrs, transform_context) {
|
|
|
5550
5400
|
for (const attr of jsx_attrs) {
|
|
5551
5401
|
if (!is_jsx_ref_attribute(attr)) continue;
|
|
5552
5402
|
count += 1;
|
|
5553
|
-
if (!attr.metadata?.
|
|
5403
|
+
if (!attr.metadata?.synthetic_ref) tsx_form_count += 1;
|
|
5554
5404
|
}
|
|
5555
5405
|
if (count <= 1) return jsx_attrs;
|
|
5556
5406
|
// Two or more genuine `ref={...}` (TSX-form) attributes are already a
|
|
@@ -5571,7 +5421,7 @@ export function merge_duplicate_refs(jsx_attrs, transform_context) {
|
|
|
5571
5421
|
// Inherit loc from the (at most one) `ref={expr}`-form attribute so
|
|
5572
5422
|
// the kept `ref` keyword in the generated `ref={__mergeRefs(...)}`
|
|
5573
5423
|
// retains a source mapping back to its original `ref=` keyword.
|
|
5574
|
-
if (!source_attr && !attr.metadata?.
|
|
5424
|
+
if (!source_attr && !attr.metadata?.synthetic_ref) {
|
|
5575
5425
|
source_attr = attr;
|
|
5576
5426
|
}
|
|
5577
5427
|
} else {
|
|
@@ -5629,8 +5479,9 @@ function is_jsx_ref_attribute(attr) {
|
|
|
5629
5479
|
* identifiers and avoids shadowing user-declared `mergeRefs` symbols.
|
|
5630
5480
|
*/
|
|
5631
5481
|
export const MERGE_REFS_INTERNAL_NAME = '__mergeRefs';
|
|
5632
|
-
export const CREATE_REF_PROP_INTERNAL_NAME = '__create_ref_prop';
|
|
5633
5482
|
export const NORMALIZE_SPREAD_PROPS_INTERNAL_NAME = '__normalize_spread_props';
|
|
5483
|
+
export const NORMALIZE_SPREAD_PROPS_FOR_REF_ATTR_INTERNAL_NAME =
|
|
5484
|
+
'__normalize_spread_props_for_ref_attr';
|
|
5634
5485
|
export const MAP_ITERABLE_INTERNAL_NAME = '__map_iterable';
|
|
5635
5486
|
export const ITERATION_VALUE_INTERNAL_NAME = '__IterationValue';
|
|
5636
5487
|
|
|
@@ -5652,17 +5503,6 @@ const MATHML_REF_TAG_NAMES = new Set(
|
|
|
5652
5503
|
),
|
|
5653
5504
|
);
|
|
5654
5505
|
|
|
5655
|
-
/**
|
|
5656
|
-
* @param {any} value
|
|
5657
|
-
* @returns {boolean}
|
|
5658
|
-
*/
|
|
5659
|
-
export function is_ref_expression_attribute_value(value) {
|
|
5660
|
-
return (
|
|
5661
|
-
value?.type === 'RefExpression' ||
|
|
5662
|
-
(value?.type === 'JSXExpressionContainer' && value.expression?.type === 'RefExpression')
|
|
5663
|
-
);
|
|
5664
|
-
}
|
|
5665
|
-
|
|
5666
5506
|
/**
|
|
5667
5507
|
* @param {any} element
|
|
5668
5508
|
* @param {'html' | 'svg' | 'mathml'} [namespace]
|
|
@@ -5751,27 +5591,6 @@ function create_tag_name_map_ref_type(map_name, tag_name) {
|
|
|
5751
5591
|
export function to_jsx_attribute(attr, transform_context) {
|
|
5752
5592
|
if (!attr) return attr;
|
|
5753
5593
|
if (attr.type === 'JSXAttribute') {
|
|
5754
|
-
if (
|
|
5755
|
-
attr.value?.type === 'JSXExpressionContainer' &&
|
|
5756
|
-
attr.value.expression?.type === 'RefExpression'
|
|
5757
|
-
) {
|
|
5758
|
-
return {
|
|
5759
|
-
...attr,
|
|
5760
|
-
value: to_jsx_expression_container(
|
|
5761
|
-
create_ref_prop_call(attr.value.expression, transform_context),
|
|
5762
|
-
),
|
|
5763
|
-
metadata: { ...(attr.metadata || {}), from_ref_keyword: true },
|
|
5764
|
-
};
|
|
5765
|
-
}
|
|
5766
|
-
if (
|
|
5767
|
-
attr.value?.type === 'JSXExpressionContainer' &&
|
|
5768
|
-
is_ref_prop_expression(attr.value.expression)
|
|
5769
|
-
) {
|
|
5770
|
-
return {
|
|
5771
|
-
...attr,
|
|
5772
|
-
metadata: { ...(attr.metadata || {}), from_ref_keyword: true },
|
|
5773
|
-
};
|
|
5774
|
-
}
|
|
5775
5594
|
return attr;
|
|
5776
5595
|
}
|
|
5777
5596
|
if (attr.type === 'JSXSpreadAttribute') {
|
|
@@ -5786,26 +5605,6 @@ export function to_jsx_attribute(attr, transform_context) {
|
|
|
5786
5605
|
attr,
|
|
5787
5606
|
);
|
|
5788
5607
|
}
|
|
5789
|
-
if (attr.type === 'RefAttribute') {
|
|
5790
|
-
// `{ref expr}` and the generated `ref={expr}` have different shapes,
|
|
5791
|
-
// so the source-to-generated mapping is imprecise — but pointing
|
|
5792
|
-
// editors at the `{ref expr}` span is still useful for hover/jump,
|
|
5793
|
-
// matching how shorthand `{name}` → `name={name}` carries loc.
|
|
5794
|
-
// `from_ref_keyword` lets `merge_duplicate_refs` tell this form apart
|
|
5795
|
-
// from genuine `ref={...}` attributes without inferring it from
|
|
5796
|
-
// whether `name.loc` happens to be present.
|
|
5797
|
-
return set_loc(
|
|
5798
|
-
/** @type {any} */ ({
|
|
5799
|
-
type: 'JSXAttribute',
|
|
5800
|
-
name: { type: 'JSXIdentifier', name: 'ref', metadata: { path: [] } },
|
|
5801
|
-
value: to_jsx_expression_container(attr.argument),
|
|
5802
|
-
shorthand: false,
|
|
5803
|
-
metadata: { path: [], from_ref_keyword: true },
|
|
5804
|
-
}),
|
|
5805
|
-
attr,
|
|
5806
|
-
);
|
|
5807
|
-
}
|
|
5808
|
-
|
|
5809
5608
|
// Platforms that expect React-style DOM attrs (React) rewrite `class` to
|
|
5810
5609
|
// `className`; Preact and Solid accept `class` natively and keep it.
|
|
5811
5610
|
let attr_name = attr.name;
|
|
@@ -5824,28 +5623,15 @@ export function to_jsx_attribute(attr, transform_context) {
|
|
|
5824
5623
|
attr_name && attr_name.type === 'Identifier' ? identifier_to_jsx_name(attr_name) : attr_name;
|
|
5825
5624
|
|
|
5826
5625
|
let value = attr.value;
|
|
5827
|
-
const is_ref_expression_value =
|
|
5828
|
-
value?.type === 'RefExpression' ||
|
|
5829
|
-
is_ref_prop_expression(value) ||
|
|
5830
|
-
(value?.type === 'JSXExpressionContainer' && is_ref_prop_expression(value.expression));
|
|
5831
5626
|
if (value) {
|
|
5832
5627
|
if (value.type === 'Literal' && typeof value.value === 'string') {
|
|
5833
5628
|
// Keep string literal as attribute string.
|
|
5834
|
-
} else if (value.type === 'RefExpression') {
|
|
5835
|
-
value = to_jsx_expression_container(create_ref_prop_call(value, transform_context));
|
|
5836
5629
|
} else if (value.type !== 'JSXExpressionContainer') {
|
|
5837
5630
|
value = to_jsx_expression_container(value);
|
|
5838
|
-
} else if (value.expression?.type === 'RefExpression') {
|
|
5839
|
-
value = to_jsx_expression_container(
|
|
5840
|
-
create_ref_prop_call(value.expression, transform_context),
|
|
5841
|
-
);
|
|
5842
5631
|
}
|
|
5843
5632
|
}
|
|
5844
5633
|
|
|
5845
5634
|
const jsx_attribute = build_jsx_attribute(name, value || null, attr.shorthand === true);
|
|
5846
|
-
if (is_ref_expression_value) {
|
|
5847
|
-
/** @type {any} */ (jsx_attribute.metadata).from_ref_keyword = true;
|
|
5848
|
-
}
|
|
5849
5635
|
|
|
5850
5636
|
if (value_has_unmappable_jsx_loc(value)) {
|
|
5851
5637
|
/** @type {any} */ (jsx_attribute.metadata).has_unmappable_value = true;
|
|
@@ -5867,26 +5653,6 @@ function value_has_unmappable_jsx_loc(value) {
|
|
|
5867
5653
|
);
|
|
5868
5654
|
}
|
|
5869
5655
|
|
|
5870
|
-
/**
|
|
5871
|
-
* @param {any} node
|
|
5872
|
-
* @param {TransformContext} transform_context
|
|
5873
|
-
* @returns {any}
|
|
5874
|
-
*/
|
|
5875
|
-
function create_ref_prop_call(node, transform_context) {
|
|
5876
|
-
transform_context.needs_ref_prop = true;
|
|
5877
|
-
|
|
5878
|
-
const argument = node.argument;
|
|
5879
|
-
const args = [b.thunk(argument)];
|
|
5880
|
-
|
|
5881
|
-
if (argument.type === 'Identifier' || argument.type === 'MemberExpression') {
|
|
5882
|
-
args.push(
|
|
5883
|
-
b.arrow([b.id('v')], b.assignment('=', clone_expression_node(argument, false), b.id('v'))),
|
|
5884
|
-
);
|
|
5885
|
-
}
|
|
5886
|
-
|
|
5887
|
-
return b.call(CREATE_REF_PROP_INTERNAL_NAME, ...args);
|
|
5888
|
-
}
|
|
5889
|
-
|
|
5890
5656
|
/**
|
|
5891
5657
|
* @param {any} node
|
|
5892
5658
|
* @param {TransformContext} transform_context
|