@tsrx/core 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -5
- package/src/analyze/prune.js +1151 -0
- package/src/index.js +1 -0
- package/src/transform/jsx/index.js +78 -1
- package/src/transform/scoping.js +38 -12
- package/src/transform/segments.js +17 -8
package/src/index.js
CHANGED
|
@@ -236,6 +236,7 @@ export {
|
|
|
236
236
|
|
|
237
237
|
// Analyze
|
|
238
238
|
export { analyze_css as analyzeCss } from './analyze/css-analyze.js';
|
|
239
|
+
export { prune_css as pruneCss } from './analyze/prune.js';
|
|
239
240
|
export {
|
|
240
241
|
CLASS_COMPONENT_AS_NON_ARROW_PROPERTY_ERROR,
|
|
241
242
|
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`
|
|
@@ -5547,6 +5622,8 @@ export function to_jsx_attribute(attr, transform_context) {
|
|
|
5547
5622
|
attr_name.name === 'class'
|
|
5548
5623
|
) {
|
|
5549
5624
|
attr_name = set_loc(b.id('className'), attr.name);
|
|
5625
|
+
attr_name.metadata.source_name = 'class';
|
|
5626
|
+
attr_name.metadata.source_length = 'class'.length;
|
|
5550
5627
|
}
|
|
5551
5628
|
|
|
5552
5629
|
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
|