@tsrx/core 0.0.18 → 0.0.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 +2 -1
- package/src/transform/jsx/index.js +139 -71
- package/types/index.d.ts +9 -1
- package/types/jsx-platform.d.ts +49 -0
- package/types/runtime/merge-refs.d.ts +12 -0
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Core compiler infrastructure for TSRX syntax",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Dominic Gannaway",
|
|
6
|
-
"version": "0.0.
|
|
6
|
+
"version": "0.0.19",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"types": "./types/acorn.d.ts"
|
|
29
29
|
},
|
|
30
30
|
"./runtime/merge-refs": {
|
|
31
|
+
"types": "./types/runtime/merge-refs.d.ts",
|
|
31
32
|
"default": "./src/runtime/merge-refs.js"
|
|
32
33
|
},
|
|
33
34
|
"./test-harness/source-mappings": "./tests/shared/source-mappings.js",
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/** @import * as AST from 'estree' */
|
|
2
2
|
/** @import * as ESTreeJSX from 'estree-jsx' */
|
|
3
|
-
/** @import { JsxPlatform, JsxTransformOptions, JsxTransformResult } from '@tsrx/core/types' */
|
|
3
|
+
/** @import { JsxPlatform, JsxTransformContext, JsxTransformOptions, JsxTransformResult } from '@tsrx/core/types' */
|
|
4
4
|
|
|
5
5
|
import { walk } from 'zimmerframe';
|
|
6
6
|
import { print } from 'esrap';
|
|
7
|
+
import { error } from '../../errors.js';
|
|
7
8
|
import {
|
|
8
9
|
ensure_function_metadata,
|
|
9
10
|
in_jsx_child_context,
|
|
@@ -14,7 +15,6 @@ import {
|
|
|
14
15
|
clone_expression_node,
|
|
15
16
|
clone_identifier,
|
|
16
17
|
clone_jsx_name,
|
|
17
|
-
create_compile_error,
|
|
18
18
|
create_generated_identifier,
|
|
19
19
|
create_null_literal,
|
|
20
20
|
flatten_switch_consequent,
|
|
@@ -26,7 +26,11 @@ import {
|
|
|
26
26
|
to_text_expression,
|
|
27
27
|
} from './ast-builders.js';
|
|
28
28
|
import { render_stylesheets as renderStylesheets } from '../stylesheet.js';
|
|
29
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
set_location as setLocation,
|
|
31
|
+
jsx_attribute as build_jsx_attribute,
|
|
32
|
+
jsx_id as build_jsx_id,
|
|
33
|
+
} from '../../utils/builders.js';
|
|
30
34
|
import {
|
|
31
35
|
apply_lazy_transforms,
|
|
32
36
|
collect_lazy_bindings_from_component,
|
|
@@ -45,18 +49,11 @@ import {
|
|
|
45
49
|
import { is_hoist_safe_jsx_node } from '../jsx-hoist.js';
|
|
46
50
|
|
|
47
51
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* needs_merge_refs: boolean,
|
|
54
|
-
* helper_state: { base_name: string, next_id: number, helpers: any[], statics: any[] } | null,
|
|
55
|
-
* available_bindings: Map<string, AST.Identifier>,
|
|
56
|
-
* lazy_next_id: number,
|
|
57
|
-
* current_css_hash: string | null,
|
|
58
|
-
* inside_element_child?: boolean,
|
|
59
|
-
* }} TransformContext
|
|
52
|
+
* Local alias for the shared `JsxTransformContext`. Kept as a typedef so the
|
|
53
|
+
* rest of this file's `@param {TransformContext}` annotations don't all have
|
|
54
|
+
* to spell out the import.
|
|
55
|
+
*
|
|
56
|
+
* @typedef {JsxTransformContext} TransformContext
|
|
60
57
|
*/
|
|
61
58
|
|
|
62
59
|
/**
|
|
@@ -99,7 +96,7 @@ export function createJsxTransform(platform) {
|
|
|
99
96
|
const stylesheets = [];
|
|
100
97
|
|
|
101
98
|
/** @type {TransformContext} */
|
|
102
|
-
const transform_context =
|
|
99
|
+
const transform_context = {
|
|
103
100
|
platform,
|
|
104
101
|
local_statement_component_index: 0,
|
|
105
102
|
needs_error_boundary: false,
|
|
@@ -109,10 +106,14 @@ export function createJsxTransform(platform) {
|
|
|
109
106
|
available_bindings: new Map(),
|
|
110
107
|
lazy_next_id: 0,
|
|
111
108
|
current_css_hash: null,
|
|
109
|
+
filename: filename ?? null,
|
|
110
|
+
loose: !!options?.loose,
|
|
111
|
+
errors: options?.loose ? options?.errors : undefined,
|
|
112
|
+
comments: options?.comments,
|
|
112
113
|
// Platforms can seed their own tracking state (e.g. solid's
|
|
113
114
|
// needs_show / needs_for flags) via `hooks.initialState`.
|
|
114
115
|
...(platform.hooks?.initialState?.() ?? {}),
|
|
115
|
-
}
|
|
116
|
+
};
|
|
116
117
|
|
|
117
118
|
preallocate_lazy_ids(/** @type {any} */ (ast), transform_context);
|
|
118
119
|
|
|
@@ -143,9 +144,12 @@ export function createJsxTransform(platform) {
|
|
|
143
144
|
source,
|
|
144
145
|
);
|
|
145
146
|
} else if (!module_uses_server_directive) {
|
|
146
|
-
|
|
147
|
-
await_expression,
|
|
147
|
+
error(
|
|
148
148
|
`${platform.name} components can only use \`await\` when the module has a top-level "use server" directive.`,
|
|
149
|
+
state.filename,
|
|
150
|
+
await_expression,
|
|
151
|
+
state.errors,
|
|
152
|
+
state.comments,
|
|
149
153
|
);
|
|
150
154
|
}
|
|
151
155
|
|
|
@@ -212,10 +216,10 @@ export function createJsxTransform(platform) {
|
|
|
212
216
|
return /** @type {any} */ (tsx_node_to_jsx_expression(inner, in_jsx_child_context(path)));
|
|
213
217
|
},
|
|
214
218
|
|
|
215
|
-
TsxCompat(node, { next, path }) {
|
|
219
|
+
TsxCompat(node, { next, path, state }) {
|
|
216
220
|
const inner = /** @type {any} */ (next() ?? node);
|
|
217
221
|
return /** @type {any} */ (
|
|
218
|
-
tsx_compat_node_to_jsx_expression(inner,
|
|
222
|
+
tsx_compat_node_to_jsx_expression(inner, state, in_jsx_child_context(path))
|
|
219
223
|
);
|
|
220
224
|
},
|
|
221
225
|
|
|
@@ -1485,7 +1489,22 @@ const TEMPLATE_FRAGMENT_ERROR =
|
|
|
1485
1489
|
function to_jsx_element(node, transform_context, raw_children = node.children || []) {
|
|
1486
1490
|
if (node.type === 'JSXElement') return node;
|
|
1487
1491
|
if (!node.id) {
|
|
1488
|
-
|
|
1492
|
+
error(
|
|
1493
|
+
TEMPLATE_FRAGMENT_ERROR,
|
|
1494
|
+
transform_context.filename,
|
|
1495
|
+
node,
|
|
1496
|
+
transform_context.errors,
|
|
1497
|
+
transform_context.comments,
|
|
1498
|
+
);
|
|
1499
|
+
return set_loc(
|
|
1500
|
+
/** @type {any} */ ({
|
|
1501
|
+
type: 'JSXFragment',
|
|
1502
|
+
openingFragment: { type: 'JSXOpeningFragment' },
|
|
1503
|
+
closingFragment: { type: 'JSXClosingFragment' },
|
|
1504
|
+
children: [],
|
|
1505
|
+
}),
|
|
1506
|
+
node,
|
|
1507
|
+
);
|
|
1489
1508
|
}
|
|
1490
1509
|
if (is_dynamic_element_id(node.id)) {
|
|
1491
1510
|
return dynamic_element_to_jsx_child(node, transform_context);
|
|
@@ -2111,7 +2130,7 @@ function to_jsx_child(node, transform_context) {
|
|
|
2111
2130
|
// JSXExpressionContainer wrapper for bare `{expr}` children.
|
|
2112
2131
|
return tsx_node_to_jsx_expression(node, true);
|
|
2113
2132
|
case 'TsxCompat':
|
|
2114
|
-
return tsx_compat_node_to_jsx_expression(node, transform_context
|
|
2133
|
+
return tsx_compat_node_to_jsx_expression(node, transform_context, true);
|
|
2115
2134
|
case 'Element':
|
|
2116
2135
|
return to_jsx_element(node, transform_context);
|
|
2117
2136
|
case 'Text':
|
|
@@ -2282,9 +2301,12 @@ function find_key_expression_in_body(body_nodes) {
|
|
|
2282
2301
|
*/
|
|
2283
2302
|
function for_of_statement_to_jsx_child(node, transform_context) {
|
|
2284
2303
|
if (node.await) {
|
|
2285
|
-
|
|
2286
|
-
node,
|
|
2304
|
+
error(
|
|
2287
2305
|
`${transform_context.platform.name} TSRX does not support \`for await...of\` in component templates.`,
|
|
2306
|
+
transform_context.filename,
|
|
2307
|
+
node,
|
|
2308
|
+
transform_context.errors,
|
|
2309
|
+
transform_context.comments,
|
|
2288
2310
|
);
|
|
2289
2311
|
}
|
|
2290
2312
|
|
|
@@ -2460,23 +2482,33 @@ function try_statement_to_jsx_child(node, transform_context) {
|
|
|
2460
2482
|
const finalizer = node.finalizer;
|
|
2461
2483
|
|
|
2462
2484
|
if (finalizer) {
|
|
2463
|
-
|
|
2464
|
-
finalizer,
|
|
2485
|
+
error(
|
|
2465
2486
|
`${transform_context.platform.name} TSRX does not support JavaScript \`try/finally\` in component templates. \`finally\` is not part of TSRX control flow; move the try/finally into a function if you need cleanup logic.`,
|
|
2487
|
+
transform_context.filename,
|
|
2488
|
+
finalizer,
|
|
2489
|
+
transform_context.errors,
|
|
2490
|
+
transform_context.comments,
|
|
2466
2491
|
);
|
|
2467
2492
|
}
|
|
2468
2493
|
|
|
2469
2494
|
if (!pending && !handler) {
|
|
2470
|
-
|
|
2471
|
-
node,
|
|
2495
|
+
error(
|
|
2472
2496
|
'Component try statements must have a `pending` or `catch` block.',
|
|
2497
|
+
transform_context.filename,
|
|
2498
|
+
node,
|
|
2499
|
+
transform_context.errors,
|
|
2500
|
+
transform_context.comments,
|
|
2473
2501
|
);
|
|
2502
|
+
return to_jsx_expression_container(create_null_literal());
|
|
2474
2503
|
}
|
|
2475
2504
|
|
|
2476
2505
|
if (pending && transform_context.platform.validation.unsupportedTryPendingMessage) {
|
|
2477
|
-
|
|
2478
|
-
pending,
|
|
2506
|
+
error(
|
|
2479
2507
|
transform_context.platform.validation.unsupportedTryPendingMessage,
|
|
2508
|
+
transform_context.filename,
|
|
2509
|
+
pending,
|
|
2510
|
+
transform_context.errors,
|
|
2511
|
+
transform_context.comments,
|
|
2480
2512
|
);
|
|
2481
2513
|
}
|
|
2482
2514
|
|
|
@@ -2484,16 +2516,22 @@ function try_statement_to_jsx_child(node, transform_context) {
|
|
|
2484
2516
|
if (pending) {
|
|
2485
2517
|
const try_body = node.block.body || [];
|
|
2486
2518
|
if (!try_body.some(is_jsx_child)) {
|
|
2487
|
-
|
|
2488
|
-
node.block,
|
|
2519
|
+
error(
|
|
2489
2520
|
'Component try statements must contain a template in their main body. Move the try statement into a function if it does not render anything.',
|
|
2521
|
+
transform_context.filename,
|
|
2522
|
+
node.block,
|
|
2523
|
+
transform_context.errors,
|
|
2524
|
+
transform_context.comments,
|
|
2490
2525
|
);
|
|
2491
2526
|
}
|
|
2492
2527
|
const pending_body = pending.body || [];
|
|
2493
2528
|
if (!pending_body.some(is_jsx_child)) {
|
|
2494
|
-
|
|
2495
|
-
pending,
|
|
2529
|
+
error(
|
|
2496
2530
|
'Component try statements must contain a template in their "pending" body. Rendering a pending fallback is required to have a template.',
|
|
2531
|
+
transform_context.filename,
|
|
2532
|
+
pending,
|
|
2533
|
+
transform_context.errors,
|
|
2534
|
+
transform_context.comments,
|
|
2497
2535
|
);
|
|
2498
2536
|
}
|
|
2499
2537
|
}
|
|
@@ -2963,7 +3001,7 @@ function to_jsx_expression_container(expression, source_node = expression) {
|
|
|
2963
3001
|
* @returns {any[]}
|
|
2964
3002
|
*/
|
|
2965
3003
|
function transform_element_attributes_dispatch(attrs, transform_context, element) {
|
|
2966
|
-
validate_at_most_one_ref_attribute(attrs);
|
|
3004
|
+
validate_at_most_one_ref_attribute(attrs, transform_context);
|
|
2967
3005
|
const preprocess = transform_context.platform.hooks?.preprocessElementAttributes;
|
|
2968
3006
|
if (preprocess) {
|
|
2969
3007
|
attrs = preprocess(attrs, transform_context, element);
|
|
@@ -2987,9 +3025,11 @@ function transform_element_attributes_dispatch(attrs, transform_context, element
|
|
|
2987
3025
|
* the original `JSXAttribute`/`JSXIdentifier` shape, so we accept both.
|
|
2988
3026
|
*
|
|
2989
3027
|
* @param {any[]} raw_attrs
|
|
3028
|
+
* @param {TransformContext} [transform_context]
|
|
2990
3029
|
*/
|
|
2991
|
-
export function validate_at_most_one_ref_attribute(raw_attrs) {
|
|
2992
|
-
|
|
3030
|
+
export function validate_at_most_one_ref_attribute(raw_attrs, transform_context) {
|
|
3031
|
+
/** @type {any[]} */
|
|
3032
|
+
const refs = [];
|
|
2993
3033
|
for (const attr of raw_attrs) {
|
|
2994
3034
|
if (!attr) continue;
|
|
2995
3035
|
const is_ref_attr =
|
|
@@ -3002,14 +3042,25 @@ export function validate_at_most_one_ref_attribute(raw_attrs) {
|
|
|
3002
3042
|
attr.name.type === 'JSXIdentifier' &&
|
|
3003
3043
|
attr.name.name === 'ref');
|
|
3004
3044
|
if (!is_ref_attr) continue;
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3045
|
+
refs.push(attr.name);
|
|
3046
|
+
}
|
|
3047
|
+
if (refs.length < 2) {
|
|
3048
|
+
return;
|
|
3049
|
+
}
|
|
3050
|
+
for (let i = 0; i < refs.length; i++) {
|
|
3051
|
+
const node = refs[i];
|
|
3052
|
+
if (!transform_context?.loose && i === 0) {
|
|
3053
|
+
// in the non-loose mode, only throw on the second duplicate
|
|
3054
|
+
continue;
|
|
3011
3055
|
}
|
|
3012
|
-
|
|
3056
|
+
error(
|
|
3057
|
+
'Element has multiple `ref={...}` attributes; an element may have at most one. ' +
|
|
3058
|
+
"Use Ripple's `{ref expr}` keyword form to combine multiple refs on one element.",
|
|
3059
|
+
transform_context?.filename ?? null,
|
|
3060
|
+
node,
|
|
3061
|
+
transform_context?.errors,
|
|
3062
|
+
transform_context?.comments,
|
|
3063
|
+
);
|
|
3013
3064
|
}
|
|
3014
3065
|
}
|
|
3015
3066
|
|
|
@@ -3040,18 +3091,34 @@ export function merge_duplicate_refs(jsx_attrs, transform_context) {
|
|
|
3040
3091
|
if (!strategy) return jsx_attrs;
|
|
3041
3092
|
|
|
3042
3093
|
let count = 0;
|
|
3094
|
+
let tsx_form_count = 0;
|
|
3043
3095
|
for (const attr of jsx_attrs) {
|
|
3044
|
-
if (is_jsx_ref_attribute(attr))
|
|
3096
|
+
if (!is_jsx_ref_attribute(attr)) continue;
|
|
3097
|
+
count += 1;
|
|
3098
|
+
if (!attr.metadata?.from_ref_keyword) tsx_form_count += 1;
|
|
3045
3099
|
}
|
|
3046
3100
|
if (count <= 1) return jsx_attrs;
|
|
3101
|
+
// Two or more genuine `ref={...}` (TSX-form) attributes are already a
|
|
3102
|
+
// validator-flagged compile error and TypeScript flags them as duplicate
|
|
3103
|
+
// JSX props. Leave them in place so the user gets all three signals
|
|
3104
|
+
// instead of silently composing them into `__mergeRefs(...)`.
|
|
3105
|
+
if (tsx_form_count >= 2) return jsx_attrs;
|
|
3047
3106
|
|
|
3048
3107
|
/** @type {any[]} */
|
|
3049
3108
|
const ref_exprs = [];
|
|
3050
3109
|
/** @type {any[]} */
|
|
3051
3110
|
const result = [];
|
|
3111
|
+
/** @type {any} */
|
|
3112
|
+
let source_attr = null;
|
|
3052
3113
|
for (const attr of jsx_attrs) {
|
|
3053
3114
|
if (is_jsx_ref_attribute(attr)) {
|
|
3054
3115
|
ref_exprs.push(attr.value.expression);
|
|
3116
|
+
// Inherit loc from the (at most one) `ref={expr}`-form attribute so
|
|
3117
|
+
// the kept `ref` keyword in the generated `ref={__mergeRefs(...)}`
|
|
3118
|
+
// retains a source mapping back to its original `ref=` keyword.
|
|
3119
|
+
if (!source_attr && !attr.metadata?.from_ref_keyword) {
|
|
3120
|
+
source_attr = attr;
|
|
3121
|
+
}
|
|
3055
3122
|
} else {
|
|
3056
3123
|
result.push(attr);
|
|
3057
3124
|
}
|
|
@@ -3080,23 +3147,23 @@ export function merge_duplicate_refs(jsx_attrs, transform_context) {
|
|
|
3080
3147
|
transform_context.needs_merge_refs = true;
|
|
3081
3148
|
}
|
|
3082
3149
|
|
|
3083
|
-
//
|
|
3084
|
-
//
|
|
3085
|
-
// the
|
|
3086
|
-
//
|
|
3087
|
-
|
|
3150
|
+
// Inherit start/end/loc from the (at most one) `ref={expr}`-form attribute
|
|
3151
|
+
// so segments.js emits a normal source-to-generated mapping for the
|
|
3152
|
+
// merged attribute and its name. Without this the kept `ref` keyword in
|
|
3153
|
+
// `ref={__mergeRefs(...)}` has no source mapping back to the user's `ref=`
|
|
3154
|
+
// keyword.
|
|
3155
|
+
const merged_name = build_jsx_id('ref', source_attr?.name);
|
|
3156
|
+
const merged_attr = build_jsx_attribute(
|
|
3157
|
+
merged_name,
|
|
3088
3158
|
/** @type {any} */ ({
|
|
3089
|
-
type: '
|
|
3090
|
-
|
|
3091
|
-
value: {
|
|
3092
|
-
type: 'JSXExpressionContainer',
|
|
3093
|
-
expression: merged_value,
|
|
3094
|
-
metadata: { path: [] },
|
|
3095
|
-
},
|
|
3096
|
-
shorthand: false,
|
|
3159
|
+
type: 'JSXExpressionContainer',
|
|
3160
|
+
expression: merged_value,
|
|
3097
3161
|
metadata: { path: [] },
|
|
3098
3162
|
}),
|
|
3163
|
+
false,
|
|
3164
|
+
source_attr,
|
|
3099
3165
|
);
|
|
3166
|
+
result.push(merged_attr);
|
|
3100
3167
|
|
|
3101
3168
|
return result;
|
|
3102
3169
|
}
|
|
@@ -3150,13 +3217,16 @@ export function to_jsx_attribute(attr, transform_context) {
|
|
|
3150
3217
|
// so the source-to-generated mapping is imprecise — but pointing
|
|
3151
3218
|
// editors at the `{ref expr}` span is still useful for hover/jump,
|
|
3152
3219
|
// matching how shorthand `{name}` → `name={name}` carries loc.
|
|
3220
|
+
// `from_ref_keyword` lets `merge_duplicate_refs` tell this form apart
|
|
3221
|
+
// from genuine `ref={...}` attributes without inferring it from
|
|
3222
|
+
// whether `name.loc` happens to be present.
|
|
3153
3223
|
return set_loc(
|
|
3154
3224
|
/** @type {any} */ ({
|
|
3155
3225
|
type: 'JSXAttribute',
|
|
3156
3226
|
name: { type: 'JSXIdentifier', name: 'ref', metadata: { path: [] } },
|
|
3157
3227
|
value: to_jsx_expression_container(attr.argument),
|
|
3158
3228
|
shorthand: false,
|
|
3159
|
-
metadata: { path: [] },
|
|
3229
|
+
metadata: { path: [], from_ref_keyword: true },
|
|
3160
3230
|
}),
|
|
3161
3231
|
attr,
|
|
3162
3232
|
);
|
|
@@ -3189,13 +3259,7 @@ export function to_jsx_attribute(attr, transform_context) {
|
|
|
3189
3259
|
}
|
|
3190
3260
|
}
|
|
3191
3261
|
|
|
3192
|
-
const jsx_attribute =
|
|
3193
|
-
type: 'JSXAttribute',
|
|
3194
|
-
name,
|
|
3195
|
-
value: value || null,
|
|
3196
|
-
shorthand: false,
|
|
3197
|
-
metadata: { path: [] },
|
|
3198
|
-
});
|
|
3262
|
+
const jsx_attribute = build_jsx_attribute(name, value || null, attr.shorthand === true);
|
|
3199
3263
|
|
|
3200
3264
|
if (value_has_unmappable_jsx_loc(value)) {
|
|
3201
3265
|
/** @type {any} */ (jsx_attribute.metadata).has_unmappable_value = true;
|
|
@@ -3360,16 +3424,20 @@ function build_return_expression(render_nodes) {
|
|
|
3360
3424
|
|
|
3361
3425
|
/**
|
|
3362
3426
|
* @param {any} node
|
|
3363
|
-
* @param {
|
|
3427
|
+
* @param {TransformContext} transform_context
|
|
3364
3428
|
* @param {boolean} [in_jsx_child]
|
|
3365
3429
|
* @returns {any}
|
|
3366
3430
|
*/
|
|
3367
|
-
function tsx_compat_node_to_jsx_expression(node,
|
|
3431
|
+
function tsx_compat_node_to_jsx_expression(node, transform_context, in_jsx_child = false) {
|
|
3432
|
+
const platform = transform_context.platform;
|
|
3368
3433
|
if (!platform.jsx.acceptedTsxKinds.includes(node.kind)) {
|
|
3369
3434
|
const accepted = platform.jsx.acceptedTsxKinds.map((k) => `<tsx:${k}>`).join(', ');
|
|
3370
|
-
|
|
3371
|
-
node,
|
|
3435
|
+
error(
|
|
3372
3436
|
`${platform.name} TSRX does not support <tsx:${node.kind}> blocks. Use <tsx> or one of: ${accepted}.`,
|
|
3437
|
+
transform_context.filename,
|
|
3438
|
+
node,
|
|
3439
|
+
transform_context.errors,
|
|
3440
|
+
transform_context.comments,
|
|
3373
3441
|
);
|
|
3374
3442
|
}
|
|
3375
3443
|
|
package/types/index.d.ts
CHANGED
|
@@ -8,13 +8,21 @@ import type { RequireAllOrNone } from '../src/helpers.js';
|
|
|
8
8
|
import type {
|
|
9
9
|
JsxPlatform,
|
|
10
10
|
JsxPlatformHooks,
|
|
11
|
+
JsxTransformContext,
|
|
11
12
|
JsxTransformOptions,
|
|
12
13
|
JsxTransformResult,
|
|
13
14
|
componentToFunctionDeclaration,
|
|
14
15
|
createJsxTransform,
|
|
15
16
|
} from './jsx-platform';
|
|
16
17
|
|
|
17
|
-
export type {
|
|
18
|
+
export type {
|
|
19
|
+
Parse,
|
|
20
|
+
JsxPlatform,
|
|
21
|
+
JsxPlatformHooks,
|
|
22
|
+
JsxTransformContext,
|
|
23
|
+
JsxTransformOptions,
|
|
24
|
+
JsxTransformResult,
|
|
25
|
+
};
|
|
18
26
|
export { createJsxTransform, componentToFunctionDeclaration };
|
|
19
27
|
|
|
20
28
|
/**
|
package/types/jsx-platform.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type * as AST from 'estree';
|
|
2
2
|
import type { RawSourceMap } from 'source-map';
|
|
3
|
+
import type { CompileError } from './index';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Result returned by a JSX platform transform (React, Preact, Solid).
|
|
@@ -16,6 +17,38 @@ export interface JsxTransformResult {
|
|
|
16
17
|
css: { code: string; hash: string } | null;
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Shared base for the per-call transform context that the JSX factory passes
|
|
22
|
+
* into every visitor and helper. Platform-specific transforms (e.g. Solid)
|
|
23
|
+
* extend this with their own `needs_*` flags via `hooks.initialState`; helpers
|
|
24
|
+
* defined in `@tsrx/core` only ever rely on these base fields.
|
|
25
|
+
*/
|
|
26
|
+
export interface JsxTransformContext {
|
|
27
|
+
platform: JsxPlatform;
|
|
28
|
+
local_statement_component_index: number;
|
|
29
|
+
needs_error_boundary: boolean;
|
|
30
|
+
needs_suspense: boolean;
|
|
31
|
+
needs_merge_refs: boolean;
|
|
32
|
+
helper_state: {
|
|
33
|
+
base_name: string;
|
|
34
|
+
next_id: number;
|
|
35
|
+
helpers: any[];
|
|
36
|
+
statics: any[];
|
|
37
|
+
} | null;
|
|
38
|
+
available_bindings: Map<string, AST.Identifier>;
|
|
39
|
+
lazy_next_id: number;
|
|
40
|
+
current_css_hash: string | null;
|
|
41
|
+
inside_element_child?: boolean;
|
|
42
|
+
/** Source filename for diagnostics; null when the caller did not supply one. */
|
|
43
|
+
filename: string | null;
|
|
44
|
+
/** True when recoverable errors should be collected onto `errors` instead of thrown. */
|
|
45
|
+
loose: boolean;
|
|
46
|
+
/** Collected non-fatal errors. Undefined when `loose` is false. */
|
|
47
|
+
errors: CompileError[] | undefined;
|
|
48
|
+
/** Module-level comments used to honor `@tsrx-ignore` / `@tsrx-expect-error`. */
|
|
49
|
+
comments: AST.CommentWithLocation[] | undefined;
|
|
50
|
+
}
|
|
51
|
+
|
|
19
52
|
/**
|
|
20
53
|
* Optional per-call compile options passed to a created JSX transform.
|
|
21
54
|
*/
|
|
@@ -26,6 +59,22 @@ export interface JsxTransformOptions {
|
|
|
26
59
|
* host pick `preact/compat` vs. another compat entry point.
|
|
27
60
|
*/
|
|
28
61
|
suspenseSource?: string;
|
|
62
|
+
/**
|
|
63
|
+
* When true, recoverable transform errors are pushed onto `errors` instead
|
|
64
|
+
* of thrown so editor tooling can surface them as diagnostics. Errors that
|
|
65
|
+
* leave the transform in an unrecoverable state are still thrown.
|
|
66
|
+
*/
|
|
67
|
+
loose?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Collected non-fatal errors. The transform appends to this array when
|
|
70
|
+
* `loose` is true; callers read it after the transform returns.
|
|
71
|
+
*/
|
|
72
|
+
errors?: CompileError[];
|
|
73
|
+
/**
|
|
74
|
+
* Module-level comments used to suppress diagnostics via `@tsrx-ignore` /
|
|
75
|
+
* `@tsrx-expect-error` line comments.
|
|
76
|
+
*/
|
|
77
|
+
comments?: AST.CommentWithLocation[];
|
|
29
78
|
}
|
|
30
79
|
|
|
31
80
|
/**
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type MergeableRefCallback<T> = (node: T | null) => void | (() => void);
|
|
2
|
+
export type MergeableRefObject<T> = { current: T | null };
|
|
3
|
+
export type MergeableVueRef<T> = { value: T | null };
|
|
4
|
+
|
|
5
|
+
export type MergeableRef<T> =
|
|
6
|
+
| MergeableRefCallback<T>
|
|
7
|
+
| MergeableRefObject<T>
|
|
8
|
+
| MergeableVueRef<T>
|
|
9
|
+
| null
|
|
10
|
+
| undefined;
|
|
11
|
+
|
|
12
|
+
export function mergeRefs<T = any>(...refs: Array<MergeableRef<T>>): (node: T | null) => () => void;
|