@tsrx/core 0.1.20 → 0.1.24
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 +117 -70
- package/src/analyze/validation.js +122 -5
- package/src/diagnostics.js +1 -0
- package/src/index.js +10 -4
- package/src/parse/index.js +157 -99
- package/src/plugin.js +2540 -867
- package/src/runtime/html.js +1 -1
- package/src/runtime/iterable.js +15 -13
- package/src/runtime/language-helpers.js +39 -0
- 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 +6 -81
- package/src/transform/jsx/helpers.js +8 -5
- package/src/transform/jsx/index.js +1440 -451
- package/src/transform/jsx-interleave.js +1 -2
- package/src/transform/scoping.js +26 -63
- package/src/transform/segments.js +66 -48
- package/src/transform/style-ref.js +3 -11
- package/src/utils/builders.js +2 -3
- package/types/index.d.ts +181 -115
- package/types/jsx-platform.d.ts +14 -11
- package/types/parse.d.ts +36 -10
- package/types/runtime/html.d.ts +1 -0
- package/types/runtime/language-helpers.d.ts +4 -0
- package/types/runtime/ref.d.ts +1 -0
package/src/runtime/html.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { is_boolean_attribute } from '../utils/dom.js';
|
|
1
|
+
export { is_boolean_attribute, is_void_element } from '../utils/dom.js';
|
|
2
2
|
export { escape, escape_script } from '../utils/escaping.js';
|
|
3
3
|
export { normalize_css_property_name } from '../utils/normalize_css_property_name.js';
|
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++) {
|
|
@@ -89,3 +89,42 @@ export function iterable_array_from(iterable, index = 0) {
|
|
|
89
89
|
}
|
|
90
90
|
return result;
|
|
91
91
|
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Creates a shallow forwarding object without one prop. Values are exposed through
|
|
95
|
+
* getters so compiler-emitted reactive prop accessors are not snapshotted.
|
|
96
|
+
* @param {Record<PropertyKey, any> | null | undefined} props
|
|
97
|
+
* @param {PropertyKey} exclude_prop
|
|
98
|
+
* @returns {Record<PropertyKey, any>}
|
|
99
|
+
*/
|
|
100
|
+
export function exclude_prop_from_object(props, exclude_prop) {
|
|
101
|
+
/** @type {Record<PropertyKey, any>} */
|
|
102
|
+
const next = {};
|
|
103
|
+
if (props == null) return next;
|
|
104
|
+
|
|
105
|
+
for (const prop of Reflect.ownKeys(props)) {
|
|
106
|
+
if (prop === exclude_prop) continue;
|
|
107
|
+
|
|
108
|
+
const descriptor = get_descriptor(props, prop);
|
|
109
|
+
if (!descriptor?.enumerable) continue;
|
|
110
|
+
|
|
111
|
+
/** @type {PropertyDescriptor} */
|
|
112
|
+
const forwarding_descriptor = {
|
|
113
|
+
enumerable: true,
|
|
114
|
+
configurable: true,
|
|
115
|
+
get() {
|
|
116
|
+
return props[prop];
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
if (descriptor.writable === true || typeof descriptor.set === 'function') {
|
|
121
|
+
forwarding_descriptor.set = (value) => {
|
|
122
|
+
props[prop] = value;
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
define_property(next, prop, forwarding_descriptor);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return next;
|
|
130
|
+
}
|
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
|
|
|
@@ -242,11 +242,10 @@ export function is_jsx_child(node) {
|
|
|
242
242
|
t === 'JSXFragment' ||
|
|
243
243
|
t === 'JSXExpressionContainer' ||
|
|
244
244
|
t === 'JSXText' ||
|
|
245
|
-
t === '
|
|
246
|
-
t === '
|
|
247
|
-
t === '
|
|
248
|
-
t === '
|
|
249
|
-
t === 'TSRXExpression' ||
|
|
245
|
+
t === 'JSXIfExpression' ||
|
|
246
|
+
t === 'JSXForExpression' ||
|
|
247
|
+
t === 'JSXSwitchExpression' ||
|
|
248
|
+
t === 'JSXTryExpression' ||
|
|
250
249
|
t === 'IfStatement' ||
|
|
251
250
|
t === 'ForOfStatement' ||
|
|
252
251
|
t === 'SwitchStatement' ||
|
|
@@ -305,26 +304,6 @@ export function is_bare_render_expression(node) {
|
|
|
305
304
|
}
|
|
306
305
|
}
|
|
307
306
|
|
|
308
|
-
/**
|
|
309
|
-
* A dynamic element id is one whose identifier is `tracked` — i.e. it was
|
|
310
|
-
* introduced by reactive destructuring so its value can change at runtime.
|
|
311
|
-
*
|
|
312
|
-
* @param {any} id
|
|
313
|
-
* @returns {boolean}
|
|
314
|
-
*/
|
|
315
|
-
export function is_dynamic_element_id(id) {
|
|
316
|
-
if (!id || typeof id !== 'object') {
|
|
317
|
-
return false;
|
|
318
|
-
}
|
|
319
|
-
if (id.type === 'Identifier') {
|
|
320
|
-
return !!id.tracked;
|
|
321
|
-
}
|
|
322
|
-
if (id.type === 'MemberExpression') {
|
|
323
|
-
return is_dynamic_element_id(id.object);
|
|
324
|
-
}
|
|
325
|
-
return false;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
307
|
/**
|
|
329
308
|
* Gather the params a `for (x of y; index i)` loop should expose to its body
|
|
330
309
|
* JSX (value first, optional index second).
|
|
@@ -368,58 +347,6 @@ export function flatten_switch_consequent(consequent) {
|
|
|
368
347
|
return result;
|
|
369
348
|
}
|
|
370
349
|
|
|
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
350
|
/**
|
|
424
351
|
* @param {AST.Expression | null | undefined} expression
|
|
425
352
|
* @returns {boolean}
|
|
@@ -446,10 +373,8 @@ function is_static_string_expression(expression) {
|
|
|
446
373
|
* When the expression is statically a non-null string at the AST level —
|
|
447
374
|
* a string `Literal` (`"hello"`, `'hello'`) or a `TemplateLiteral` with no
|
|
448
375
|
* interpolations (`` `hello` ``) — the coercion is provably a no-op and
|
|
449
|
-
* the literal is emitted as-is.
|
|
450
|
-
*
|
|
451
|
-
* still get the ternary because the AST alone can't prove they're non-null
|
|
452
|
-
* strings.
|
|
376
|
+
* the literal is emitted as-is. Identifiers and any other expression type still
|
|
377
|
+
* get the ternary because the AST alone can't prove they're non-null strings.
|
|
453
378
|
*
|
|
454
379
|
* @param {AST.Expression} expression
|
|
455
380
|
* @param {any} [source_node]
|
|
@@ -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
|
/**
|