@tsrx/core 0.1.9 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -7
- package/src/analyze/prune.js +1151 -0
- package/src/index.js +2 -0
- package/src/transform/jsx/index.js +169 -44
- package/src/transform/scoping.js +38 -12
- package/src/transform/segments.js +17 -8
- package/types/jsx-platform.d.ts +39 -1
package/src/index.js
CHANGED
|
@@ -146,6 +146,7 @@ export {
|
|
|
146
146
|
clone_switch_helper_invocation as cloneSwitchHelperInvocation,
|
|
147
147
|
collect_param_bindings as collectParamBindings,
|
|
148
148
|
collect_statement_bindings as collectStatementBindings,
|
|
149
|
+
create_hook_safe_helper as createHookSafeHelper,
|
|
149
150
|
create_host_html_attribute as createHostHtmlAttribute,
|
|
150
151
|
create_host_html_conflict_error as createHostHtmlConflictError,
|
|
151
152
|
createJsxTransform,
|
|
@@ -236,6 +237,7 @@ export {
|
|
|
236
237
|
|
|
237
238
|
// Analyze
|
|
238
239
|
export { analyze_css as analyzeCss } from './analyze/css-analyze.js';
|
|
240
|
+
export { prune_css as pruneCss } from './analyze/prune.js';
|
|
239
241
|
export {
|
|
240
242
|
CLASS_COMPONENT_AS_NON_ARROW_PROPERTY_ERROR,
|
|
241
243
|
COMPONENT_DO_WHILE_STATEMENT_ERROR,
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
import { walk } from 'zimmerframe';
|
|
6
6
|
import { print } from 'esrap';
|
|
7
7
|
import { error } from '../../errors.js';
|
|
8
|
+
import { analyze_css } from '../../analyze/css-analyze.js';
|
|
9
|
+
import { prune_css } from '../../analyze/prune.js';
|
|
8
10
|
import {
|
|
9
11
|
ensure_function_metadata,
|
|
10
12
|
in_jsx_child_context,
|
|
@@ -36,7 +38,11 @@ import {
|
|
|
36
38
|
import * as b from '../../utils/builders.js';
|
|
37
39
|
import { apply_lazy_transforms, preallocate_lazy_ids } from '../lazy.js';
|
|
38
40
|
import { find_first_top_level_await_in_component_body } from '../await.js';
|
|
39
|
-
import {
|
|
41
|
+
import {
|
|
42
|
+
prepare_stylesheet_for_render,
|
|
43
|
+
annotate_component_with_hash,
|
|
44
|
+
is_style_element,
|
|
45
|
+
} from '../scoping.js';
|
|
40
46
|
import {
|
|
41
47
|
validate_class_component_declarations,
|
|
42
48
|
validate_component_loop_break_statement,
|
|
@@ -426,12 +432,14 @@ export function createJsxTransform(platform) {
|
|
|
426
432
|
|
|
427
433
|
const css = as_any.css;
|
|
428
434
|
if (css) {
|
|
435
|
+
apply_css_definition_metadata(as_any, css);
|
|
429
436
|
stylesheets.push(css);
|
|
430
437
|
const hash = css.hash;
|
|
431
438
|
annotate_component_with_hash(
|
|
432
439
|
as_any,
|
|
433
440
|
hash,
|
|
434
441
|
platform.jsx.rewriteClassAttr ? 'className' : 'class',
|
|
442
|
+
transform_context.typeOnly,
|
|
435
443
|
);
|
|
436
444
|
}
|
|
437
445
|
return next(state);
|
|
@@ -609,6 +617,73 @@ export function createJsxTransform(platform) {
|
|
|
609
617
|
return transform;
|
|
610
618
|
}
|
|
611
619
|
|
|
620
|
+
/**
|
|
621
|
+
* Attach selector-location metadata used by editor definitions/hover before
|
|
622
|
+
* the shared scoping pass mutates class attributes with the component hash.
|
|
623
|
+
*
|
|
624
|
+
* @param {any} component
|
|
625
|
+
* @param {any} css
|
|
626
|
+
* @returns {void}
|
|
627
|
+
*/
|
|
628
|
+
function apply_css_definition_metadata(component, css) {
|
|
629
|
+
analyze_css(css);
|
|
630
|
+
|
|
631
|
+
const metadata = component.metadata || (component.metadata = { path: [] });
|
|
632
|
+
const style_classes = metadata.styleClasses || (metadata.styleClasses = new Map());
|
|
633
|
+
const top_scoped_classes = metadata.topScopedClasses || new Map();
|
|
634
|
+
const elements = collect_css_prunable_elements(component.body || []);
|
|
635
|
+
|
|
636
|
+
for (const element of elements) {
|
|
637
|
+
prune_css(css, element, style_classes, top_scoped_classes);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
if (top_scoped_classes.size > 0) {
|
|
641
|
+
metadata.topScopedClasses = top_scoped_classes;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* @param {any} value
|
|
647
|
+
* @param {any[]} [elements]
|
|
648
|
+
* @returns {any[]}
|
|
649
|
+
*/
|
|
650
|
+
function collect_css_prunable_elements(value, elements = []) {
|
|
651
|
+
if (!value || typeof value !== 'object') {
|
|
652
|
+
return elements;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
if (Array.isArray(value)) {
|
|
656
|
+
for (const child of value) {
|
|
657
|
+
collect_css_prunable_elements(child, elements);
|
|
658
|
+
}
|
|
659
|
+
return elements;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
if (
|
|
663
|
+
value.type === 'FunctionDeclaration' ||
|
|
664
|
+
value.type === 'FunctionExpression' ||
|
|
665
|
+
value.type === 'ArrowFunctionExpression' ||
|
|
666
|
+
value.type === 'Component'
|
|
667
|
+
) {
|
|
668
|
+
return elements;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
if (value.type === 'Element') {
|
|
672
|
+
if (!is_style_element(value)) {
|
|
673
|
+
elements.push(value);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
for (const key of Object.keys(value)) {
|
|
678
|
+
if (key === 'loc' || key === 'start' || key === 'end' || key === 'metadata' || key === 'css') {
|
|
679
|
+
continue;
|
|
680
|
+
}
|
|
681
|
+
collect_css_prunable_elements(value[key], elements);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
return elements;
|
|
685
|
+
}
|
|
686
|
+
|
|
612
687
|
/**
|
|
613
688
|
* Detect a top-level `"use server"` directive. Used by platforms whose
|
|
614
689
|
* validation rule requires the directive to enable top-level `await`
|
|
@@ -1140,23 +1215,27 @@ function is_hook_callee(callee) {
|
|
|
1140
1215
|
|
|
1141
1216
|
/**
|
|
1142
1217
|
* @param {AST.Identifier[]} bindings
|
|
1218
|
+
* @param {Set<string>} [mapped_bindings]
|
|
1143
1219
|
* @returns {AST.ObjectPattern}
|
|
1144
1220
|
*/
|
|
1145
|
-
function create_helper_props_pattern(bindings) {
|
|
1221
|
+
function create_helper_props_pattern(bindings, mapped_bindings = new Set()) {
|
|
1146
1222
|
return /** @type {any} */ ({
|
|
1147
1223
|
type: 'ObjectPattern',
|
|
1148
|
-
properties: bindings.map((binding) =>
|
|
1224
|
+
properties: bindings.map((binding) =>
|
|
1225
|
+
create_helper_props_property(binding, mapped_bindings.has(binding.name)),
|
|
1226
|
+
),
|
|
1149
1227
|
metadata: { path: [] },
|
|
1150
1228
|
});
|
|
1151
1229
|
}
|
|
1152
1230
|
|
|
1153
1231
|
/**
|
|
1154
1232
|
* @param {AST.Identifier} binding
|
|
1233
|
+
* @param {boolean} [map_binding]
|
|
1155
1234
|
* @returns {AST.Property}
|
|
1156
1235
|
*/
|
|
1157
|
-
function create_helper_props_property(binding) {
|
|
1158
|
-
const key = create_generated_identifier(binding.name);
|
|
1159
|
-
const value = create_generated_identifier(binding.name);
|
|
1236
|
+
function create_helper_props_property(binding, map_binding = false) {
|
|
1237
|
+
const key = map_binding ? clone_identifier(binding) : create_generated_identifier(binding.name);
|
|
1238
|
+
const value = map_binding ? clone_identifier(binding) : create_generated_identifier(binding.name);
|
|
1160
1239
|
|
|
1161
1240
|
return b.prop('init', key, value, false, true);
|
|
1162
1241
|
}
|
|
@@ -3336,14 +3415,16 @@ function get_hook_callee_name(callee) {
|
|
|
3336
3415
|
* Used by the switch lift's chained-call build, which allocates ids in
|
|
3337
3416
|
* source order in a forward pass and then constructs helpers in reverse so
|
|
3338
3417
|
* each fall-through case can reference the next case's component element.
|
|
3418
|
+
* @param {{ transientBindings?: Set<string> }} [options]
|
|
3339
3419
|
* @returns {{ setup_statements: any[], component_element: ESTreeJSX.JSXElement }}
|
|
3340
3420
|
*/
|
|
3341
|
-
function create_hook_safe_helper(
|
|
3421
|
+
export function create_hook_safe_helper(
|
|
3342
3422
|
body_nodes,
|
|
3343
3423
|
key_expression,
|
|
3344
3424
|
source_node,
|
|
3345
3425
|
transform_context,
|
|
3346
3426
|
preallocated_helper_id,
|
|
3427
|
+
options = {},
|
|
3347
3428
|
) {
|
|
3348
3429
|
validate_hook_safe_body_does_not_assign_hook_results_to_outer_bindings(
|
|
3349
3430
|
body_nodes,
|
|
@@ -3361,9 +3442,14 @@ function create_hook_safe_helper(
|
|
|
3361
3442
|
body_nodes,
|
|
3362
3443
|
transform_context.available_bindings,
|
|
3363
3444
|
);
|
|
3445
|
+
const transient_bindings = options.transientBindings ?? new Set();
|
|
3364
3446
|
const aliases = use_module_scoped_component
|
|
3365
3447
|
? []
|
|
3366
|
-
: helper_bindings.map((binding) =>
|
|
3448
|
+
: helper_bindings.map((binding) =>
|
|
3449
|
+
transient_bindings.has(binding.name)
|
|
3450
|
+
? null
|
|
3451
|
+
: create_helper_type_alias_declaration(helper_id, binding),
|
|
3452
|
+
);
|
|
3367
3453
|
const props_type =
|
|
3368
3454
|
helper_bindings.length > 0 && !use_module_scoped_component
|
|
3369
3455
|
? create_helper_props_type_literal(helper_bindings, aliases)
|
|
@@ -3372,8 +3458,8 @@ function create_hook_safe_helper(
|
|
|
3372
3458
|
helper_bindings.length > 0
|
|
3373
3459
|
? [
|
|
3374
3460
|
props_type !== null
|
|
3375
|
-
? create_typed_helper_props_pattern(helper_bindings, props_type)
|
|
3376
|
-
: create_helper_props_pattern(helper_bindings),
|
|
3461
|
+
? create_typed_helper_props_pattern(helper_bindings, props_type, transient_bindings)
|
|
3462
|
+
: create_helper_props_pattern(helper_bindings, transient_bindings),
|
|
3377
3463
|
]
|
|
3378
3464
|
: [];
|
|
3379
3465
|
|
|
@@ -3415,7 +3501,7 @@ function create_hook_safe_helper(
|
|
|
3415
3501
|
if (!transform_context.helper_state) {
|
|
3416
3502
|
return {
|
|
3417
3503
|
setup_statements: [
|
|
3418
|
-
...aliases.
|
|
3504
|
+
...aliases.flatMap((alias) => (alias ? [alias.declaration] : [])),
|
|
3419
3505
|
create_helper_declaration(helper_id, helper_fn, source_node, transform_context),
|
|
3420
3506
|
],
|
|
3421
3507
|
component_element,
|
|
@@ -3439,7 +3525,7 @@ function create_hook_safe_helper(
|
|
|
3439
3525
|
|
|
3440
3526
|
return {
|
|
3441
3527
|
setup_statements: [
|
|
3442
|
-
...aliases.
|
|
3528
|
+
...aliases.flatMap((alias) => (alias ? [alias.declaration] : [])),
|
|
3443
3529
|
create_cached_helper_declaration(
|
|
3444
3530
|
helper_id,
|
|
3445
3531
|
cache_id,
|
|
@@ -3513,7 +3599,7 @@ function create_helper_type_alias_declaration(helper_id, binding) {
|
|
|
3513
3599
|
|
|
3514
3600
|
/**
|
|
3515
3601
|
* @param {AST.Identifier[]} bindings
|
|
3516
|
-
* @param {{ id: AST.Identifier }[]} aliases
|
|
3602
|
+
* @param {({ id: AST.Identifier } | null)[]} aliases
|
|
3517
3603
|
* @returns {any}
|
|
3518
3604
|
*/
|
|
3519
3605
|
function create_helper_props_type_literal(bindings, aliases) {
|
|
@@ -3521,7 +3607,13 @@ function create_helper_props_type_literal(bindings, aliases) {
|
|
|
3521
3607
|
bindings.map((binding, i) =>
|
|
3522
3608
|
b.ts_property_signature(
|
|
3523
3609
|
create_generated_identifier(binding.name),
|
|
3524
|
-
b.ts_type_annotation(
|
|
3610
|
+
b.ts_type_annotation(
|
|
3611
|
+
aliases[i]
|
|
3612
|
+
? b.ts_type_query(
|
|
3613
|
+
clone_identifier(/** @type {{ id: AST.Identifier }} */ (aliases[i]).id),
|
|
3614
|
+
)
|
|
3615
|
+
: b.ts_keyword_type('any'),
|
|
3616
|
+
),
|
|
3525
3617
|
),
|
|
3526
3618
|
),
|
|
3527
3619
|
);
|
|
@@ -3530,10 +3622,11 @@ function create_helper_props_type_literal(bindings, aliases) {
|
|
|
3530
3622
|
/**
|
|
3531
3623
|
* @param {AST.Identifier[]} bindings
|
|
3532
3624
|
* @param {any} props_type
|
|
3625
|
+
* @param {Set<string>} [mapped_bindings]
|
|
3533
3626
|
* @returns {AST.ObjectPattern}
|
|
3534
3627
|
*/
|
|
3535
|
-
function create_typed_helper_props_pattern(bindings, props_type) {
|
|
3536
|
-
const pattern = create_helper_props_pattern(bindings);
|
|
3628
|
+
function create_typed_helper_props_pattern(bindings, props_type, mapped_bindings = new Set()) {
|
|
3629
|
+
const pattern = create_helper_props_pattern(bindings, mapped_bindings);
|
|
3537
3630
|
/** @type {any} */ (pattern).typeAnnotation = b.ts_type_annotation(props_type);
|
|
3538
3631
|
return pattern;
|
|
3539
3632
|
}
|
|
@@ -4427,18 +4520,25 @@ function try_statement_to_jsx_child(node, transform_context) {
|
|
|
4427
4520
|
? to_jsx_expression_container(create_null_literal())
|
|
4428
4521
|
: statement_body_to_jsx_child(pending_body_nodes, transform_context);
|
|
4429
4522
|
|
|
4430
|
-
result =
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4523
|
+
result =
|
|
4524
|
+
transform_context.platform.hooks?.createPendingBoundary?.(
|
|
4525
|
+
result,
|
|
4526
|
+
fallback_content,
|
|
4527
|
+
transform_context,
|
|
4528
|
+
node,
|
|
4529
|
+
) ??
|
|
4530
|
+
create_jsx_element(
|
|
4531
|
+
'Suspense',
|
|
4532
|
+
[
|
|
4533
|
+
{
|
|
4534
|
+
type: 'JSXAttribute',
|
|
4535
|
+
name: { type: 'JSXIdentifier', name: 'fallback', metadata: { path: [] } },
|
|
4536
|
+
value: fallback_content,
|
|
4537
|
+
metadata: { path: [] },
|
|
4538
|
+
},
|
|
4539
|
+
],
|
|
4540
|
+
[result],
|
|
4541
|
+
);
|
|
4442
4542
|
}
|
|
4443
4543
|
|
|
4444
4544
|
// Wrap in <TsrxErrorBoundary> if catch block exists
|
|
@@ -4476,19 +4576,42 @@ function try_statement_to_jsx_child(node, transform_context) {
|
|
|
4476
4576
|
|
|
4477
4577
|
const fallback_fn = b.arrow(
|
|
4478
4578
|
catch_params,
|
|
4479
|
-
b.block(build_render_statements(catch_body_nodes, true, transform_context)),
|
|
4579
|
+
b.block(build_render_statements(catch_body_nodes, true, transform_context), handler.body),
|
|
4580
|
+
false,
|
|
4581
|
+
undefined,
|
|
4582
|
+
handler,
|
|
4480
4583
|
);
|
|
4481
4584
|
|
|
4585
|
+
const fallback_component =
|
|
4586
|
+
transform_context.platform.hooks?.createErrorFallbackComponent?.(
|
|
4587
|
+
catch_body_nodes,
|
|
4588
|
+
catch_params,
|
|
4589
|
+
transform_context,
|
|
4590
|
+
node,
|
|
4591
|
+
) ?? null;
|
|
4592
|
+
|
|
4482
4593
|
transform_context.available_bindings = saved_catch_bindings;
|
|
4483
4594
|
|
|
4484
4595
|
const boundary_content =
|
|
4485
4596
|
transform_context.platform.hooks?.createErrorBoundaryContent?.(
|
|
4597
|
+
result,
|
|
4598
|
+
transform_context,
|
|
4599
|
+
node,
|
|
4600
|
+
) ?? null;
|
|
4601
|
+
|
|
4602
|
+
const custom_boundary =
|
|
4603
|
+
transform_context.platform.hooks?.createErrorBoundary?.(
|
|
4604
|
+
result,
|
|
4486
4605
|
try_content,
|
|
4606
|
+
fallback_fn,
|
|
4487
4607
|
transform_context,
|
|
4488
4608
|
node,
|
|
4609
|
+
{ fallbackComponent: fallback_component },
|
|
4489
4610
|
) ?? null;
|
|
4490
4611
|
|
|
4491
|
-
if (
|
|
4612
|
+
if (custom_boundary) {
|
|
4613
|
+
result = custom_boundary;
|
|
4614
|
+
} else if (boundary_content && transform_context.inside_element_child) {
|
|
4492
4615
|
result = to_jsx_expression_container(
|
|
4493
4616
|
b.call(
|
|
4494
4617
|
'TsrxErrorBoundary',
|
|
@@ -4497,21 +4620,21 @@ function try_statement_to_jsx_child(node, transform_context) {
|
|
|
4497
4620
|
);
|
|
4498
4621
|
|
|
4499
4622
|
return result;
|
|
4623
|
+
} else {
|
|
4624
|
+
result = create_jsx_element(
|
|
4625
|
+
'TsrxErrorBoundary',
|
|
4626
|
+
[
|
|
4627
|
+
b.jsx_attribute(
|
|
4628
|
+
b.jsx_id('fallback'),
|
|
4629
|
+
to_jsx_expression_container(/** @type {any} */ (fallback_fn)),
|
|
4630
|
+
),
|
|
4631
|
+
...(boundary_content
|
|
4632
|
+
? [b.jsx_attribute(b.jsx_id('content'), to_jsx_expression_container(boundary_content))]
|
|
4633
|
+
: []),
|
|
4634
|
+
],
|
|
4635
|
+
boundary_content ? [] : [result],
|
|
4636
|
+
);
|
|
4500
4637
|
}
|
|
4501
|
-
|
|
4502
|
-
result = create_jsx_element(
|
|
4503
|
-
'TsrxErrorBoundary',
|
|
4504
|
-
[
|
|
4505
|
-
b.jsx_attribute(
|
|
4506
|
-
b.jsx_id('fallback'),
|
|
4507
|
-
to_jsx_expression_container(/** @type {any} */ (fallback_fn)),
|
|
4508
|
-
),
|
|
4509
|
-
...(boundary_content
|
|
4510
|
-
? [b.jsx_attribute(b.jsx_id('content'), to_jsx_expression_container(boundary_content))]
|
|
4511
|
-
: []),
|
|
4512
|
-
],
|
|
4513
|
-
boundary_content ? [] : [result],
|
|
4514
|
-
);
|
|
4515
4638
|
}
|
|
4516
4639
|
|
|
4517
4640
|
// result is a JSXElement, but we need to return a JSXExpressionContainer
|
|
@@ -5547,6 +5670,8 @@ export function to_jsx_attribute(attr, transform_context) {
|
|
|
5547
5670
|
attr_name.name === 'class'
|
|
5548
5671
|
) {
|
|
5549
5672
|
attr_name = set_loc(b.id('className'), attr.name);
|
|
5673
|
+
attr_name.metadata.source_name = 'class';
|
|
5674
|
+
attr_name.metadata.source_length = 'class'.length;
|
|
5550
5675
|
}
|
|
5551
5676
|
|
|
5552
5677
|
const name =
|
package/src/transform/scoping.js
CHANGED
|
@@ -95,9 +95,15 @@ function is_composite_jsx_element(node) {
|
|
|
95
95
|
* @param {any} node
|
|
96
96
|
* @param {string} hash
|
|
97
97
|
* @param {'class' | 'className'} [jsx_class_attr_name='class']
|
|
98
|
+
* @param {boolean} [preserve_style_elements=false]
|
|
98
99
|
* @returns {any}
|
|
99
100
|
*/
|
|
100
|
-
export function annotate_with_hash(
|
|
101
|
+
export function annotate_with_hash(
|
|
102
|
+
node,
|
|
103
|
+
hash,
|
|
104
|
+
jsx_class_attr_name = 'class',
|
|
105
|
+
preserve_style_elements = false,
|
|
106
|
+
) {
|
|
101
107
|
if (!node || typeof node !== 'object') return node;
|
|
102
108
|
if (
|
|
103
109
|
node.type === 'Component' ||
|
|
@@ -109,13 +115,19 @@ export function annotate_with_hash(node, hash, jsx_class_attr_name = 'class') {
|
|
|
109
115
|
}
|
|
110
116
|
|
|
111
117
|
if (node.type === 'Element') {
|
|
118
|
+
if (preserve_style_elements && is_style_element(node)) {
|
|
119
|
+
node.children = [];
|
|
120
|
+
return node;
|
|
121
|
+
}
|
|
112
122
|
if (!is_style_element(node) && !is_composite_element(node)) {
|
|
113
123
|
add_hash_class(node, hash);
|
|
114
124
|
}
|
|
115
125
|
if (Array.isArray(node.children)) {
|
|
116
126
|
node.children = node.children
|
|
117
|
-
.filter((/** @type {any} */ child) => !is_style_element(child))
|
|
118
|
-
.map((/** @type {any} */ child) =>
|
|
127
|
+
.filter((/** @type {any} */ child) => preserve_style_elements || !is_style_element(child))
|
|
128
|
+
.map((/** @type {any} */ child) =>
|
|
129
|
+
annotate_with_hash(child, hash, jsx_class_attr_name, preserve_style_elements),
|
|
130
|
+
);
|
|
119
131
|
}
|
|
120
132
|
return node;
|
|
121
133
|
}
|
|
@@ -126,7 +138,7 @@ export function annotate_with_hash(node, hash, jsx_class_attr_name = 'class') {
|
|
|
126
138
|
}
|
|
127
139
|
if (Array.isArray(node.children)) {
|
|
128
140
|
node.children = node.children.map((/** @type {any} */ child) =>
|
|
129
|
-
annotate_with_hash(child, hash, jsx_class_attr_name),
|
|
141
|
+
annotate_with_hash(child, hash, jsx_class_attr_name, preserve_style_elements),
|
|
130
142
|
);
|
|
131
143
|
}
|
|
132
144
|
return node;
|
|
@@ -140,10 +152,10 @@ export function annotate_with_hash(node, hash, jsx_class_attr_name = 'class') {
|
|
|
140
152
|
const value = node[key];
|
|
141
153
|
if (Array.isArray(value)) {
|
|
142
154
|
node[key] = value.map((/** @type {any} */ child) =>
|
|
143
|
-
annotate_with_hash(child, hash, jsx_class_attr_name),
|
|
155
|
+
annotate_with_hash(child, hash, jsx_class_attr_name, preserve_style_elements),
|
|
144
156
|
);
|
|
145
157
|
} else if (value && typeof value === 'object') {
|
|
146
|
-
node[key] = annotate_with_hash(value, hash, jsx_class_attr_name);
|
|
158
|
+
node[key] = annotate_with_hash(value, hash, jsx_class_attr_name, preserve_style_elements);
|
|
147
159
|
}
|
|
148
160
|
}
|
|
149
161
|
|
|
@@ -154,14 +166,22 @@ export function annotate_with_hash(node, hash, jsx_class_attr_name = 'class') {
|
|
|
154
166
|
* @param {any} component
|
|
155
167
|
* @param {string} hash
|
|
156
168
|
* @param {'class' | 'className'} [jsx_class_attr_name='class']
|
|
169
|
+
* @param {boolean} [preserve_style_elements=false]
|
|
157
170
|
* @returns {void}
|
|
158
171
|
*/
|
|
159
|
-
export function annotate_component_with_hash(
|
|
172
|
+
export function annotate_component_with_hash(
|
|
173
|
+
component,
|
|
174
|
+
hash,
|
|
175
|
+
jsx_class_attr_name = 'class',
|
|
176
|
+
preserve_style_elements = false,
|
|
177
|
+
) {
|
|
160
178
|
/** @type {any[]} */
|
|
161
179
|
const body = component.body;
|
|
162
180
|
component.body = body
|
|
163
|
-
.filter((/** @type {any} */ child) => !is_style_element(child))
|
|
164
|
-
.map((/** @type {any} */ child) =>
|
|
181
|
+
.filter((/** @type {any} */ child) => preserve_style_elements || !is_style_element(child))
|
|
182
|
+
.map((/** @type {any} */ child) =>
|
|
183
|
+
annotate_with_hash(child, hash, jsx_class_attr_name, preserve_style_elements),
|
|
184
|
+
);
|
|
165
185
|
}
|
|
166
186
|
|
|
167
187
|
/**
|
|
@@ -198,7 +218,8 @@ export function add_hash_class(element, hash) {
|
|
|
198
218
|
|
|
199
219
|
if (value.type === 'Literal' && typeof value.value === 'string') {
|
|
200
220
|
const merged = `${value.value} ${hash}`;
|
|
201
|
-
|
|
221
|
+
value.value = merged;
|
|
222
|
+
value.raw = JSON.stringify(merged);
|
|
202
223
|
return;
|
|
203
224
|
}
|
|
204
225
|
|
|
@@ -233,7 +254,11 @@ function add_hash_class_to_jsx_element(element, hash, jsx_class_attr_name) {
|
|
|
233
254
|
existing.name = {
|
|
234
255
|
type: 'JSXIdentifier',
|
|
235
256
|
name: jsx_class_attr_name,
|
|
236
|
-
metadata:
|
|
257
|
+
metadata: {
|
|
258
|
+
...(existing.name.metadata || { path: [] }),
|
|
259
|
+
source_name: existing.name.name,
|
|
260
|
+
source_length: existing.name.name.length,
|
|
261
|
+
},
|
|
237
262
|
};
|
|
238
263
|
}
|
|
239
264
|
|
|
@@ -245,7 +270,8 @@ function add_hash_class_to_jsx_element(element, hash, jsx_class_attr_name) {
|
|
|
245
270
|
|
|
246
271
|
if (value.type === 'Literal' && typeof value.value === 'string') {
|
|
247
272
|
const merged = `${value.value} ${hash}`;
|
|
248
|
-
|
|
273
|
+
value.value = merged;
|
|
274
|
+
value.raw = JSON.stringify(merged);
|
|
249
275
|
return;
|
|
250
276
|
}
|
|
251
277
|
|
|
@@ -162,14 +162,14 @@ function visit_source_ast(ast, src_line_offsets, { regions, css_element_info })
|
|
|
162
162
|
start: cssStart,
|
|
163
163
|
end: cssEnd,
|
|
164
164
|
content: node.css,
|
|
165
|
-
id: get_style_region_id(node.metadata.styleScopeHash, `head-${region_id}`),
|
|
165
|
+
id: get_style_region_id(node.metadata.styleScopeHash, `head-${region_id++}`),
|
|
166
166
|
});
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
context.next();
|
|
170
170
|
},
|
|
171
171
|
Attribute(node, context) {
|
|
172
|
-
const element = context.path?.
|
|
172
|
+
const element = context.path?.findLast((n) => n.type === 'Element');
|
|
173
173
|
if (element?.metadata?.css?.scopedClasses) {
|
|
174
174
|
// we don't need to check is_element_dom_element(node)
|
|
175
175
|
// since scopedClasses are added during pruning only to DOM elements
|
|
@@ -568,10 +568,11 @@ export function convert_source_map_to_mappings(
|
|
|
568
568
|
if (node.loc && node.name) {
|
|
569
569
|
/** @type {Token} */
|
|
570
570
|
const token = {
|
|
571
|
-
source: node.metadata?.
|
|
571
|
+
source: node.metadata?.source_name ?? node.name,
|
|
572
572
|
generated: node.name,
|
|
573
573
|
loc: node.loc,
|
|
574
574
|
metadata: {},
|
|
575
|
+
sourceLength: node.metadata?.source_length,
|
|
575
576
|
};
|
|
576
577
|
if (node.metadata?.disable_verification) {
|
|
577
578
|
token.mappingData = { ...mapping_data, verification: false };
|
|
@@ -708,16 +709,24 @@ export function convert_source_map_to_mappings(
|
|
|
708
709
|
visit(node.value);
|
|
709
710
|
}
|
|
710
711
|
} else {
|
|
712
|
+
const is_class_attribute =
|
|
713
|
+
node.name?.type === 'JSXIdentifier' &&
|
|
714
|
+
(node.name.name === 'class' || node.name.name === 'className');
|
|
711
715
|
const attr =
|
|
712
|
-
|
|
716
|
+
is_class_attribute && node.value?.type === 'JSXExpressionContainer'
|
|
713
717
|
? node.value.expression
|
|
714
718
|
: node.value;
|
|
715
719
|
|
|
716
|
-
const css =
|
|
717
|
-
|
|
718
|
-
|
|
720
|
+
const css =
|
|
721
|
+
is_class_attribute && attr
|
|
722
|
+
? css_element_info.get(`${attr.loc?.start.line}:${attr.loc?.start.column}`)
|
|
723
|
+
: null;
|
|
719
724
|
|
|
720
725
|
if (attr && css) {
|
|
726
|
+
if (node.name) {
|
|
727
|
+
visit(node.name);
|
|
728
|
+
}
|
|
729
|
+
|
|
721
730
|
// Extract class names from the attribute value
|
|
722
731
|
const classes = extract_classes(
|
|
723
732
|
attr,
|
|
@@ -861,7 +870,7 @@ export function convert_source_map_to_mappings(
|
|
|
861
870
|
target_node,
|
|
862
871
|
src_to_gen_map,
|
|
863
872
|
gen_line_offsets,
|
|
864
|
-
mapping_data_verify_only,
|
|
873
|
+
closing ? mapping_data_verify_only : mapping_data_verify_complete,
|
|
865
874
|
);
|
|
866
875
|
// The generated code includes a semicolon after the closing or self-closed tag
|
|
867
876
|
// We're extending the mapping to include the semicolon
|
package/types/jsx-platform.d.ts
CHANGED
|
@@ -200,11 +200,49 @@ export interface JsxPlatformHooks {
|
|
|
200
200
|
* the loop to the downstream Vapor JSX compiler as a typed `VaporFor` component.
|
|
201
201
|
*/
|
|
202
202
|
renderForOf?: (node: any, loopParams: any[], bodyStatements: any[], ctx: any) => any | null;
|
|
203
|
+
/**
|
|
204
|
+
* Optionally replace the default React-style pending lowering for
|
|
205
|
+
* `try { ... } pending { ... }`. The default emits
|
|
206
|
+
* `<Suspense fallback={fallbackContent}>tryContent</Suspense>`.
|
|
207
|
+
* Vue Vapor uses this to provide `default` and `fallback` slots via
|
|
208
|
+
* `v-slots`.
|
|
209
|
+
*/
|
|
210
|
+
createPendingBoundary?: (
|
|
211
|
+
tryContent: any,
|
|
212
|
+
fallbackContent: any,
|
|
213
|
+
ctx: any,
|
|
214
|
+
node: any,
|
|
215
|
+
) => any | null;
|
|
216
|
+
/**
|
|
217
|
+
* Optionally create a generated component for a catch fallback body while
|
|
218
|
+
* the catch parameters are still in scope. Platforms can use this to reuse
|
|
219
|
+
* one mapped catch-body component from multiple runtime catch sites.
|
|
220
|
+
*/
|
|
221
|
+
createErrorFallbackComponent?: (
|
|
222
|
+
catchBodyNodes: any[],
|
|
223
|
+
catchParams: any[],
|
|
224
|
+
ctx: any,
|
|
225
|
+
node: any,
|
|
226
|
+
) => any | null;
|
|
227
|
+
/**
|
|
228
|
+
* Optionally replace the default `try/catch` boundary wrapper. The hook
|
|
229
|
+
* receives the current render content, the original try-body content before
|
|
230
|
+
* any pending wrapper, and the generated catch fallback function.
|
|
231
|
+
*/
|
|
232
|
+
createErrorBoundary?: (
|
|
233
|
+
tryContent: any,
|
|
234
|
+
rawTryContent: any,
|
|
235
|
+
fallbackFn: any,
|
|
236
|
+
ctx: any,
|
|
237
|
+
node: any,
|
|
238
|
+
info?: { fallbackComponent?: any },
|
|
239
|
+
) => any | null;
|
|
203
240
|
/**
|
|
204
241
|
* Optionally move the primary `try { ... }` render content into an explicit
|
|
205
242
|
* error-boundary prop instead of rendering it as the boundary's JSX children.
|
|
206
243
|
* Vue Vapor uses this because boundary content must execute lazily from a
|
|
207
|
-
* zero-argument function.
|
|
244
|
+
* zero-argument function. If a `pending` block exists, `tryContent` is the
|
|
245
|
+
* already-created pending boundary so catch wrappers still enclose it.
|
|
208
246
|
*/
|
|
209
247
|
createErrorBoundaryContent?: (tryContent: any, ctx: any, node: any) => any | null;
|
|
210
248
|
/**
|