@tsrx/core 0.1.46 → 0.1.47
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/index.js +2 -2
- package/src/parse/index.js +3 -2
- package/src/transform/jsx/ast-builders.js +131 -110
- package/src/transform/jsx/helpers.js +76 -81
- package/src/transform/jsx/index.js +342 -360
- package/src/transform/lazy.js +5 -5
- package/src/transform/segments.js +29 -28
- package/src/transform/style-ref.js +9 -13
- package/src/utils/ast.js +11 -0
- package/src/utils/builders.js +3 -3
- package/types/index.d.ts +86 -11
- package/types/jsx-platform.d.ts +88 -54
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** @import * as AST from 'estree' */
|
|
2
|
-
/** @import
|
|
2
|
+
/** @import * as ESRap from 'esrap' */
|
|
3
3
|
|
|
4
4
|
import tsx from 'esrap/languages/tsx';
|
|
5
5
|
import { should_preserve_comment, format_comment } from '../../comment-utils.js';
|
|
@@ -12,7 +12,7 @@ import { should_preserve_comment, format_comment } from '../../comment-utils.js'
|
|
|
12
12
|
* transform built around render children — either way a bare expression in a
|
|
13
13
|
* child slot would print as JSX text.
|
|
14
14
|
*
|
|
15
|
-
* @param {
|
|
15
|
+
* @param {AST.Node[]} path
|
|
16
16
|
* @returns {boolean}
|
|
17
17
|
*/
|
|
18
18
|
export function in_jsx_child_context(path) {
|
|
@@ -21,15 +21,14 @@ export function in_jsx_child_context(path) {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
* @param {
|
|
24
|
+
* @param {AST.Node | null | undefined} node
|
|
25
25
|
* @returns {boolean}
|
|
26
26
|
*/
|
|
27
27
|
export function is_empty_jsx_fragment(node) {
|
|
28
28
|
return (
|
|
29
29
|
node?.type === 'JSXFragment' &&
|
|
30
30
|
!(node.children || []).some(
|
|
31
|
-
(
|
|
32
|
-
child && (child.type !== 'JSXText' || child.value.trim() !== ''),
|
|
31
|
+
(child) => child && (child.type !== 'JSXText' || child.value.trim() !== ''),
|
|
33
32
|
)
|
|
34
33
|
);
|
|
35
34
|
}
|
|
@@ -39,8 +38,8 @@ export function is_empty_jsx_fragment(node) {
|
|
|
39
38
|
* carries its current ancestor path for downstream CSS pruning and mapping
|
|
40
39
|
* helpers.
|
|
41
40
|
*
|
|
42
|
-
* @param {
|
|
43
|
-
* @param {
|
|
41
|
+
* @param {AST.Node} node
|
|
42
|
+
* @param {AST.Node[]} path
|
|
44
43
|
* @returns {void}
|
|
45
44
|
*/
|
|
46
45
|
export function set_node_path_metadata(node, path) {
|
|
@@ -62,7 +61,7 @@ export function set_node_path_metadata(node, path) {
|
|
|
62
61
|
*
|
|
63
62
|
* Shared across all JSX-producing targets (React, Preact, Solid).
|
|
64
63
|
*
|
|
65
|
-
* @returns {
|
|
64
|
+
* @returns {ESRap.Visitors<AST.Node>}
|
|
66
65
|
*/
|
|
67
66
|
/**
|
|
68
67
|
* @param {boolean} [boundary_tokens] Enable esrap's `boundaryTokens` anchors
|
|
@@ -76,16 +75,17 @@ export function set_node_path_metadata(node, path) {
|
|
|
76
75
|
* TS input — dropping a leading pragma changes how the whole file checks.
|
|
77
76
|
*/
|
|
78
77
|
export function tsx_with_ts_locations(boundary_tokens = false, comments = undefined) {
|
|
79
|
-
const base =
|
|
78
|
+
const base = tsx({ boundaryTokens: boundary_tokens });
|
|
79
|
+
const { _: base_visitor, ...base_visitors } = base;
|
|
80
80
|
|
|
81
|
-
const leading_preserved = (/** @type {
|
|
81
|
+
const leading_preserved = (/** @type {AST.Program} */ program) => {
|
|
82
82
|
if (!comments?.length) return [];
|
|
83
83
|
// Injected statements (dynamic-import/try-import prepends) carry no
|
|
84
84
|
// loc; anchor "leading" on the first statement that maps to source,
|
|
85
85
|
// else every preserved comment in the file would hoist to the top.
|
|
86
|
-
const first = program.body
|
|
86
|
+
const first = program.body.find((node) => node.loc);
|
|
87
87
|
return comments.filter(
|
|
88
|
-
(
|
|
88
|
+
(comment) =>
|
|
89
89
|
should_preserve_comment(comment) &&
|
|
90
90
|
(first?.loc == null ||
|
|
91
91
|
(comment.loc &&
|
|
@@ -95,22 +95,7 @@ export function tsx_with_ts_locations(boundary_tokens = false, comments = undefi
|
|
|
95
95
|
);
|
|
96
96
|
};
|
|
97
97
|
|
|
98
|
-
/**
|
|
99
|
-
* @param {any} node
|
|
100
|
-
* @param {any} context
|
|
101
|
-
* @param {any} visitor
|
|
102
|
-
*/
|
|
103
|
-
const wrap_with_locations = (node, context, visitor) => {
|
|
104
|
-
if (!node.loc) {
|
|
105
|
-
visitor(node, context);
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
context.location(node.loc.start.line, node.loc.start.column);
|
|
109
|
-
visitor(node, context);
|
|
110
|
-
context.location(node.loc.end.line, node.loc.end.column);
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
/** @type {Record<string, (node: any, context: any) => void>} */
|
|
98
|
+
/** @type {ESRap.Visitors<AST.Node>} */
|
|
114
99
|
const wrappers = {
|
|
115
100
|
Program: (node, context) => {
|
|
116
101
|
for (const comment of leading_preserved(node)) {
|
|
@@ -119,10 +104,10 @@ export function tsx_with_ts_locations(boundary_tokens = false, comments = undefi
|
|
|
119
104
|
if (comment.loc) context.location(comment.loc.end.line, comment.loc.end.column);
|
|
120
105
|
context.newline();
|
|
121
106
|
}
|
|
122
|
-
base.Program(node, context);
|
|
107
|
+
/** @type {NonNullable<typeof base.Program>} */ (base.Program)(node, context);
|
|
123
108
|
},
|
|
124
109
|
ArrayPattern: (node, context) => {
|
|
125
|
-
base.ArrayPattern(node, context);
|
|
110
|
+
/** @type {NonNullable<typeof base.ArrayPattern>} */ (base.ArrayPattern)(node, context);
|
|
126
111
|
if (node.typeAnnotation) {
|
|
127
112
|
context.visit(node.typeAnnotation);
|
|
128
113
|
}
|
|
@@ -143,7 +128,7 @@ export function tsx_with_ts_locations(boundary_tokens = false, comments = undefi
|
|
|
143
128
|
// must fall through to base.Property to preserve their printed form.
|
|
144
129
|
Property: (node, context) => {
|
|
145
130
|
if (!node.method || node.value.type !== 'FunctionExpression') {
|
|
146
|
-
base.Property(node, context);
|
|
131
|
+
/** @type {NonNullable<typeof base.Property>} */ (base.Property)(node, context);
|
|
147
132
|
return;
|
|
148
133
|
}
|
|
149
134
|
const value = node.value;
|
|
@@ -204,58 +189,68 @@ export function tsx_with_ts_locations(boundary_tokens = false, comments = undefi
|
|
|
204
189
|
context.visit(node.id);
|
|
205
190
|
context.visit(node.body);
|
|
206
191
|
},
|
|
192
|
+
_(node, context, visit) {
|
|
193
|
+
const visit_with_locations = () => {
|
|
194
|
+
if (!LOCATION_WRAPPED_NODE_TYPES.has(node.type) || !node.loc) {
|
|
195
|
+
visit(node);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
context.location(node.loc.start.line, node.loc.start.column);
|
|
199
|
+
visit(node);
|
|
200
|
+
context.location(node.loc.end.line, node.loc.end.column);
|
|
201
|
+
};
|
|
202
|
+
if (base_visitor) {
|
|
203
|
+
base_visitor(node, context, visit_with_locations);
|
|
204
|
+
} else {
|
|
205
|
+
visit_with_locations();
|
|
206
|
+
}
|
|
207
|
+
},
|
|
207
208
|
};
|
|
208
209
|
|
|
209
|
-
|
|
210
|
-
// above in the `wrappers`
|
|
211
|
-
// if there is already a visitor but you still need a mapping
|
|
212
|
-
// on the whole node, only then duplicate it here
|
|
213
|
-
// e.g. JSXOpeningElement is such a case
|
|
214
|
-
for (const type of [
|
|
215
|
-
// JS nodes with boundary positions esrap still cannot map. Keyword
|
|
216
|
-
// writes (if/new/return/for/switch/await) and `boundaryTokens`
|
|
217
|
-
// anchors (brackets, braces, parens, computed/call closers) cover
|
|
218
|
-
// many STARTS, but statement ENDS land on unanchored characters
|
|
219
|
-
// (`;`, a block's `}`), `class` is not a keyword-write, template
|
|
220
|
-
// literals' backticks carry no location, and an arrow's span can
|
|
221
|
-
// start at a bare `(` — so these node-level markers remain the
|
|
222
|
-
// source of both boundaries until esrap can anchor them.
|
|
223
|
-
'ClassDeclaration',
|
|
224
|
-
'ClassExpression',
|
|
225
|
-
'IfStatement',
|
|
226
|
-
'NewExpression',
|
|
227
|
-
'MemberExpression',
|
|
228
|
-
'ObjectExpression',
|
|
229
|
-
'ReturnStatement',
|
|
230
|
-
'ForStatement',
|
|
231
|
-
'ForInStatement',
|
|
232
|
-
'ForOfStatement',
|
|
233
|
-
'TemplateLiteral',
|
|
234
|
-
'AwaitExpression',
|
|
235
|
-
'SwitchStatement',
|
|
236
|
-
'TaggedTemplateExpression',
|
|
237
|
-
'ArrowFunctionExpression',
|
|
238
|
-
// JSX wrapper nodes: esrap writes `<`, `>`, `</`, `{`, `}` without
|
|
239
|
-
// locations, so the opening/closing element's and expression
|
|
240
|
-
// container's start and end don't resolve.
|
|
241
|
-
'JSXOpeningElement',
|
|
242
|
-
'JSXClosingElement',
|
|
243
|
-
'JSXExpressionContainer',
|
|
244
|
-
// TS wrapper nodes with the same issue.
|
|
245
|
-
'TSTypeParameterInstantiation',
|
|
246
|
-
'TSTypeParameterDeclaration',
|
|
247
|
-
'TSTypeParameter',
|
|
248
|
-
]) {
|
|
249
|
-
const visitor = wrappers[type];
|
|
250
|
-
|
|
251
|
-
wrappers[type] = (node, context) => wrap_with_locations(node, context, visitor ?? base[type]);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
return { ...base, ...wrappers };
|
|
210
|
+
return { ...base_visitors, ...wrappers };
|
|
255
211
|
}
|
|
256
212
|
|
|
213
|
+
// Be careful when adding visitors that are already defined in `wrappers`.
|
|
214
|
+
// JSXOpeningElement is intentionally in both places: its custom printer still
|
|
215
|
+
// needs a location marker around the whole node.
|
|
216
|
+
const LOCATION_WRAPPED_NODE_TYPES = new Set([
|
|
217
|
+
// JS nodes with boundary positions esrap still cannot map. Keyword
|
|
218
|
+
// writes (if/new/return/for/switch/await) and `boundaryTokens`
|
|
219
|
+
// anchors (brackets, braces, parens, computed/call closers) cover
|
|
220
|
+
// many STARTS, but statement ENDS land on unanchored characters
|
|
221
|
+
// (`;`, a block's `}`), `class` is not a keyword-write, template
|
|
222
|
+
// literals' backticks carry no location, and an arrow's span can
|
|
223
|
+
// start at a bare `(` — so these node-level markers remain the
|
|
224
|
+
// source of both boundaries until esrap can anchor them.
|
|
225
|
+
'ClassDeclaration',
|
|
226
|
+
'ClassExpression',
|
|
227
|
+
'IfStatement',
|
|
228
|
+
'NewExpression',
|
|
229
|
+
'MemberExpression',
|
|
230
|
+
'ObjectExpression',
|
|
231
|
+
'ReturnStatement',
|
|
232
|
+
'ForStatement',
|
|
233
|
+
'ForInStatement',
|
|
234
|
+
'ForOfStatement',
|
|
235
|
+
'TemplateLiteral',
|
|
236
|
+
'AwaitExpression',
|
|
237
|
+
'SwitchStatement',
|
|
238
|
+
'TaggedTemplateExpression',
|
|
239
|
+
'ArrowFunctionExpression',
|
|
240
|
+
// JSX wrapper nodes: esrap writes `<`, `>`, `</`, `{`, `}` without
|
|
241
|
+
// locations, so the opening/closing element's and expression
|
|
242
|
+
// container's start and end don't resolve.
|
|
243
|
+
'JSXOpeningElement',
|
|
244
|
+
'JSXClosingElement',
|
|
245
|
+
'JSXExpressionContainer',
|
|
246
|
+
// TS wrapper nodes with the same issue.
|
|
247
|
+
'TSTypeParameterInstantiation',
|
|
248
|
+
'TSTypeParameterDeclaration',
|
|
249
|
+
'TSTypeParameter',
|
|
250
|
+
]);
|
|
251
|
+
|
|
257
252
|
/**
|
|
258
|
-
* @param {
|
|
253
|
+
* @param {AST.Node | null | undefined} node
|
|
259
254
|
* @returns {boolean}
|
|
260
255
|
*/
|
|
261
256
|
export function is_template_if_node(node) {
|
|
@@ -266,7 +261,7 @@ export function is_template_if_node(node) {
|
|
|
266
261
|
}
|
|
267
262
|
|
|
268
263
|
/**
|
|
269
|
-
* @param {
|
|
264
|
+
* @param {AST.Node | null | undefined} node
|
|
270
265
|
* @returns {boolean}
|
|
271
266
|
*/
|
|
272
267
|
export function is_template_for_of_node(node) {
|
|
@@ -277,7 +272,7 @@ export function is_template_for_of_node(node) {
|
|
|
277
272
|
}
|
|
278
273
|
|
|
279
274
|
/**
|
|
280
|
-
* @param {
|
|
275
|
+
* @param {AST.Node | null | undefined} node
|
|
281
276
|
* @returns {boolean}
|
|
282
277
|
*/
|
|
283
278
|
export function is_template_switch_node(node) {
|
|
@@ -288,7 +283,7 @@ export function is_template_switch_node(node) {
|
|
|
288
283
|
}
|
|
289
284
|
|
|
290
285
|
/**
|
|
291
|
-
* @param {
|
|
286
|
+
* @param {AST.Node | null | undefined} node
|
|
292
287
|
* @returns {boolean}
|
|
293
288
|
*/
|
|
294
289
|
export function is_template_try_node(node) {
|