@tsrx/core 0.1.20 → 0.1.22
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 +3 -3
- package/src/analyze/prune.js +119 -61
- package/src/analyze/validation.js +122 -5
- package/src/index.js +11 -3
- package/src/parse/index.js +157 -99
- package/src/plugin.js +2417 -844
- package/src/runtime/iterable.js +15 -13
- package/src/scope.js +25 -10
- package/src/source-map-utils.js +1 -1
- package/src/transform/await.js +5 -1
- package/src/transform/jsx/ast-builders.js +44 -59
- package/src/transform/jsx/helpers.js +8 -5
- package/src/transform/jsx/index.js +755 -344
- package/src/transform/jsx-interleave.js +1 -2
- package/src/transform/scoping.js +26 -63
- package/src/transform/segments.js +53 -5
- package/src/transform/style-ref.js +3 -11
- package/src/utils/builders.js +2 -3
- package/types/index.d.ts +179 -110
- package/types/jsx-platform.d.ts +6 -11
- package/types/parse.d.ts +36 -10
- package/types/runtime/ref.d.ts +1 -0
package/src/runtime/iterable.js
CHANGED
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
* @param {Iterable<T> | Iterator<T>} iterable
|
|
5
5
|
* @param {(item: T, index: number, is_last: boolean) => U} fn
|
|
6
6
|
* @param {() => U | U[]} [tail]
|
|
7
|
+
* @param {() => U | U[]} [empty]
|
|
7
8
|
* @returns {U[]}
|
|
8
9
|
*/
|
|
9
|
-
export function map_iterable(iterable, fn, tail) {
|
|
10
|
+
export function map_iterable(iterable, fn, tail, empty) {
|
|
10
11
|
if (Array.isArray(iterable)) {
|
|
11
|
-
return map_array(iterable, fn, tail);
|
|
12
|
+
return map_array(iterable, fn, tail, empty);
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
/** @type {Iterator<T>} */
|
|
@@ -25,14 +26,14 @@ export function map_iterable(iterable, fn, tail) {
|
|
|
25
26
|
|
|
26
27
|
var current = iterator.next();
|
|
27
28
|
if (current.done) {
|
|
28
|
-
if (!
|
|
29
|
+
if (!empty) {
|
|
29
30
|
return [];
|
|
30
31
|
}
|
|
31
|
-
var
|
|
32
|
-
if (Array.isArray(
|
|
33
|
-
return
|
|
32
|
+
var empty_value = empty();
|
|
33
|
+
if (Array.isArray(empty_value)) {
|
|
34
|
+
return empty_value;
|
|
34
35
|
}
|
|
35
|
-
return [
|
|
36
|
+
return [empty_value];
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
var index = 0;
|
|
@@ -71,19 +72,20 @@ export function map_iterable(iterable, fn, tail) {
|
|
|
71
72
|
* @param {Array<T>} array
|
|
72
73
|
* @param {(item: T, index: number, is_last: boolean) => U} fn
|
|
73
74
|
* @param {() => U | U[]} [tail]
|
|
75
|
+
* @param {() => U | U[]} [empty]
|
|
74
76
|
* @returns {U[]}
|
|
75
77
|
*/
|
|
76
|
-
function map_array(array, fn, tail) {
|
|
78
|
+
function map_array(array, fn, tail, empty) {
|
|
77
79
|
var length = array.length;
|
|
78
80
|
if (length === 0) {
|
|
79
|
-
if (!
|
|
81
|
+
if (!empty) {
|
|
80
82
|
return [];
|
|
81
83
|
}
|
|
82
|
-
var
|
|
83
|
-
if (Array.isArray(
|
|
84
|
-
return
|
|
84
|
+
var empty_value = empty();
|
|
85
|
+
if (Array.isArray(empty_value)) {
|
|
86
|
+
return empty_value;
|
|
85
87
|
}
|
|
86
|
-
return [
|
|
88
|
+
return [empty_value];
|
|
87
89
|
}
|
|
88
90
|
var result = [];
|
|
89
91
|
for (var i = 0; i < length; i++) {
|
package/src/scope.js
CHANGED
|
@@ -107,18 +107,28 @@ export function create_scopes(ast, root, parent, error_options) {
|
|
|
107
107
|
}
|
|
108
108
|
},
|
|
109
109
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
JSXElement(node, { state, next }) {
|
|
111
|
+
if (node.metadata?.native_tsrx) {
|
|
112
|
+
const scope = state.scope.child();
|
|
113
|
+
scopes.set(node, scope);
|
|
113
114
|
|
|
114
|
-
|
|
115
|
+
next({ scope });
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
next();
|
|
115
120
|
},
|
|
116
121
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
122
|
+
JSXFragment(node, { state, next }) {
|
|
123
|
+
if (node.metadata?.native_tsrx) {
|
|
124
|
+
const scope = state.scope.child();
|
|
125
|
+
scopes.set(node, scope);
|
|
120
126
|
|
|
121
|
-
|
|
127
|
+
next({ scope });
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
next();
|
|
122
132
|
},
|
|
123
133
|
|
|
124
134
|
TSModuleDeclaration(node, { state, next }) {
|
|
@@ -169,6 +179,8 @@ export function create_scopes(ast, root, parent, error_options) {
|
|
|
169
179
|
ForInStatement: create_block_scope,
|
|
170
180
|
ForOfStatement: create_block_scope,
|
|
171
181
|
SwitchStatement: create_block_scope,
|
|
182
|
+
JSXForExpression: create_block_scope,
|
|
183
|
+
JSXSwitchExpression: create_block_scope,
|
|
172
184
|
BlockStatement(node, context) {
|
|
173
185
|
const parent = context.path.at(-1);
|
|
174
186
|
if (
|
|
@@ -192,13 +204,16 @@ export function create_scopes(ast, root, parent, error_options) {
|
|
|
192
204
|
for (const declarator of node.declarations) {
|
|
193
205
|
/** @type {Binding[]} */
|
|
194
206
|
const bindings = [];
|
|
195
|
-
const initial = /** @type {AST.Expression |
|
|
207
|
+
const initial = /** @type {AST.Expression | null} */ (declarator.init);
|
|
196
208
|
|
|
197
209
|
state.scope.declarators.set(declarator, bindings);
|
|
198
210
|
|
|
199
211
|
for (const id of extract_identifiers(declarator.id)) {
|
|
200
212
|
const binding = state.scope.declare(id, 'normal', node.kind, initial);
|
|
201
|
-
if (
|
|
213
|
+
if (
|
|
214
|
+
(initial?.type === 'JSXElement' || initial?.type === 'JSXFragment') &&
|
|
215
|
+
initial.metadata?.native_tsrx
|
|
216
|
+
) {
|
|
202
217
|
binding.metadata = {
|
|
203
218
|
...(binding.metadata ?? {}),
|
|
204
219
|
is_template_value: true,
|
package/src/source-map-utils.js
CHANGED
package/src/transform/await.js
CHANGED
|
@@ -42,7 +42,11 @@ export function find_first_top_level_await(node, inside_nested_function) {
|
|
|
42
42
|
return null;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
if (
|
|
45
|
+
if (
|
|
46
|
+
node.type === 'AwaitExpression' ||
|
|
47
|
+
(node.type === 'ForOfStatement' && node.await === true) ||
|
|
48
|
+
(node.type === 'JSXForExpression' && node.await === true)
|
|
49
|
+
) {
|
|
46
50
|
return node;
|
|
47
51
|
}
|
|
48
52
|
|
|
@@ -89,6 +89,44 @@ export function clone_jsx_name(name, source_node = name) {
|
|
|
89
89
|
return name;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Convert a JSX tag name back into a JavaScript expression. Dynamic element
|
|
94
|
+
* tags are parsed as JSX-shaped names, but the runtime alias needs ordinary JS.
|
|
95
|
+
*
|
|
96
|
+
* @param {any} name
|
|
97
|
+
* @returns {any}
|
|
98
|
+
*/
|
|
99
|
+
export function jsx_name_to_expression(name) {
|
|
100
|
+
if (!name) return name;
|
|
101
|
+
if (name.type === 'JSXIdentifier') {
|
|
102
|
+
return set_loc(
|
|
103
|
+
/** @type {any} */ ({
|
|
104
|
+
type: 'Identifier',
|
|
105
|
+
name: name.name,
|
|
106
|
+
metadata: name.metadata || { path: [] },
|
|
107
|
+
}),
|
|
108
|
+
name,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
if (name.type === 'JSXMemberExpression') {
|
|
112
|
+
return set_loc(
|
|
113
|
+
/** @type {any} */ ({
|
|
114
|
+
type: 'MemberExpression',
|
|
115
|
+
object: jsx_name_to_expression(name.object),
|
|
116
|
+
property: jsx_name_to_expression(name.property),
|
|
117
|
+
computed: false,
|
|
118
|
+
optional: false,
|
|
119
|
+
metadata: name.metadata || { path: [] },
|
|
120
|
+
}),
|
|
121
|
+
name,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
if (name.type === 'Identifier' || name.type === 'MemberExpression') {
|
|
125
|
+
return clone_expression_node(name);
|
|
126
|
+
}
|
|
127
|
+
return name;
|
|
128
|
+
}
|
|
129
|
+
|
|
92
130
|
/**
|
|
93
131
|
* @returns {AST.Literal}
|
|
94
132
|
*/
|
|
@@ -242,11 +280,10 @@ export function is_jsx_child(node) {
|
|
|
242
280
|
t === 'JSXFragment' ||
|
|
243
281
|
t === 'JSXExpressionContainer' ||
|
|
244
282
|
t === 'JSXText' ||
|
|
245
|
-
t === '
|
|
246
|
-
t === '
|
|
247
|
-
t === '
|
|
248
|
-
t === '
|
|
249
|
-
t === 'TSRXExpression' ||
|
|
283
|
+
t === 'JSXIfExpression' ||
|
|
284
|
+
t === 'JSXForExpression' ||
|
|
285
|
+
t === 'JSXSwitchExpression' ||
|
|
286
|
+
t === 'JSXTryExpression' ||
|
|
250
287
|
t === 'IfStatement' ||
|
|
251
288
|
t === 'ForOfStatement' ||
|
|
252
289
|
t === 'SwitchStatement' ||
|
|
@@ -316,10 +353,10 @@ export function is_dynamic_element_id(id) {
|
|
|
316
353
|
if (!id || typeof id !== 'object') {
|
|
317
354
|
return false;
|
|
318
355
|
}
|
|
319
|
-
if (id.type === 'Identifier') {
|
|
356
|
+
if (id.type === 'Identifier' || id.type === 'JSXIdentifier') {
|
|
320
357
|
return !!id.tracked;
|
|
321
358
|
}
|
|
322
|
-
if (id.type === 'MemberExpression') {
|
|
359
|
+
if (id.type === 'MemberExpression' || id.type === 'JSXMemberExpression') {
|
|
323
360
|
return is_dynamic_element_id(id.object);
|
|
324
361
|
}
|
|
325
362
|
return false;
|
|
@@ -368,58 +405,6 @@ export function flatten_switch_consequent(consequent) {
|
|
|
368
405
|
return result;
|
|
369
406
|
}
|
|
370
407
|
|
|
371
|
-
/**
|
|
372
|
-
* Compute fall-through expansions for each `case` in a `switch`. JavaScript
|
|
373
|
-
* `switch` semantics say that once a case body executes, execution continues
|
|
374
|
-
* into the bodies of subsequent cases until a `break` or terminal `return` is
|
|
375
|
-
* hit. We pre-compute, per case, the flat list of statements that should run
|
|
376
|
-
* when that case is the entry point — so downstream targets (which render each
|
|
377
|
-
* case independently rather than executing fall-through at runtime) still
|
|
378
|
-
* produce the right output.
|
|
379
|
-
*
|
|
380
|
-
* Walking right-to-left lets each case reuse the next case's already-expanded
|
|
381
|
-
* tail without recomputation. Downstream nodes are deep-cloned when absorbed
|
|
382
|
-
* so each case's expanded body owns its own AST subtree.
|
|
383
|
-
*
|
|
384
|
-
* @param {any[]} cases
|
|
385
|
-
* @returns {Array<{ test: any, body: any[], source: any }>}
|
|
386
|
-
*/
|
|
387
|
-
export function expand_switch_cases_for_fallthrough(cases) {
|
|
388
|
-
/** @type {Array<{ test: any, body: any[], source: any }>} */
|
|
389
|
-
const expanded = new Array(cases.length);
|
|
390
|
-
for (let i = cases.length - 1; i >= 0; i--) {
|
|
391
|
-
const consequent = flatten_switch_consequent(cases[i].consequent || []);
|
|
392
|
-
const body = [];
|
|
393
|
-
let has_terminal = false;
|
|
394
|
-
for (const child of consequent) {
|
|
395
|
-
if (child.type === 'BreakStatement') {
|
|
396
|
-
has_terminal = true;
|
|
397
|
-
break;
|
|
398
|
-
}
|
|
399
|
-
body.push(child);
|
|
400
|
-
if (child.type === 'ReturnStatement') {
|
|
401
|
-
has_terminal = true;
|
|
402
|
-
break;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
// Strip locations from cloned downstream nodes. Only the original case
|
|
406
|
-
// (one entry up the chain) keeps `loc`/`start`/`end`; clones inlined
|
|
407
|
-
// into upstream cases would otherwise point editor IntelliSense at the
|
|
408
|
-
// same source range multiple times (one hover/go-to-definition per
|
|
409
|
-
// fall-through entry point), producing double/triple results in Volar.
|
|
410
|
-
const downstream =
|
|
411
|
-
!has_terminal && i + 1 < cases.length
|
|
412
|
-
? expanded[i + 1].body.map((n) => clone_expression_node(n, false))
|
|
413
|
-
: [];
|
|
414
|
-
expanded[i] = {
|
|
415
|
-
test: cases[i].test,
|
|
416
|
-
body: [...body, ...downstream],
|
|
417
|
-
source: cases[i],
|
|
418
|
-
};
|
|
419
|
-
}
|
|
420
|
-
return expanded;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
408
|
/**
|
|
424
409
|
* @param {AST.Expression | null | undefined} expression
|
|
425
410
|
* @returns {boolean}
|
|
@@ -4,17 +4,20 @@
|
|
|
4
4
|
import tsx from 'esrap/languages/tsx';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Zimmerframe provides `path` as the ancestor chain
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* it renders as a standalone expression (e.g. a return value).
|
|
7
|
+
* Zimmerframe provides `path` as the ancestor chain. A native template node whose
|
|
8
|
+
* parent is another native template node renders as a JSX child; anywhere else it
|
|
9
|
+
* renders as a standalone expression (e.g. a return value).
|
|
11
10
|
*
|
|
12
11
|
* @param {any[]} path
|
|
13
12
|
* @returns {boolean}
|
|
14
13
|
*/
|
|
15
14
|
export function in_jsx_child_context(path) {
|
|
16
15
|
const parent = path[path.length - 1];
|
|
17
|
-
return
|
|
16
|
+
return (
|
|
17
|
+
!!parent &&
|
|
18
|
+
(parent.type === 'JSXElement' || parent.type === 'JSXFragment') &&
|
|
19
|
+
parent.metadata?.native_tsrx
|
|
20
|
+
);
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
/**
|