@tsrx/core 0.1.48 → 0.1.50
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 +0 -1
- package/src/plugin.js +72 -17
- package/src/transform/await.js +14 -12
- package/src/transform/jsx/ast-builders.js +2 -81
- package/src/transform/jsx/helpers.js +11 -6
- package/src/transform/jsx/index.js +951 -727
- package/src/transform/jsx-hoist.js +2 -1
- package/src/transform/jsx-interleave.js +22 -36
- package/src/transform/scoping.js +4 -2
- package/src/transform/segments.js +20 -6
- package/src/utils/ast.js +37 -0
- package/src/utils/builders.js +22 -15
- package/types/helpers.d.ts +1 -2
- package/types/index.d.ts +79 -16
- package/types/jsx-platform.d.ts +18 -8
- package/types/parse.d.ts +2 -4
- package/types/runtime/ref.d.ts +1 -5
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** @import * as AST from 'estree' */
|
|
1
2
|
/** @import * as ESTreeJSX from 'estree-jsx' */
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -104,7 +105,7 @@ export function is_hoist_safe_jsx_attribute(attribute) {
|
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
/**
|
|
107
|
-
* @param {
|
|
108
|
+
* @param {AST.TSRXJSXElement | AST.TSRXJSXFragment} node
|
|
108
109
|
* @returns {boolean}
|
|
109
110
|
*/
|
|
110
111
|
export function is_hoist_safe_jsx_node(node) {
|
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
* textually after the mutation.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
/** @import * as AST from 'estree' */
|
|
12
|
+
/** @import * as ESTreeJSX from 'estree-jsx' */
|
|
13
|
+
|
|
14
|
+
import * as b from '../utils/builders.js';
|
|
15
|
+
|
|
11
16
|
/**
|
|
12
17
|
* Returns true when the body contains a non-JSX statement that appears
|
|
13
18
|
* after a JSX child. In that case JSX children must be captured at their
|
|
@@ -17,8 +22,8 @@
|
|
|
17
22
|
* The `is_jsx_child` predicate is target-specific — each target recognizes
|
|
18
23
|
* its JSX-bearing child nodes and template-control expressions.
|
|
19
24
|
*
|
|
20
|
-
* @param {
|
|
21
|
-
* @param {(node:
|
|
25
|
+
* @param {AST.Node[]} body_nodes
|
|
26
|
+
* @param {(node: AST.Node) => boolean} is_jsx_child
|
|
22
27
|
* @returns {boolean}
|
|
23
28
|
*/
|
|
24
29
|
export function is_interleaved_body(body_nodes, is_jsx_child) {
|
|
@@ -35,11 +40,12 @@ export function is_interleaved_body(body_nodes, is_jsx_child) {
|
|
|
35
40
|
|
|
36
41
|
/**
|
|
37
42
|
* Only JSX nodes that evaluate to a single expression can be hoisted into a
|
|
38
|
-
* `const`. Static text children (`JSXText`)
|
|
39
|
-
*
|
|
43
|
+
* `const`. Static text children (`JSXText`) and comment-only containers
|
|
44
|
+
* (`{/* … *\/}`) are inert and don't need capturing — their position relative
|
|
45
|
+
* to mutations doesn't change output, and neither has an expression to bind.
|
|
40
46
|
*
|
|
41
|
-
* @param {
|
|
42
|
-
* @returns {
|
|
47
|
+
* @param {AST.Node | null | undefined} jsx
|
|
48
|
+
* @returns {jsx is ESTreeJSX.JSXCapturableChild}
|
|
43
49
|
*/
|
|
44
50
|
export function is_capturable_jsx_child(jsx) {
|
|
45
51
|
if (!jsx) return false;
|
|
@@ -48,7 +54,8 @@ export function is_capturable_jsx_child(jsx) {
|
|
|
48
54
|
// into a const would evaluate them once.
|
|
49
55
|
if (jsx.metadata?.tsrx_reactive_block === true) return false;
|
|
50
56
|
const t = jsx.type;
|
|
51
|
-
|
|
57
|
+
if (t === 'JSXExpressionContainer') return jsx.expression.type !== 'JSXEmptyExpression';
|
|
58
|
+
return t === 'JSXElement' || t === 'JSXFragment';
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
/**
|
|
@@ -58,45 +65,24 @@ export function is_capturable_jsx_child(jsx) {
|
|
|
58
65
|
* statements in source order and uses the reference in place of the JSX
|
|
59
66
|
* child inside the returned fragment.
|
|
60
67
|
*
|
|
61
|
-
* @param {
|
|
68
|
+
* @param {ESTreeJSX.JSXCapturableChild} jsx
|
|
62
69
|
* @param {number} capture_index
|
|
63
|
-
* @
|
|
70
|
+
* @param {(id: AST.Identifier, init: AST.Expression) => AST.Identifier} [anchor_id] gives the
|
|
71
|
+
* capture's NAME an authored origin — the only anchorable token when the captured
|
|
72
|
+
* expression itself starts with punctuation
|
|
73
|
+
* @returns {{ declaration: AST.VariableDeclaration, reference: ESTreeJSX.JSXExpressionContainer }}
|
|
64
74
|
*/
|
|
65
|
-
export function capture_jsx_child(jsx, capture_index) {
|
|
75
|
+
export function capture_jsx_child(jsx, capture_index, anchor_id) {
|
|
66
76
|
const name = `_tsrx_child_${capture_index}`;
|
|
67
77
|
const init = jsx.type === 'JSXExpressionContainer' ? jsx.expression : jsx;
|
|
68
78
|
|
|
69
|
-
const declaration =
|
|
70
|
-
type: 'VariableDeclaration',
|
|
71
|
-
kind: 'const',
|
|
72
|
-
declarations: [
|
|
73
|
-
/** @type {any} */ ({
|
|
74
|
-
type: 'VariableDeclarator',
|
|
75
|
-
id: /** @type {any} */ ({
|
|
76
|
-
type: 'Identifier',
|
|
77
|
-
name,
|
|
78
|
-
metadata: { path: [] },
|
|
79
|
-
}),
|
|
80
|
-
init,
|
|
81
|
-
metadata: { path: [] },
|
|
82
|
-
}),
|
|
83
|
-
],
|
|
84
|
-
metadata: { path: [] },
|
|
85
|
-
});
|
|
79
|
+
const declaration = b.const(anchor_id ? anchor_id(b.id(name), init) : b.id(name), init);
|
|
86
80
|
|
|
87
81
|
// NOTE: JSXExpressionContainer nodes are intentionally created without
|
|
88
82
|
// loc — they're synthetic wrappers whose source positions don't
|
|
89
83
|
// correspond to source-map entries and adding loc causes Volar mapping
|
|
90
84
|
// failures.
|
|
91
|
-
const reference =
|
|
92
|
-
type: 'JSXExpressionContainer',
|
|
93
|
-
expression: /** @type {any} */ ({
|
|
94
|
-
type: 'Identifier',
|
|
95
|
-
name,
|
|
96
|
-
metadata: { path: [] },
|
|
97
|
-
}),
|
|
98
|
-
metadata: { path: [] },
|
|
99
|
-
});
|
|
85
|
+
const reference = b.jsx_expression_container(b.id(name));
|
|
100
86
|
|
|
101
87
|
return { declaration, reference };
|
|
102
88
|
}
|
package/src/transform/scoping.js
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* `.foo.hash`) match after rendering.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
/** @import * as AST from 'estree' */
|
|
9
|
+
|
|
8
10
|
import { walk } from 'zimmerframe';
|
|
9
11
|
import * as b from '../utils/builders.js';
|
|
10
12
|
import { mark_class_map_selectors } from './style-ref.js';
|
|
@@ -91,8 +93,8 @@ function is_unreachable_via_class_map(complex_selector, path) {
|
|
|
91
93
|
}
|
|
92
94
|
|
|
93
95
|
/**
|
|
94
|
-
* @param {
|
|
95
|
-
* @returns {
|
|
96
|
+
* @param {AST.Node | null | undefined} node
|
|
97
|
+
* @returns {node is AST.JSXStyleElement}
|
|
96
98
|
*/
|
|
97
99
|
export function is_style_element(node) {
|
|
98
100
|
return !!node && node.type === 'JSXStyleElement';
|
|
@@ -68,6 +68,7 @@ import { should_preserve_comment } from '../comment-utils.js';
|
|
|
68
68
|
import { has_location } from '../utils/ast.js';
|
|
69
69
|
|
|
70
70
|
const LAZY_PARAM_IDENTIFIER_REGEX = /^__lazy\d+$/;
|
|
71
|
+
const RETURN_KEYWORD = 'return';
|
|
71
72
|
|
|
72
73
|
/**
|
|
73
74
|
* @param {string} value
|
|
@@ -1506,18 +1507,31 @@ export function convert_source_map_to_mappings(
|
|
|
1506
1507
|
visit(node.argument);
|
|
1507
1508
|
}
|
|
1508
1509
|
|
|
1509
|
-
|
|
1510
|
+
// Map only the `return` KEYWORD: a whole-statement mapping is too broad
|
|
1511
|
+
// and shadows the finer mappings of everything inside it.
|
|
1512
|
+
//
|
|
1513
|
+
// That clamp is only meaningful when the author actually wrote the
|
|
1514
|
+
// keyword there. A SYNTHESIZED return — every template arm in a
|
|
1515
|
+
// `.tsrx` file (`@case`/`@default`/`@empty`/`@else` bodies, a `@{ … }`
|
|
1516
|
+
// body) — carries the arm's authored range instead, whose text is the
|
|
1517
|
+
// arm's own syntax. Clamping that to six characters pairs an arbitrary
|
|
1518
|
+
// slice of source (`@defau`) with an arbitrary slice of output
|
|
1519
|
+
// (`defaul`), which then wins any narrowest-match lookup. A
|
|
1520
|
+
// synthesized return has no authored keyword to point at, so it
|
|
1521
|
+
// contributes no mapping.
|
|
1522
|
+
if (
|
|
1523
|
+
node.type === 'ReturnStatement' &&
|
|
1524
|
+
has_location(node) &&
|
|
1525
|
+
source.startsWith(RETURN_KEYWORD, node.start)
|
|
1526
|
+
) {
|
|
1510
1527
|
const mapping = get_mapping_from_node(
|
|
1511
1528
|
node,
|
|
1512
1529
|
src_to_gen_map,
|
|
1513
1530
|
gen_line_offsets,
|
|
1514
1531
|
mapping_data_verify_only,
|
|
1515
1532
|
);
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
const return_keyword_length = 'return'.length;
|
|
1519
|
-
mapping.lengths = [return_keyword_length];
|
|
1520
|
-
mapping.generatedLengths = [return_keyword_length];
|
|
1533
|
+
mapping.lengths = [RETURN_KEYWORD.length];
|
|
1534
|
+
mapping.generatedLengths = [RETURN_KEYWORD.length];
|
|
1521
1535
|
|
|
1522
1536
|
mappings.push(mapping);
|
|
1523
1537
|
}
|
package/src/utils/ast.js
CHANGED
|
@@ -20,6 +20,43 @@
|
|
|
20
20
|
|
|
21
21
|
import * as b from './builders.js';
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @param {unknown} value
|
|
25
|
+
* @returns {value is AST.Node}
|
|
26
|
+
*/
|
|
27
|
+
export function is_ast_node(value) {
|
|
28
|
+
return !!value && typeof value === 'object' && 'type' in value;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The child nodes reachable from `node`'s own properties, flattening node
|
|
33
|
+
* arrays. Positional and metadata keys are skipped: they never hold children,
|
|
34
|
+
* and `metadata` in particular can hold memoized lowerings of nodes that are
|
|
35
|
+
* already reachable elsewhere in the tree.
|
|
36
|
+
*
|
|
37
|
+
* @param {AST.Node} node
|
|
38
|
+
* @param {string} [skip_key] an extra own key to skip
|
|
39
|
+
* @returns {AST.Node[]}
|
|
40
|
+
*/
|
|
41
|
+
export function child_nodes(node, skip_key) {
|
|
42
|
+
/** @type {AST.Node[]} */
|
|
43
|
+
const children = [];
|
|
44
|
+
const entries = /** @type {AST.TraversableAstNode} */ (node);
|
|
45
|
+
for (const key of Object.keys(entries)) {
|
|
46
|
+
if (key === 'loc' || key === 'start' || key === 'end' || key === 'metadata') continue;
|
|
47
|
+
if (key === skip_key) continue;
|
|
48
|
+
const value = entries[key];
|
|
49
|
+
if (Array.isArray(value)) {
|
|
50
|
+
for (const item of value) {
|
|
51
|
+
if (is_ast_node(item)) children.push(item);
|
|
52
|
+
}
|
|
53
|
+
} else if (is_ast_node(value)) {
|
|
54
|
+
children.push(value);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return children;
|
|
58
|
+
}
|
|
59
|
+
|
|
23
60
|
/**
|
|
24
61
|
* @template {object} T
|
|
25
62
|
* @param {T | null | undefined} node
|
package/src/utils/builders.js
CHANGED
|
@@ -605,13 +605,17 @@ export function ts_type_literal(members, loc_info) {
|
|
|
605
605
|
}
|
|
606
606
|
|
|
607
607
|
/**
|
|
608
|
+
* `@types/estree`'s `Statement` union has no TS declarations in it, so the
|
|
609
|
+
* result is typed as both: a `type X = …` alias occupies a statement slot
|
|
610
|
+
* everywhere the transforms emit one.
|
|
611
|
+
*
|
|
608
612
|
* @param {AST.Identifier} id
|
|
609
613
|
* @param {AST.Node} type_annotation
|
|
610
614
|
* @param {AST.NodeWithLocation} [loc_info]
|
|
611
|
-
* @returns {AST.TSTypeAliasDeclaration}
|
|
615
|
+
* @returns {AST.TSTypeAliasDeclaration & AST.Statement}
|
|
612
616
|
*/
|
|
613
617
|
export function ts_type_alias(id, type_annotation, loc_info) {
|
|
614
|
-
const node = /** @type {AST.TSTypeAliasDeclaration} */ ({
|
|
618
|
+
const node = /** @type {AST.TSTypeAliasDeclaration & AST.Statement} */ ({
|
|
615
619
|
type: 'TSTypeAliasDeclaration',
|
|
616
620
|
id,
|
|
617
621
|
typeParameters: undefined,
|
|
@@ -1090,8 +1094,8 @@ export function try_builder(block, handler = null, finalizer = null, pending = n
|
|
|
1090
1094
|
}
|
|
1091
1095
|
|
|
1092
1096
|
/**
|
|
1093
|
-
* @param {AST.Pattern | null} param
|
|
1094
|
-
* @param {AST.Pattern | null} reset_param
|
|
1097
|
+
* @param {AST.Pattern | null | undefined} param
|
|
1098
|
+
* @param {AST.Pattern | null | undefined} reset_param
|
|
1095
1099
|
* @param {AST.BlockStatement} body
|
|
1096
1100
|
* @param {AST.NodeWithLocation} [loc_info]
|
|
1097
1101
|
* @return {AST.CatchClause}
|
|
@@ -1100,8 +1104,8 @@ export function catch_clause_builder(param, reset_param, body, loc_info) {
|
|
|
1100
1104
|
/** @type {AST.CatchClause} */
|
|
1101
1105
|
const node = {
|
|
1102
1106
|
type: 'CatchClause',
|
|
1103
|
-
param,
|
|
1104
|
-
resetParam: reset_param,
|
|
1107
|
+
param: param ?? null,
|
|
1108
|
+
resetParam: reset_param ?? null,
|
|
1105
1109
|
body,
|
|
1106
1110
|
metadata: { path: [] },
|
|
1107
1111
|
};
|
|
@@ -1147,7 +1151,7 @@ export function jsx_attribute(name, value = null, shorthand = false, loc_info) {
|
|
|
1147
1151
|
* @param {boolean} [self_closing]
|
|
1148
1152
|
* @param {ESTreeJSX.JSXOpeningElement['typeArguments']} [type_arguments]
|
|
1149
1153
|
* @param {AST.NodeWithLocation} [loc_info]
|
|
1150
|
-
* @returns {ESTreeJSX.
|
|
1154
|
+
* @returns {ESTreeJSX.TSRXJSXOpeningElement}
|
|
1151
1155
|
*/
|
|
1152
1156
|
export function jsx_opening_element(
|
|
1153
1157
|
name,
|
|
@@ -1156,7 +1160,7 @@ export function jsx_opening_element(
|
|
|
1156
1160
|
type_arguments = undefined,
|
|
1157
1161
|
loc_info,
|
|
1158
1162
|
) {
|
|
1159
|
-
const node = /** @type {ESTreeJSX.
|
|
1163
|
+
const node = /** @type {ESTreeJSX.TSRXJSXOpeningElement} */ ({
|
|
1160
1164
|
type: 'JSXOpeningElement',
|
|
1161
1165
|
name,
|
|
1162
1166
|
attributes,
|
|
@@ -1173,10 +1177,10 @@ export function jsx_opening_element(
|
|
|
1173
1177
|
*
|
|
1174
1178
|
* @param {ESTreeJSX.TSRXJSXClosingElement['name']} name
|
|
1175
1179
|
* @param {AST.NodeWithLocation} [loc_info]
|
|
1176
|
-
* @returns {ESTreeJSX.
|
|
1180
|
+
* @returns {ESTreeJSX.TSRXJSXClosingElement}
|
|
1177
1181
|
*/
|
|
1178
1182
|
export function jsx_closing_element(name, loc_info) {
|
|
1179
|
-
const node = /** @type {ESTreeJSX.
|
|
1183
|
+
const node = /** @type {ESTreeJSX.TSRXJSXClosingElement} */ ({
|
|
1180
1184
|
type: 'JSXClosingElement',
|
|
1181
1185
|
name,
|
|
1182
1186
|
metadata: { path: [] },
|
|
@@ -1191,11 +1195,14 @@ export function jsx_closing_element(name, loc_info) {
|
|
|
1191
1195
|
* derived from an existing source node, use `jsx_element` (which spreads
|
|
1192
1196
|
* the source's name and metadata).
|
|
1193
1197
|
*
|
|
1194
|
-
*
|
|
1195
|
-
*
|
|
1196
|
-
*
|
|
1198
|
+
* Carries the parser's widened TSRX shape (dynamic-tag names, lowered template
|
|
1199
|
+
* children) — see {@link jsx_element}.
|
|
1200
|
+
*
|
|
1201
|
+
* @param {ESTreeJSX.TSRXJSXOpeningElement} opening_element
|
|
1202
|
+
* @param {ESTreeJSX.TSRXJSXClosingElement | null} [closing_element]
|
|
1203
|
+
* @param {AST.TSRXJSXElement['children']} [children]
|
|
1197
1204
|
* @param {AST.NodeWithLocation} [loc_info]
|
|
1198
|
-
* @returns {
|
|
1205
|
+
* @returns {AST.TSRXJSXElement}
|
|
1199
1206
|
*/
|
|
1200
1207
|
export function jsx_element_fresh(
|
|
1201
1208
|
opening_element,
|
|
@@ -1203,7 +1210,7 @@ export function jsx_element_fresh(
|
|
|
1203
1210
|
children = [],
|
|
1204
1211
|
loc_info,
|
|
1205
1212
|
) {
|
|
1206
|
-
const node = /** @type {
|
|
1213
|
+
const node = /** @type {AST.TSRXJSXElement} */ ({
|
|
1207
1214
|
type: 'JSXElement',
|
|
1208
1215
|
openingElement: opening_element,
|
|
1209
1216
|
closingElement: closing_element,
|
package/types/helpers.d.ts
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import type { Parse } from './parse.js';
|
|
|
5
5
|
import type * as ESRap from 'esrap';
|
|
6
6
|
import type { Position } from 'acorn';
|
|
7
7
|
import type { RequireAllOrNone } from './helpers';
|
|
8
|
+
import type { Context as ZimmerframeContext } from 'zimmerframe';
|
|
8
9
|
import type {
|
|
9
10
|
JsxPlatform,
|
|
10
11
|
JsxPlatformHooks,
|
|
@@ -27,7 +28,8 @@ export { createJsxTransform };
|
|
|
27
28
|
/** Result of extracting a branch body into a generated helper component. */
|
|
28
29
|
export interface JsxHelperComponent {
|
|
29
30
|
setup_statements: AST.Statement[];
|
|
30
|
-
|
|
31
|
+
/** The parser's widened TSRX element shape — see {@link AST.TSRXJSXElement}. */
|
|
32
|
+
component_element: AST.TSRXJSXElement;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
export function collectStyleRefAttributes(
|
|
@@ -86,7 +88,7 @@ export interface CompileOptions {
|
|
|
86
88
|
}
|
|
87
89
|
|
|
88
90
|
export type NameSpace = 'html' | 'svg' | 'mathml';
|
|
89
|
-
interface BaseNodeMetaData {
|
|
91
|
+
export interface BaseNodeMetaData {
|
|
90
92
|
scoped?: boolean;
|
|
91
93
|
path: AST.Node[];
|
|
92
94
|
has_template?: boolean;
|
|
@@ -105,6 +107,8 @@ interface BaseNodeMetaData {
|
|
|
105
107
|
commentContainerId?: number;
|
|
106
108
|
parenthesized?: boolean;
|
|
107
109
|
native_tsrx?: boolean;
|
|
110
|
+
/** The function's body came from a `@{ … }` code block that has been lowered. */
|
|
111
|
+
native_tsrx_body?: boolean;
|
|
108
112
|
tsrx_generated_wrapper?: boolean;
|
|
109
113
|
native_tsrx_template_block?: boolean;
|
|
110
114
|
dynamicElement?: boolean;
|
|
@@ -155,9 +159,19 @@ interface BaseNodeMetaData {
|
|
|
155
159
|
disable_verification?: boolean;
|
|
156
160
|
extra_source_mappings?: AST.NodeWithLocation[];
|
|
157
161
|
generated_setup_declarations?: AST.Statement[];
|
|
162
|
+
/** Helper components lifted out of a component; read back by `expand_component_helpers`. */
|
|
163
|
+
generated_helpers?: AST.Statement[];
|
|
164
|
+
/** Module-level static JSX hoisted out of a component. */
|
|
165
|
+
generated_statics?: AST.Statement[];
|
|
158
166
|
has_unmappable_value?: boolean;
|
|
159
167
|
synthetic_ref?: boolean;
|
|
160
168
|
tsrx_reactive_block?: boolean;
|
|
169
|
+
/** Generated dynamic-tag render-block closure, not a user component boundary. */
|
|
170
|
+
tsrx_dynamic_wrapper?: boolean;
|
|
171
|
+
/** Scoped-class definition sites, for editor definitions/hover on `style.x`. */
|
|
172
|
+
styleClasses?: StyleClasses;
|
|
173
|
+
/** Top-level scoped classes collected while pruning the component's CSS. */
|
|
174
|
+
topScopedClasses?: TopScopedClasses;
|
|
161
175
|
vapor_pending_fallback?: ESTreeJSX.JSXRenderNode;
|
|
162
176
|
lazy_param_binding_mappings?: Array<{
|
|
163
177
|
source: AST.Identifier;
|
|
@@ -165,7 +179,7 @@ interface BaseNodeMetaData {
|
|
|
165
179
|
}>;
|
|
166
180
|
}
|
|
167
181
|
|
|
168
|
-
interface FunctionMetaData extends BaseNodeMetaData {
|
|
182
|
+
export interface FunctionMetaData extends BaseNodeMetaData {
|
|
169
183
|
native_tsrx?: boolean;
|
|
170
184
|
native_tsrx_function?: boolean;
|
|
171
185
|
is_method?: boolean;
|
|
@@ -173,11 +187,7 @@ interface FunctionMetaData extends BaseNodeMetaData {
|
|
|
173
187
|
has_lazy_descendants?: boolean;
|
|
174
188
|
/** The component's extracted `<style>` stylesheet (element-level scoped-class info lives on BaseNodeMetaData's `css`). */
|
|
175
189
|
component_css?: AST.CSS.StyleSheet | null;
|
|
176
|
-
/** Top-level scoped classes collected while pruning the component's CSS. */
|
|
177
|
-
topScopedClasses?: TopScopedClasses;
|
|
178
190
|
synthetic_children?: boolean;
|
|
179
|
-
generated_helpers?: AST.Statement[];
|
|
180
|
-
generated_statics?: AST.Statement[];
|
|
181
191
|
}
|
|
182
192
|
|
|
183
193
|
// Strip parent, loc, and range from TSESTree nodes to match @sveltejs/acorn-typescript output
|
|
@@ -405,6 +415,8 @@ declare module 'estree' {
|
|
|
405
415
|
test: AST.Expression;
|
|
406
416
|
consequent: AST.Statement;
|
|
407
417
|
alternate: AST.Statement | null;
|
|
418
|
+
/** Span of the `@else` keyword; only present when `alternate` is. */
|
|
419
|
+
alternateKeyword?: AST.NodeWithLocation | null;
|
|
408
420
|
metadata: BaseNodeMetaData;
|
|
409
421
|
}
|
|
410
422
|
|
|
@@ -415,6 +427,11 @@ declare module 'estree' {
|
|
|
415
427
|
index?: AST.Identifier | null;
|
|
416
428
|
key?: AST.Expression | null;
|
|
417
429
|
empty?: AST.BlockStatement | null;
|
|
430
|
+
/**
|
|
431
|
+
* Span of the `@empty` keyword; only present when `empty` is. The clause's
|
|
432
|
+
* block starts at its `{`, so this is the only pointer to the keyword text.
|
|
433
|
+
*/
|
|
434
|
+
emptyKeyword?: AST.NodeWithLocation | null;
|
|
418
435
|
metadata: BaseNodeMetaData;
|
|
419
436
|
}
|
|
420
437
|
|
|
@@ -461,10 +478,7 @@ declare module 'estree' {
|
|
|
461
478
|
|
|
462
479
|
/** A `@if`/`@for`/`@switch`/`@try` template control-flow directive. */
|
|
463
480
|
type JSXTemplateDirective =
|
|
464
|
-
|
|
|
465
|
-
| JSXForExpression
|
|
466
|
-
| JSXSwitchExpression
|
|
467
|
-
| JSXTryExpression;
|
|
481
|
+
JSXIfExpression | JSXForExpression | JSXSwitchExpression | JSXTryExpression;
|
|
468
482
|
|
|
469
483
|
/** A statement-form template directive after its parser node has been retyped. */
|
|
470
484
|
type JSXTemplateStatement =
|
|
@@ -525,16 +539,27 @@ declare module 'estree' {
|
|
|
525
539
|
interface TryStatement {
|
|
526
540
|
statementType?: 'TryStatement';
|
|
527
541
|
pending?: AST.BlockStatement | null;
|
|
542
|
+
/** Span of the `@pending` keyword; only present when `pending` is. */
|
|
543
|
+
pendingKeyword?: AST.NodeWithLocation | null;
|
|
544
|
+
/** Span of the `@catch` keyword; only present when `handler` is. */
|
|
545
|
+
handlerKeyword?: AST.NodeWithLocation | null;
|
|
528
546
|
}
|
|
529
547
|
|
|
530
548
|
interface IfStatement {
|
|
531
549
|
statementType?: 'IfStatement';
|
|
550
|
+
/** Span of the `@else` keyword; only present when `alternate` is. */
|
|
551
|
+
alternateKeyword?: AST.NodeWithLocation | null;
|
|
532
552
|
}
|
|
533
553
|
|
|
534
554
|
interface SwitchStatement {
|
|
535
555
|
statementType?: 'SwitchStatement';
|
|
536
556
|
}
|
|
537
557
|
|
|
558
|
+
interface SwitchCase {
|
|
559
|
+
/** Span of the arm's `@case`/`@default` keyword. */
|
|
560
|
+
keyword?: AST.NodeWithLocation | null;
|
|
561
|
+
}
|
|
562
|
+
|
|
538
563
|
interface CatchClause {
|
|
539
564
|
resetParam?: AST.Pattern | null;
|
|
540
565
|
}
|
|
@@ -544,6 +569,8 @@ declare module 'estree' {
|
|
|
544
569
|
index?: AST.Identifier | null;
|
|
545
570
|
key?: AST.Expression | null;
|
|
546
571
|
empty?: AST.BlockStatement | null;
|
|
572
|
+
/** Span of the `@empty` keyword; only present when `empty` is. */
|
|
573
|
+
emptyKeyword?: AST.NodeWithLocation | null;
|
|
547
574
|
}
|
|
548
575
|
|
|
549
576
|
interface ImportDeclaration {
|
|
@@ -796,8 +823,21 @@ declare module 'estree-jsx' {
|
|
|
796
823
|
/** A node that can be returned from a platform hook into a JSX render slot. */
|
|
797
824
|
type JSXRenderNode = AST.Expression | JSXExpressionContainer | JSXText | JSXSpreadChild;
|
|
798
825
|
|
|
799
|
-
/**
|
|
800
|
-
|
|
826
|
+
/**
|
|
827
|
+
* A JSX child produced by the transform's render-body lowering. Elements and
|
|
828
|
+
* fragments carry the parser's widened TSRX shape, which plain estree-jsx
|
|
829
|
+
* elements are assignable to.
|
|
830
|
+
*/
|
|
831
|
+
type JSXRenderChild = AST.TSRXJSXElement | AST.TSRXJSXFragment | JSXExpressionContainer | JSXText;
|
|
832
|
+
|
|
833
|
+
/**
|
|
834
|
+
* A JSX child that evaluates to a single expression, so it can be captured
|
|
835
|
+
* into a `const` at its source position.
|
|
836
|
+
*/
|
|
837
|
+
type JSXCapturableChild =
|
|
838
|
+
| AST.TSRXJSXElement
|
|
839
|
+
| AST.TSRXJSXFragment
|
|
840
|
+
| (JSXExpressionContainer & { expression: AST.Expression });
|
|
801
841
|
|
|
802
842
|
/** An attribute accepted by and emitted from the shared JSX transformer. */
|
|
803
843
|
type JSXAttributeNode = JSXAttribute | JSXSpreadAttribute;
|
|
@@ -810,9 +850,7 @@ declare module 'estree-jsx' {
|
|
|
810
850
|
|
|
811
851
|
/** A child accepted while TSRX JSX is being lowered to standard ESTree JSX. */
|
|
812
852
|
type JSXTransformChild =
|
|
813
|
-
|
|
814
|
-
| AST.TSRXJSXElement
|
|
815
|
-
| AST.TSRXJSXFragment;
|
|
853
|
+
JSXElement['children'][number] | AST.TSRXJSXElement | AST.TSRXJSXFragment;
|
|
816
854
|
|
|
817
855
|
interface JSXAttribute {
|
|
818
856
|
shorthand: boolean;
|
|
@@ -1679,6 +1717,14 @@ export interface TransformClientState extends BaseState {
|
|
|
1679
1717
|
ref_target_type?: AST.TypeNode;
|
|
1680
1718
|
}
|
|
1681
1719
|
|
|
1720
|
+
/** Accumulator for the helper components and statics a component lift produces. */
|
|
1721
|
+
export interface JsxHelperState {
|
|
1722
|
+
base_name: string;
|
|
1723
|
+
next_id: number;
|
|
1724
|
+
helpers: AST.Statement[];
|
|
1725
|
+
statics: AST.Statement[];
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1682
1728
|
/** Override zimmerframe types and provide our own */
|
|
1683
1729
|
/**
|
|
1684
1730
|
* Where stock `@types/estree-jsx` and the TSRX parser shapes share a `type`
|
|
@@ -1748,6 +1794,13 @@ export type VisitorClientContext = TransformClientContext & {
|
|
|
1748
1794
|
value_position?: boolean;
|
|
1749
1795
|
};
|
|
1750
1796
|
|
|
1797
|
+
/**
|
|
1798
|
+
* The zimmerframe visitor context the JSX transform's visitors receive. Walked
|
|
1799
|
+
* over the `Node` union rather than `Program`, since only that union admits a
|
|
1800
|
+
* visitor per node type.
|
|
1801
|
+
*/
|
|
1802
|
+
export type JsxVisitorContext = ZimmerframeContext<AST.Node, JsxTransformContext>;
|
|
1803
|
+
|
|
1751
1804
|
/**
|
|
1752
1805
|
* Delegated event result
|
|
1753
1806
|
*/
|
|
@@ -1766,6 +1819,16 @@ export type TopScopedClasses = Map<
|
|
|
1766
1819
|
|
|
1767
1820
|
export type StyleClasses = Map<string, AST.MemberExpression['property']>;
|
|
1768
1821
|
|
|
1822
|
+
/**
|
|
1823
|
+
* The scoped-CSS work for one native TSRX node: its stylesheet, the `style.x`
|
|
1824
|
+
* ref attributes that reference it, and a hash-annotated copy of the node.
|
|
1825
|
+
*/
|
|
1826
|
+
export interface JsxStyleContext {
|
|
1827
|
+
css: AST.CSS.StyleSheet;
|
|
1828
|
+
style_refs: ESTreeJSX.JSXAttribute[];
|
|
1829
|
+
fragment: AST.NativeTSRXNode;
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1769
1832
|
/**
|
|
1770
1833
|
* Event handling types
|
|
1771
1834
|
*/
|
package/types/jsx-platform.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type * as AST from 'estree';
|
|
2
2
|
import type * as ESTreeJSX from 'estree-jsx';
|
|
3
3
|
import type { RawSourceMap } from 'source-map';
|
|
4
|
-
import type { CompileError, JsxHelperComponent } from './index';
|
|
4
|
+
import type { CompileError, JsxHelperComponent, JsxHelperState } from './index';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Result returned by a JSX platform transform (React, Preact, Solid).
|
|
@@ -53,12 +53,7 @@ export interface JsxTransformContext {
|
|
|
53
53
|
stylesheets: AST.CSS.StyleSheet[];
|
|
54
54
|
type_only_style_anchors: AST.Statement[];
|
|
55
55
|
module_scoped_hook_components: boolean;
|
|
56
|
-
helper_state:
|
|
57
|
-
base_name: string;
|
|
58
|
-
next_id: number;
|
|
59
|
-
helpers: AST.Statement[];
|
|
60
|
-
statics: AST.Statement[];
|
|
61
|
-
} | null;
|
|
56
|
+
helper_state: JsxHelperState | null;
|
|
62
57
|
hook_helpers_enabled: boolean;
|
|
63
58
|
available_bindings: Map<string, AST.Identifier>;
|
|
64
59
|
lazy_next_id: number;
|
|
@@ -75,6 +70,12 @@ export interface JsxTransformContext {
|
|
|
75
70
|
comments: AST.CommentWithLocation[] | undefined;
|
|
76
71
|
/** True when emitting a type-only virtual TSX module; preserves lazy destructuring patterns. */
|
|
77
72
|
typeOnly: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* True when generated nodes may be anchored on the directive keyword that
|
|
75
|
+
* produced them. Off by default; the emitted code and its source map are
|
|
76
|
+
* unchanged when clear.
|
|
77
|
+
*/
|
|
78
|
+
inspect: boolean;
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
/**
|
|
@@ -121,6 +122,15 @@ export interface JsxTransformOptions {
|
|
|
121
122
|
* bindings.
|
|
122
123
|
*/
|
|
123
124
|
typeOnly?: boolean;
|
|
125
|
+
/**
|
|
126
|
+
* Anchor generated nodes on the directive keyword that produced them, so
|
|
127
|
+
* navigation tooling can trace an authored `@for` / `@empty` to the code it
|
|
128
|
+
* became. Off by default — a directive is lowered away entirely, so nothing
|
|
129
|
+
* in the source map otherwise reaches its keyword. With the flag clear the
|
|
130
|
+
* output bytes and every mapping derived from them are unaffected, which is
|
|
131
|
+
* why the editor pipeline never asks for it.
|
|
132
|
+
*/
|
|
133
|
+
inspect?: boolean;
|
|
124
134
|
}
|
|
125
135
|
|
|
126
136
|
/**
|
|
@@ -303,7 +313,7 @@ export interface JsxPlatformHooks {
|
|
|
303
313
|
* otherwise statically safe. Targets can use this to keep runtime-sensitive
|
|
304
314
|
* JSX, such as component invocations, inside render/setup execution.
|
|
305
315
|
*/
|
|
306
|
-
canHoistStaticNode?: (node:
|
|
316
|
+
canHoistStaticNode?: (node: AST.TSRXJSXElement, ctx: JsxTransformContext) => boolean;
|
|
307
317
|
/**
|
|
308
318
|
* Custom validation for a component body that uses top-level `await`.
|
|
309
319
|
* Default: enforce `validation.requireUseServerForAwait`. Solid rejects
|
package/types/parse.d.ts
CHANGED
|
@@ -1677,8 +1677,7 @@ export namespace Parse {
|
|
|
1677
1677
|
* Parse JSX namespaced name (ns:name)
|
|
1678
1678
|
*/
|
|
1679
1679
|
jsx_parseNamespacedName():
|
|
1680
|
-
|
|
1681
|
-
| ReturnType<Parser['jsx_parseIdentifier']>;
|
|
1680
|
+
ESTreeJSX.JSXNamespacedName | ReturnType<Parser['jsx_parseIdentifier']>;
|
|
1682
1681
|
|
|
1683
1682
|
/**
|
|
1684
1683
|
* Parse JSX element name (identifier, member, namespaced, or a dynamic
|
|
@@ -1695,8 +1694,7 @@ export namespace Parse {
|
|
|
1695
1694
|
* @returns Attribute value (expression, string, or element)
|
|
1696
1695
|
*/
|
|
1697
1696
|
jsx_parseAttributeValue():
|
|
1698
|
-
|
|
1699
|
-
| ReturnType<Parser['parseExprAtom']>;
|
|
1697
|
+
ESTreeJSX.JSXExpressionContainer | ReturnType<Parser['parseExprAtom']>;
|
|
1700
1698
|
|
|
1701
1699
|
/**
|
|
1702
1700
|
* Parse JSX empty expression (for {})
|
package/types/runtime/ref.d.ts
CHANGED
|
@@ -14,11 +14,7 @@ export type RefValue<T = Element> =
|
|
|
14
14
|
| undefined;
|
|
15
15
|
|
|
16
16
|
export type MergeableRef<T> =
|
|
17
|
-
|
|
|
18
|
-
| MergeableRefObject<T>
|
|
19
|
-
| MergeableVueRef<T>
|
|
20
|
-
| null
|
|
21
|
-
| undefined;
|
|
17
|
+
MergeableRefCallback<T> | MergeableRefObject<T> | MergeableVueRef<T> | null | undefined;
|
|
22
18
|
|
|
23
19
|
export function mergeRefs<T = any>(...refs: Array<MergeableRef<T>>): (node: T | null) => () => void;
|
|
24
20
|
export function isRefProp(value: unknown): boolean;
|