@tsrx/core 0.1.17 → 0.1.19
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 +1 -1
- package/src/analyze/prune.js +1 -1
- package/src/index.js +2 -1
- package/src/transform/jsx/helpers.js +17 -19
- package/src/transform/jsx/index.js +476 -287
- package/src/transform/scoping.js +5 -16
- package/src/transform/style-ref.js +92 -1
- package/types/index.d.ts +21 -1
- package/types/jsx-platform.d.ts +8 -9
package/src/transform/scoping.js
CHANGED
|
@@ -119,7 +119,7 @@ export function annotate_with_hash(
|
|
|
119
119
|
return node;
|
|
120
120
|
}
|
|
121
121
|
if (!is_style_element(node) && !is_composite_element(node)) {
|
|
122
|
-
add_hash_class(node, hash);
|
|
122
|
+
add_hash_class(node, hash, jsx_class_attr_name);
|
|
123
123
|
}
|
|
124
124
|
if (Array.isArray(node.children)) {
|
|
125
125
|
node.children = node.children
|
|
@@ -184,13 +184,14 @@ export function annotate_component_with_hash(
|
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
/**
|
|
187
|
-
* Ensure the element carries a
|
|
187
|
+
* Ensure the element carries a class attribute containing the scoping hash.
|
|
188
188
|
*
|
|
189
189
|
* @param {any} element
|
|
190
190
|
* @param {string} hash
|
|
191
|
+
* @param {'class' | 'className'} [class_attr_name='class']
|
|
191
192
|
* @returns {void}
|
|
192
193
|
*/
|
|
193
|
-
export function add_hash_class(element, hash) {
|
|
194
|
+
export function add_hash_class(element, hash, class_attr_name = 'class') {
|
|
194
195
|
const attrs = element.attributes || (element.attributes = []);
|
|
195
196
|
const existing = attrs.find(
|
|
196
197
|
(/** @type {any} */ a) =>
|
|
@@ -203,7 +204,7 @@ export function add_hash_class(element, hash) {
|
|
|
203
204
|
if (!existing) {
|
|
204
205
|
attrs.push({
|
|
205
206
|
type: 'Attribute',
|
|
206
|
-
name: b.id(
|
|
207
|
+
name: b.id(class_attr_name),
|
|
207
208
|
value: { type: 'Literal', value: hash, raw: JSON.stringify(hash) },
|
|
208
209
|
});
|
|
209
210
|
return;
|
|
@@ -249,18 +250,6 @@ function add_hash_class_to_jsx_element(element, hash, jsx_class_attr_name) {
|
|
|
249
250
|
return;
|
|
250
251
|
}
|
|
251
252
|
|
|
252
|
-
if (existing.name.name !== jsx_class_attr_name) {
|
|
253
|
-
existing.name = {
|
|
254
|
-
type: 'JSXIdentifier',
|
|
255
|
-
name: jsx_class_attr_name,
|
|
256
|
-
metadata: {
|
|
257
|
-
...(existing.name.metadata || { path: [] }),
|
|
258
|
-
source_name: existing.name.name,
|
|
259
|
-
source_length: existing.name.name.length,
|
|
260
|
-
},
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
|
|
264
253
|
const value = existing.value;
|
|
265
254
|
if (!value) {
|
|
266
255
|
existing.value = { type: 'Literal', value: hash, raw: JSON.stringify(hash) };
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
import * as b from '../utils/builders.js';
|
|
4
4
|
import { clone_expression_node, clone_identifier } from './jsx/ast-builders.js';
|
|
5
5
|
|
|
6
|
+
const regex_backslash_and_following_character = /\\(.)/g;
|
|
7
|
+
|
|
6
8
|
/**
|
|
7
9
|
* @typedef {{
|
|
8
10
|
* allowMutableRefTarget?: boolean;
|
|
@@ -19,7 +21,7 @@ import { clone_expression_node, clone_identifier } from './jsx/ast-builders.js';
|
|
|
19
21
|
export function create_style_class_map(component, css) {
|
|
20
22
|
const hash = css?.hash ?? null;
|
|
21
23
|
const top_scoped_classes = /** @type {Map<string, any>} */ (
|
|
22
|
-
component?.metadata?.topScopedClasses ??
|
|
24
|
+
component?.metadata?.topScopedClasses ?? collect_style_class_map_entries(css)
|
|
23
25
|
);
|
|
24
26
|
const class_names = [...top_scoped_classes.keys()].sort();
|
|
25
27
|
|
|
@@ -30,6 +32,28 @@ export function create_style_class_map(component, css) {
|
|
|
30
32
|
);
|
|
31
33
|
}
|
|
32
34
|
|
|
35
|
+
/**
|
|
36
|
+
* @param {any} css
|
|
37
|
+
* @returns {AST.ObjectExpression}
|
|
38
|
+
*/
|
|
39
|
+
export function create_style_class_map_from_stylesheet(css) {
|
|
40
|
+
return create_style_class_map(
|
|
41
|
+
{ metadata: { topScopedClasses: collect_style_class_map_entries(css) } },
|
|
42
|
+
css,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @param {any} style_element
|
|
48
|
+
* @returns {any | null}
|
|
49
|
+
*/
|
|
50
|
+
export function get_style_element_stylesheet(style_element) {
|
|
51
|
+
return (
|
|
52
|
+
style_element?.children?.find?.((/** @type {any} */ child) => child.type === 'StyleSheet') ??
|
|
53
|
+
null
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
33
57
|
/**
|
|
34
58
|
* @param {any} node
|
|
35
59
|
* @param {any[]} [refs]
|
|
@@ -233,3 +257,70 @@ function is_function_or_class_boundary(node) {
|
|
|
233
257
|
node?.type === 'ClassExpression'
|
|
234
258
|
);
|
|
235
259
|
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* @param {any} css
|
|
263
|
+
* @returns {Map<string, any>}
|
|
264
|
+
*/
|
|
265
|
+
function collect_style_class_map_entries(css) {
|
|
266
|
+
const entries = new Map();
|
|
267
|
+
collect_rule_class_map_entries(css, entries);
|
|
268
|
+
return entries;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* @param {any} node
|
|
273
|
+
* @param {Map<string, any>} entries
|
|
274
|
+
* @returns {void}
|
|
275
|
+
*/
|
|
276
|
+
function collect_rule_class_map_entries(node, entries) {
|
|
277
|
+
if (!node || typeof node !== 'object') return;
|
|
278
|
+
|
|
279
|
+
if (Array.isArray(node)) {
|
|
280
|
+
for (const child of node) collect_rule_class_map_entries(child, entries);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (node.type === 'ComplexSelector') {
|
|
285
|
+
const class_selector = get_standalone_class_selector(node);
|
|
286
|
+
if (class_selector) {
|
|
287
|
+
const name = class_selector.name.replace(regex_backslash_and_following_character, '$1');
|
|
288
|
+
if (!entries.has(name)) {
|
|
289
|
+
entries.set(name, {
|
|
290
|
+
start: class_selector.start,
|
|
291
|
+
end: class_selector.end,
|
|
292
|
+
selector: class_selector,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (is_function_or_class_boundary(node)) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
for (const key of Object.keys(node)) {
|
|
303
|
+
if (key === 'loc' || key === 'start' || key === 'end' || key === 'metadata') {
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
collect_rule_class_map_entries(node[key], entries);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* @param {any} complex_selector
|
|
312
|
+
* @returns {any | null}
|
|
313
|
+
*/
|
|
314
|
+
function get_standalone_class_selector(complex_selector) {
|
|
315
|
+
if (complex_selector?.children?.length !== 1) return null;
|
|
316
|
+
const relative_selector = complex_selector.children[0];
|
|
317
|
+
if (
|
|
318
|
+
relative_selector?.metadata?.is_global ||
|
|
319
|
+
relative_selector?.metadata?.is_global_like ||
|
|
320
|
+
relative_selector?.selectors?.length !== 1
|
|
321
|
+
) {
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
const selector = relative_selector.selectors[0];
|
|
325
|
+
return selector?.type === 'ClassSelector' ? selector : null;
|
|
326
|
+
}
|
package/types/index.d.ts
CHANGED
|
@@ -26,6 +26,7 @@ export { createJsxTransform };
|
|
|
26
26
|
|
|
27
27
|
export function collectStyleRefAttributes(node: any, refs?: any[]): any[];
|
|
28
28
|
export function createStyleClassMap(component: any, css: any): AST.ObjectExpression;
|
|
29
|
+
export function createStyleClassMapFromStylesheet(css: any): AST.ObjectExpression;
|
|
29
30
|
export function createStyleRefSetupStatements(
|
|
30
31
|
refAttributes: any[],
|
|
31
32
|
styleMap: AST.Expression,
|
|
@@ -35,6 +36,7 @@ export function createStyleRefSetupStatements(
|
|
|
35
36
|
visitExpression?: (expression: AST.Expression) => AST.Expression;
|
|
36
37
|
},
|
|
37
38
|
): AST.Statement[];
|
|
39
|
+
export function getStyleElementStylesheet(styleElement: any): any | null;
|
|
38
40
|
|
|
39
41
|
/**
|
|
40
42
|
* Compile error interface
|
|
@@ -100,11 +102,15 @@ interface BaseNodeMetaData {
|
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
interface FunctionMetaData extends BaseNodeMetaData {
|
|
105
|
+
native_tsrx?: boolean;
|
|
103
106
|
native_tsrx_function?: boolean;
|
|
107
|
+
hook_split?: boolean;
|
|
104
108
|
is_method?: boolean;
|
|
105
109
|
tracked?: boolean;
|
|
106
110
|
has_lazy_descendants?: boolean;
|
|
107
111
|
synthetic_children?: boolean;
|
|
112
|
+
generated_helpers?: any[];
|
|
113
|
+
generated_statics?: any[];
|
|
108
114
|
}
|
|
109
115
|
|
|
110
116
|
// Strip parent, loc, and range from TSESTree nodes to match @sveltejs/acorn-typescript output
|
|
@@ -161,6 +167,13 @@ declare module 'estree' {
|
|
|
161
167
|
};
|
|
162
168
|
}
|
|
163
169
|
|
|
170
|
+
interface BlockStatement {
|
|
171
|
+
metadata: BaseNodeMetaData & {
|
|
172
|
+
hook_split_block?: boolean;
|
|
173
|
+
native_return_block?: boolean;
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
164
177
|
type Accessibility = 'public' | 'protected' | 'private'; // missing in acorn-typescript types
|
|
165
178
|
interface MethodDefinition {
|
|
166
179
|
typeParameters?: TSTypeParameterDeclaration;
|
|
@@ -236,6 +249,7 @@ declare module 'estree' {
|
|
|
236
249
|
}
|
|
237
250
|
|
|
238
251
|
interface ExpressionMap {
|
|
252
|
+
Tsrx: Tsrx;
|
|
239
253
|
Text: TextNode;
|
|
240
254
|
JSXEmptyExpression: ESTreeJSX.JSXEmptyExpression;
|
|
241
255
|
ParenthesizedExpression: ParenthesizedExpression;
|
|
@@ -341,7 +355,7 @@ declare module 'estree' {
|
|
|
341
355
|
closingElement: ESTreeJSX.JSXClosingElement;
|
|
342
356
|
}
|
|
343
357
|
|
|
344
|
-
interface Tsrx extends AST.
|
|
358
|
+
interface Tsrx extends AST.BaseExpression {
|
|
345
359
|
type: 'Tsrx';
|
|
346
360
|
attributes: Array<any>;
|
|
347
361
|
children: AST.Node[];
|
|
@@ -647,6 +661,12 @@ declare module 'estree-jsx' {
|
|
|
647
661
|
};
|
|
648
662
|
}
|
|
649
663
|
|
|
664
|
+
interface JSXOpeningElement {
|
|
665
|
+
metadata: BaseNodeMetaData & {
|
|
666
|
+
native_tsrx_pretransformed?: boolean;
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
|
|
650
670
|
interface JSXExpressionContainer {
|
|
651
671
|
text?: boolean;
|
|
652
672
|
style?: boolean;
|
package/types/jsx-platform.d.ts
CHANGED
|
@@ -42,6 +42,7 @@ export interface JsxTransformContext {
|
|
|
42
42
|
needs_for_of_iterable: boolean;
|
|
43
43
|
needs_iteration_value_type: boolean;
|
|
44
44
|
stylesheets: AST.CSS.StyleSheet[];
|
|
45
|
+
type_only_style_anchors: AST.Statement[];
|
|
45
46
|
module_scoped_hook_components: boolean;
|
|
46
47
|
helper_state: {
|
|
47
48
|
base_name: string;
|
|
@@ -154,13 +155,6 @@ export interface JsxPlatformHooks {
|
|
|
154
155
|
* state behaves like normal component state.
|
|
155
156
|
*/
|
|
156
157
|
wrapHelperComponent?: (helperFn: any, helperId: any, ctx: any, sourceNode: any) => any;
|
|
157
|
-
/**
|
|
158
|
-
* Wrap an uppercase JavaScript function that returns native TSRX as a target
|
|
159
|
-
* component. Vue uses this to turn `function App() { return <></>; }` into a
|
|
160
|
-
* `defineVaporComponent(function App() { ... })` binding while lowercase
|
|
161
|
-
* TSRX-returning callbacks stay plain functions.
|
|
162
|
-
*/
|
|
163
|
-
wrapNativeFunctionComponent?: (fn: any, ctx: any, path: any[]) => any;
|
|
164
158
|
/**
|
|
165
159
|
* Emit hook-isolation helper components as unique module-scope declarations
|
|
166
160
|
* instead of lazily creating and caching them from the parent component body.
|
|
@@ -354,10 +348,15 @@ export interface JsxPlatform {
|
|
|
354
348
|
|
|
355
349
|
jsx: {
|
|
356
350
|
/**
|
|
357
|
-
* Rewrite Ripple's `class` attribute to
|
|
358
|
-
*
|
|
351
|
+
* Rewrite Ripple's `class` attribute to `className` for legacy targets
|
|
352
|
+
* that require it. First-party targets keep authored `class`.
|
|
359
353
|
*/
|
|
360
354
|
rewriteClassAttr: boolean;
|
|
355
|
+
/**
|
|
356
|
+
* Attribute name to use when TSRX injects scoped CSS classes. This does
|
|
357
|
+
* not rewrite authored attributes.
|
|
358
|
+
*/
|
|
359
|
+
classAttrName?: 'class' | 'className';
|
|
361
360
|
/**
|
|
362
361
|
* Accepted values of `kind` in `<tsx:kind>` compat blocks. React accepts
|
|
363
362
|
* only `'react'`. Preact accepts both `'preact'` and `'react'`.
|