@tsrx/react 0.0.3 → 0.0.4
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 +3 -53
- package/src/transform.js +62 -674
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @import * as AST from 'estree' */
|
|
2
|
-
/** @import {
|
|
2
|
+
/** @import { ParseOptions } from '@tsrx/core/types' */
|
|
3
3
|
|
|
4
|
-
import { createVolarMappingsResult, parseModule } from '@tsrx/core';
|
|
4
|
+
import { createVolarMappingsResult, dedupeMappings, parseModule } from '@tsrx/core';
|
|
5
5
|
import { transform } from './transform.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -51,56 +51,6 @@ export function compile_to_volar_mappings(source, filename, options) {
|
|
|
51
51
|
|
|
52
52
|
return {
|
|
53
53
|
...result,
|
|
54
|
-
mappings:
|
|
54
|
+
mappings: dedupeMappings(result.mappings),
|
|
55
55
|
};
|
|
56
56
|
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Remove byte-for-byte duplicate mappings. React helper extraction can emit
|
|
60
|
-
* identical mapping entries for the same source and generated span, which
|
|
61
|
-
* causes Volar to merge duplicate hover/navigation results.
|
|
62
|
-
*
|
|
63
|
-
* @param {CodeMapping[]} mappings
|
|
64
|
-
* @returns {CodeMapping[]}
|
|
65
|
-
*/
|
|
66
|
-
function dedupe_mappings(mappings) {
|
|
67
|
-
const deduped = [];
|
|
68
|
-
const seen = new Set();
|
|
69
|
-
|
|
70
|
-
for (const mapping of mappings) {
|
|
71
|
-
const key = JSON.stringify(serialize_mapping_value(mapping));
|
|
72
|
-
|
|
73
|
-
if (seen.has(key)) {
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
seen.add(key);
|
|
78
|
-
deduped.push(mapping);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return deduped;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* @param {unknown} value
|
|
86
|
-
* @returns {unknown}
|
|
87
|
-
*/
|
|
88
|
-
function serialize_mapping_value(value) {
|
|
89
|
-
if (typeof value === 'function') {
|
|
90
|
-
return value.toString();
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (Array.isArray(value)) {
|
|
94
|
-
return value.map(serialize_mapping_value);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (value && typeof value === 'object') {
|
|
98
|
-
return Object.fromEntries(
|
|
99
|
-
Object.entries(value)
|
|
100
|
-
.sort(([left], [right]) => left.localeCompare(right))
|
|
101
|
-
.map(([key, nested_value]) => [key, serialize_mapping_value(nested_value)]),
|
|
102
|
-
);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return value;
|
|
106
|
-
}
|
package/src/transform.js
CHANGED
|
@@ -4,7 +4,16 @@
|
|
|
4
4
|
import { walk } from 'zimmerframe';
|
|
5
5
|
import { print } from 'esrap';
|
|
6
6
|
import tsx from 'esrap/languages/tsx';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
renderStylesheets,
|
|
9
|
+
setLocation,
|
|
10
|
+
applyLazyTransforms as apply_lazy_transforms,
|
|
11
|
+
collectLazyBindingsFromComponent as collect_lazy_bindings_from_component,
|
|
12
|
+
preallocateLazyIds as preallocate_lazy_ids,
|
|
13
|
+
replaceLazyParams as replace_lazy_params,
|
|
14
|
+
prepareStylesheetForRender as prepare_stylesheet_for_render,
|
|
15
|
+
annotateComponentWithHash as annotate_component_with_hash,
|
|
16
|
+
} from '@tsrx/core';
|
|
8
17
|
|
|
9
18
|
/**
|
|
10
19
|
* @typedef {{
|
|
@@ -14,6 +23,7 @@ import { renderStylesheets, setLocation } from '@tsrx/core';
|
|
|
14
23
|
* helper_state: { base_name: string, next_id: number, helpers: AST.FunctionDeclaration[], statics: any[] } | null,
|
|
15
24
|
* available_bindings: Map<string, AST.Identifier>,
|
|
16
25
|
* lazy_next_id: number,
|
|
26
|
+
* current_css_hash: string | null,
|
|
17
27
|
* }} TransformContext
|
|
18
28
|
*/
|
|
19
29
|
|
|
@@ -49,8 +59,11 @@ export function transform(ast, source, filename) {
|
|
|
49
59
|
helper_state: null,
|
|
50
60
|
available_bindings: new Map(),
|
|
51
61
|
lazy_next_id: 0,
|
|
62
|
+
current_css_hash: null,
|
|
52
63
|
};
|
|
53
64
|
|
|
65
|
+
preallocate_lazy_ids(/** @type {any} */ (ast), transform_context);
|
|
66
|
+
|
|
54
67
|
walk(/** @type {any} */ (ast), transform_context, {
|
|
55
68
|
Component(node, { next, state }) {
|
|
56
69
|
const as_any = /** @type {any} */ (node);
|
|
@@ -74,7 +87,9 @@ export function transform(ast, source, filename) {
|
|
|
74
87
|
const helper_state = create_helper_state(as_any.id?.name || 'Component');
|
|
75
88
|
const saved_helper_state = state.helper_state;
|
|
76
89
|
const saved_bindings = state.available_bindings;
|
|
90
|
+
const saved_css_hash = state.current_css_hash;
|
|
77
91
|
state.helper_state = helper_state;
|
|
92
|
+
state.current_css_hash = as_any.css ? as_any.css.hash : null;
|
|
78
93
|
|
|
79
94
|
// Pre-collect component body bindings (params + top-level statements)
|
|
80
95
|
// so that Element children processed during the bottom-up walk can see
|
|
@@ -97,6 +112,7 @@ export function transform(ast, source, filename) {
|
|
|
97
112
|
// Restore context
|
|
98
113
|
state.helper_state = saved_helper_state;
|
|
99
114
|
state.available_bindings = saved_bindings;
|
|
115
|
+
state.current_css_hash = saved_css_hash;
|
|
100
116
|
|
|
101
117
|
return /** @type {any} */ (component_to_function_declaration(inner, state, helper_state));
|
|
102
118
|
},
|
|
@@ -127,12 +143,30 @@ export function transform(ast, source, filename) {
|
|
|
127
143
|
const inner = /** @type {any} */ (next() ?? node);
|
|
128
144
|
return /** @type {any} */ (to_jsx_expression_container(inner.expression, inner));
|
|
129
145
|
},
|
|
146
|
+
|
|
147
|
+
MemberExpression(node, { next, state }) {
|
|
148
|
+
const as_any = /** @type {any} */ (node);
|
|
149
|
+
if (as_any.object && as_any.object.type === 'StyleIdentifier' && state.current_css_hash) {
|
|
150
|
+
const class_name = as_any.computed ? as_any.property.value : as_any.property.name;
|
|
151
|
+
const value = `${state.current_css_hash} ${class_name}`;
|
|
152
|
+
return /** @type {any} */ ({ type: 'Literal', value, raw: JSON.stringify(value) });
|
|
153
|
+
}
|
|
154
|
+
return next();
|
|
155
|
+
},
|
|
130
156
|
});
|
|
131
157
|
|
|
132
158
|
const expanded = expand_component_helpers(/** @type {AST.Program} */ (transformed));
|
|
133
159
|
inject_try_imports(expanded, transform_context);
|
|
134
160
|
|
|
135
|
-
|
|
161
|
+
// Apply lazy destructuring transforms to module-level code (top-level function
|
|
162
|
+
// declarations, arrow functions, etc.). Component bodies have already been
|
|
163
|
+
// transformed inside component_to_function_declaration; this catches plain
|
|
164
|
+
// functions outside components and any lazy patterns in module scope.
|
|
165
|
+
const final_program = /** @type {any} */ (
|
|
166
|
+
apply_lazy_transforms(/** @type {any} */ (expanded), new Map())
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
const result = print(/** @type {any} */ (final_program), tsx(), {
|
|
136
170
|
sourceMapSource: filename,
|
|
137
171
|
sourceMapContent: source,
|
|
138
172
|
});
|
|
@@ -147,508 +181,7 @@ export function transform(ast, source, filename) {
|
|
|
147
181
|
}
|
|
148
182
|
: null;
|
|
149
183
|
|
|
150
|
-
return { ast:
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// --- Lazy destructuring support ---
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Generate a unique lazy identifier name for a lazy destructuring pattern.
|
|
157
|
-
* @param {TransformContext} transform_context
|
|
158
|
-
* @returns {string}
|
|
159
|
-
*/
|
|
160
|
-
function generate_lazy_id(transform_context) {
|
|
161
|
-
return `__lazy${transform_context.lazy_next_id++}`;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Collect lazy bindings from a destructuring pattern.
|
|
166
|
-
* For `&{name, age}`, maps `name` → `source.name`, `age` → `source.age`.
|
|
167
|
-
* For `&[a, b]`, maps `a` → `source[0]`, `b` → `source[1]`.
|
|
168
|
-
* Handles nested AssignmentPattern (default values) and RestElement.
|
|
169
|
-
*
|
|
170
|
-
* @param {any} pattern - The ObjectPattern or ArrayPattern with lazy: true
|
|
171
|
-
* @param {string} source_name - The generated identifier name for the source
|
|
172
|
-
* @param {Map<string, LazyBinding>} lazy_bindings - Map to populate
|
|
173
|
-
*/
|
|
174
|
-
function collect_lazy_bindings(pattern, source_name, lazy_bindings) {
|
|
175
|
-
if (pattern.type === 'ObjectPattern') {
|
|
176
|
-
for (const prop of pattern.properties || []) {
|
|
177
|
-
if (prop.type === 'RestElement') {
|
|
178
|
-
// Rest element in object pattern — skip for now (complex to transform)
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
181
|
-
const value = prop.value;
|
|
182
|
-
const actual = value.type === 'AssignmentPattern' ? value.left : value;
|
|
183
|
-
if (actual.type === 'Identifier') {
|
|
184
|
-
const key = prop.key;
|
|
185
|
-
const computed = prop.computed || key.type !== 'Identifier';
|
|
186
|
-
lazy_bindings.set(actual.name, {
|
|
187
|
-
source_name,
|
|
188
|
-
read: () => ({
|
|
189
|
-
type: 'MemberExpression',
|
|
190
|
-
object: create_generated_identifier(source_name),
|
|
191
|
-
property: computed
|
|
192
|
-
? { ...key }
|
|
193
|
-
: { type: 'Identifier', name: key.name, metadata: { path: [] } },
|
|
194
|
-
computed,
|
|
195
|
-
optional: false,
|
|
196
|
-
metadata: { path: [] },
|
|
197
|
-
}),
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
} else if (pattern.type === 'ArrayPattern') {
|
|
202
|
-
for (let i = 0; i < (pattern.elements || []).length; i++) {
|
|
203
|
-
const element = pattern.elements[i];
|
|
204
|
-
if (!element) continue;
|
|
205
|
-
if (element.type === 'RestElement') {
|
|
206
|
-
// Rest element in array pattern — skip for now
|
|
207
|
-
continue;
|
|
208
|
-
}
|
|
209
|
-
const actual = element.type === 'AssignmentPattern' ? element.left : element;
|
|
210
|
-
if (actual.type === 'Identifier') {
|
|
211
|
-
const index = i;
|
|
212
|
-
lazy_bindings.set(actual.name, {
|
|
213
|
-
source_name,
|
|
214
|
-
read: () => ({
|
|
215
|
-
type: 'MemberExpression',
|
|
216
|
-
object: create_generated_identifier(source_name),
|
|
217
|
-
property: { type: 'Literal', value: index, raw: String(index), metadata: { path: [] } },
|
|
218
|
-
computed: true,
|
|
219
|
-
optional: false,
|
|
220
|
-
metadata: { path: [] },
|
|
221
|
-
}),
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Collect lazy bindings from component params and body variable declarations
|
|
230
|
-
* WITHOUT modifying any AST nodes. Returns a map of binding name → accessor info.
|
|
231
|
-
* Stores the generated identifier name on the pattern's metadata for later replacement.
|
|
232
|
-
*
|
|
233
|
-
* @param {any[]} params - Component params (metadata annotated, not structurally mutated)
|
|
234
|
-
* @param {any[]} body - Component body (metadata annotated, not structurally mutated)
|
|
235
|
-
* @param {TransformContext} transform_context
|
|
236
|
-
* @returns {Map<string, LazyBinding>}
|
|
237
|
-
*/
|
|
238
|
-
function collect_lazy_bindings_from_component(params, body, transform_context) {
|
|
239
|
-
/** @type {Map<string, LazyBinding>} */
|
|
240
|
-
const lazy_bindings = new Map();
|
|
241
|
-
|
|
242
|
-
// Collect from lazy params
|
|
243
|
-
for (const param of params) {
|
|
244
|
-
const pattern = param.type === 'AssignmentPattern' ? param.left : param;
|
|
245
|
-
|
|
246
|
-
if ((pattern.type === 'ObjectPattern' || pattern.type === 'ArrayPattern') && pattern.lazy) {
|
|
247
|
-
const lazy_name = generate_lazy_id(transform_context);
|
|
248
|
-
collect_lazy_bindings(pattern, lazy_name, lazy_bindings);
|
|
249
|
-
pattern.metadata = { ...pattern.metadata, lazy_id: lazy_name };
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Collect from lazy variable declarations in body
|
|
254
|
-
for (const statement of body) {
|
|
255
|
-
if (statement.type !== 'VariableDeclaration') continue;
|
|
256
|
-
|
|
257
|
-
for (const declarator of statement.declarations || []) {
|
|
258
|
-
const pattern = declarator.id;
|
|
259
|
-
if ((pattern.type === 'ObjectPattern' || pattern.type === 'ArrayPattern') && pattern.lazy) {
|
|
260
|
-
const lazy_name = generate_lazy_id(transform_context);
|
|
261
|
-
collect_lazy_bindings(pattern, lazy_name, lazy_bindings);
|
|
262
|
-
pattern.metadata = { ...pattern.metadata, lazy_id: lazy_name };
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
return lazy_bindings;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Walk an AST node tree and replace identifier references that match lazy bindings
|
|
272
|
-
* with their corresponding member expressions (e.g., `name` → `__lazy0.name`).
|
|
273
|
-
* Also handles AssignmentExpression and UpdateExpression targets.
|
|
274
|
-
*
|
|
275
|
-
* @param {any} node - The AST node to walk
|
|
276
|
-
* @param {Map<string, LazyBinding>} lazy_bindings - Map of lazy binding names
|
|
277
|
-
* @returns {any}
|
|
278
|
-
*/
|
|
279
|
-
function apply_lazy_transforms(node, lazy_bindings) {
|
|
280
|
-
if (!node || typeof node !== 'object') return node;
|
|
281
|
-
if (Array.isArray(node)) return node.map((child) => apply_lazy_transforms(child, lazy_bindings));
|
|
282
|
-
|
|
283
|
-
// Don't recurse into nested function declarations (helper components have their own scope)
|
|
284
|
-
if (
|
|
285
|
-
node.type === 'FunctionDeclaration' ||
|
|
286
|
-
node.type === 'FunctionExpression' ||
|
|
287
|
-
node.type === 'ArrowFunctionExpression'
|
|
288
|
-
) {
|
|
289
|
-
// Transform default parameter values (e.g. (step = count) => ...) with the
|
|
290
|
-
// outer lazy_bindings, since defaults are evaluated in the outer scope.
|
|
291
|
-
let params_changed = false;
|
|
292
|
-
const new_params = (node.params || []).map((/** @type {any} */ param) => {
|
|
293
|
-
const transformed = transform_param_defaults(param, lazy_bindings);
|
|
294
|
-
if (transformed !== param) params_changed = true;
|
|
295
|
-
return transformed;
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
// Check if any params shadow a lazy binding — if so, exclude those names
|
|
299
|
-
/** @type {Set<string>} */
|
|
300
|
-
const shadowed = new Set();
|
|
301
|
-
for (const param of node.params || []) {
|
|
302
|
-
collect_shadowed_names(param, lazy_bindings, shadowed);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
const inner_bindings =
|
|
306
|
-
shadowed.size > 0 ? remove_shadowed(lazy_bindings, shadowed) : lazy_bindings;
|
|
307
|
-
if (inner_bindings.size === 0 && !params_changed) return node;
|
|
308
|
-
|
|
309
|
-
const new_body =
|
|
310
|
-
inner_bindings.size > 0 ? apply_lazy_transforms(node.body, inner_bindings) : node.body;
|
|
311
|
-
|
|
312
|
-
if (new_body !== node.body || params_changed) {
|
|
313
|
-
return {
|
|
314
|
-
...node,
|
|
315
|
-
params: params_changed ? new_params : node.params,
|
|
316
|
-
body: new_body,
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
return node;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// Handle block-scoped variable shadowing (const/let/var that shadows a lazy name)
|
|
323
|
-
if (node.type === 'BlockStatement' || node.type === 'Program') {
|
|
324
|
-
const block_bindings = collect_block_shadowed_names(node.body, lazy_bindings);
|
|
325
|
-
const effective_bindings =
|
|
326
|
-
block_bindings.size > 0 ? remove_shadowed(lazy_bindings, block_bindings) : lazy_bindings;
|
|
327
|
-
if (effective_bindings.size === 0 && block_bindings.size > 0) return node;
|
|
328
|
-
|
|
329
|
-
let changed = false;
|
|
330
|
-
const new_body = node.body.map((/** @type {any} */ stmt) => {
|
|
331
|
-
const transformed = apply_lazy_transforms(stmt, effective_bindings);
|
|
332
|
-
if (transformed !== stmt) changed = true;
|
|
333
|
-
return transformed;
|
|
334
|
-
});
|
|
335
|
-
return changed ? { ...node, body: new_body } : node;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// Handle catch clause parameter shadowing
|
|
339
|
-
if (node.type === 'CatchClause') {
|
|
340
|
-
/** @type {Set<string>} */
|
|
341
|
-
const shadowed = new Set();
|
|
342
|
-
if (node.param) collect_shadowed_names(node.param, lazy_bindings, shadowed);
|
|
343
|
-
const effective_bindings =
|
|
344
|
-
shadowed.size > 0 ? remove_shadowed(lazy_bindings, shadowed) : lazy_bindings;
|
|
345
|
-
const new_body = apply_lazy_transforms(node.body, effective_bindings);
|
|
346
|
-
if (new_body !== node.body) return { ...node, body: new_body };
|
|
347
|
-
return node;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// Handle for-loop variable shadowing
|
|
351
|
-
if (node.type === 'ForStatement') {
|
|
352
|
-
/** @type {Set<string>} */
|
|
353
|
-
const shadowed = new Set();
|
|
354
|
-
if (node.init?.type === 'VariableDeclaration') {
|
|
355
|
-
for (const decl of node.init.declarations) {
|
|
356
|
-
if (decl.id) collect_shadowed_names(decl.id, lazy_bindings, shadowed);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
const effective_bindings =
|
|
360
|
-
shadowed.size > 0 ? remove_shadowed(lazy_bindings, shadowed) : lazy_bindings;
|
|
361
|
-
let changed = false;
|
|
362
|
-
const new_init = apply_lazy_transforms(node.init, effective_bindings);
|
|
363
|
-
if (new_init !== node.init) changed = true;
|
|
364
|
-
const new_test = apply_lazy_transforms(node.test, effective_bindings);
|
|
365
|
-
if (new_test !== node.test) changed = true;
|
|
366
|
-
const new_update = apply_lazy_transforms(node.update, effective_bindings);
|
|
367
|
-
if (new_update !== node.update) changed = true;
|
|
368
|
-
const new_body = apply_lazy_transforms(node.body, effective_bindings);
|
|
369
|
-
if (new_body !== node.body) changed = true;
|
|
370
|
-
return changed
|
|
371
|
-
? { ...node, init: new_init, test: new_test, update: new_update, body: new_body }
|
|
372
|
-
: node;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
if (node.type === 'ForOfStatement' || node.type === 'ForInStatement') {
|
|
376
|
-
/** @type {Set<string>} */
|
|
377
|
-
const shadowed = new Set();
|
|
378
|
-
if (node.left?.type === 'VariableDeclaration') {
|
|
379
|
-
for (const decl of node.left.declarations) {
|
|
380
|
-
if (decl.id) collect_shadowed_names(decl.id, lazy_bindings, shadowed);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
const effective_bindings =
|
|
384
|
-
shadowed.size > 0 ? remove_shadowed(lazy_bindings, shadowed) : lazy_bindings;
|
|
385
|
-
let changed = false;
|
|
386
|
-
const new_right = apply_lazy_transforms(node.right, lazy_bindings);
|
|
387
|
-
if (new_right !== node.right) changed = true;
|
|
388
|
-
const new_body = apply_lazy_transforms(node.body, effective_bindings);
|
|
389
|
-
if (new_body !== node.body) changed = true;
|
|
390
|
-
return changed ? { ...node, right: new_right, body: new_body } : node;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
// Handle switch-case variable shadowing (const/let inside case consequent arrays)
|
|
394
|
-
if (node.type === 'SwitchStatement') {
|
|
395
|
-
let changed = false;
|
|
396
|
-
const new_discriminant = apply_lazy_transforms(node.discriminant, lazy_bindings);
|
|
397
|
-
if (new_discriminant !== node.discriminant) changed = true;
|
|
398
|
-
const new_cases = node.cases.map((/** @type {any} */ switch_case) => {
|
|
399
|
-
const case_bindings = collect_block_shadowed_names(switch_case.consequent, lazy_bindings);
|
|
400
|
-
const effective_bindings =
|
|
401
|
-
case_bindings.size > 0 ? remove_shadowed(lazy_bindings, case_bindings) : lazy_bindings;
|
|
402
|
-
let case_changed = false;
|
|
403
|
-
const new_test = switch_case.test
|
|
404
|
-
? apply_lazy_transforms(switch_case.test, lazy_bindings)
|
|
405
|
-
: null;
|
|
406
|
-
if (new_test !== switch_case.test) case_changed = true;
|
|
407
|
-
const new_consequent = switch_case.consequent.map((/** @type {any} */ stmt) => {
|
|
408
|
-
const transformed = apply_lazy_transforms(stmt, effective_bindings);
|
|
409
|
-
if (transformed !== stmt) case_changed = true;
|
|
410
|
-
return transformed;
|
|
411
|
-
});
|
|
412
|
-
if (case_changed) {
|
|
413
|
-
changed = true;
|
|
414
|
-
return { ...switch_case, test: new_test, consequent: new_consequent };
|
|
415
|
-
}
|
|
416
|
-
return switch_case;
|
|
417
|
-
});
|
|
418
|
-
return changed ? { ...node, discriminant: new_discriminant, cases: new_cases } : node;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
// Handle assignment: `name = value` → `__lazy0.name = value`
|
|
422
|
-
if (node.type === 'AssignmentExpression' && node.left.type === 'Identifier') {
|
|
423
|
-
const binding = lazy_bindings.get(node.left.name);
|
|
424
|
-
if (binding) {
|
|
425
|
-
return {
|
|
426
|
-
...node,
|
|
427
|
-
left: binding.read(),
|
|
428
|
-
right: apply_lazy_transforms(node.right, lazy_bindings),
|
|
429
|
-
};
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
// Handle update: `count++` → `__lazy0[0]++`
|
|
434
|
-
if (node.type === 'UpdateExpression' && node.argument.type === 'Identifier') {
|
|
435
|
-
const binding = lazy_bindings.get(node.argument.name);
|
|
436
|
-
if (binding) {
|
|
437
|
-
return { ...node, argument: binding.read() };
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
// Replace lazy variable declaration patterns with generated identifiers
|
|
442
|
-
if (node.type === 'VariableDeclarator' && node.id?.metadata?.lazy_id) {
|
|
443
|
-
const lazy_id = create_generated_identifier(node.id.metadata.lazy_id);
|
|
444
|
-
if (node.id.typeAnnotation) {
|
|
445
|
-
lazy_id.typeAnnotation = node.id.typeAnnotation;
|
|
446
|
-
}
|
|
447
|
-
return {
|
|
448
|
-
...node,
|
|
449
|
-
id: lazy_id,
|
|
450
|
-
init: apply_lazy_transforms(node.init, lazy_bindings),
|
|
451
|
-
};
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// Handle identifier references in expression position
|
|
455
|
-
if (node.type === 'Identifier') {
|
|
456
|
-
const binding = lazy_bindings.get(node.name);
|
|
457
|
-
if (binding) {
|
|
458
|
-
return binding.read();
|
|
459
|
-
}
|
|
460
|
-
return node;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
// Skip JSXIdentifier (component/element names)
|
|
464
|
-
if (node.type === 'JSXIdentifier') return node;
|
|
465
|
-
|
|
466
|
-
// Handle shorthand properties: `{ name }` → `{ name: __lazy0.name }`
|
|
467
|
-
if (node.type === 'Property' && node.shorthand && node.value?.type === 'Identifier') {
|
|
468
|
-
const binding = lazy_bindings.get(node.value.name);
|
|
469
|
-
if (binding) {
|
|
470
|
-
return {
|
|
471
|
-
...node,
|
|
472
|
-
shorthand: false,
|
|
473
|
-
value: binding.read(),
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
// Recurse into child nodes
|
|
479
|
-
let changed = false;
|
|
480
|
-
const result = /** @type {any} */ ({});
|
|
481
|
-
|
|
482
|
-
for (const key of Object.keys(node)) {
|
|
483
|
-
if (key === 'loc' || key === 'start' || key === 'end') {
|
|
484
|
-
result[key] = node[key];
|
|
485
|
-
continue;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
// Skip non-computed property keys (they're labels, not references)
|
|
489
|
-
if (key === 'key' && node.type === 'Property' && !node.computed && !node.shorthand) {
|
|
490
|
-
result[key] = node[key];
|
|
491
|
-
continue;
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
// Skip non-computed member expression property names
|
|
495
|
-
if (key === 'property' && node.type === 'MemberExpression' && !node.computed) {
|
|
496
|
-
result[key] = node[key];
|
|
497
|
-
continue;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
// Skip JSXAttribute name
|
|
501
|
-
if (key === 'name' && node.type === 'JSXAttribute') {
|
|
502
|
-
result[key] = node[key];
|
|
503
|
-
continue;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
// Skip variable declaration id (the lazy declaration itself was already replaced)
|
|
507
|
-
if (key === 'id' && node.type === 'VariableDeclarator') {
|
|
508
|
-
result[key] = node[key];
|
|
509
|
-
continue;
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
const child = node[key];
|
|
513
|
-
const transformed = apply_lazy_transforms(child, lazy_bindings);
|
|
514
|
-
result[key] = transformed;
|
|
515
|
-
if (transformed !== child) changed = true;
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
return changed ? result : node;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
/**
|
|
522
|
-
* Transform default values in function parameters without touching param names.
|
|
523
|
-
* E.g. `(step = count)` where `count` is a lazy binding → `(step = __lazy0[0])`.
|
|
524
|
-
*
|
|
525
|
-
* @param {any} param
|
|
526
|
-
* @param {Map<string, LazyBinding>} lazy_bindings
|
|
527
|
-
* @returns {any}
|
|
528
|
-
*/
|
|
529
|
-
function transform_param_defaults(param, lazy_bindings) {
|
|
530
|
-
if (param?.type === 'AssignmentPattern') {
|
|
531
|
-
const new_right = apply_lazy_transforms(param.right, lazy_bindings);
|
|
532
|
-
if (new_right !== param.right) {
|
|
533
|
-
return { ...param, right: new_right };
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
return param;
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
/**
|
|
540
|
-
* Collect names from a pattern that shadow lazy bindings.
|
|
541
|
-
* @param {any} pattern
|
|
542
|
-
* @param {Map<string, LazyBinding>} lazy_bindings
|
|
543
|
-
* @param {Set<string>} shadowed
|
|
544
|
-
*/
|
|
545
|
-
function collect_shadowed_names(pattern, lazy_bindings, shadowed) {
|
|
546
|
-
if (!pattern || typeof pattern !== 'object') return;
|
|
547
|
-
|
|
548
|
-
if (pattern.type === 'Identifier' && lazy_bindings.has(pattern.name)) {
|
|
549
|
-
shadowed.add(pattern.name);
|
|
550
|
-
return;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
if (pattern.type === 'AssignmentPattern') {
|
|
554
|
-
collect_shadowed_names(pattern.left, lazy_bindings, shadowed);
|
|
555
|
-
return;
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
if (pattern.type === 'RestElement') {
|
|
559
|
-
collect_shadowed_names(pattern.argument, lazy_bindings, shadowed);
|
|
560
|
-
return;
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
if (pattern.type === 'ObjectPattern') {
|
|
564
|
-
for (const prop of pattern.properties || []) {
|
|
565
|
-
if (prop.type === 'RestElement') {
|
|
566
|
-
collect_shadowed_names(prop.argument, lazy_bindings, shadowed);
|
|
567
|
-
} else {
|
|
568
|
-
collect_shadowed_names(prop.value, lazy_bindings, shadowed);
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
return;
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
if (pattern.type === 'ArrayPattern') {
|
|
575
|
-
for (const element of pattern.elements || []) {
|
|
576
|
-
if (element) collect_shadowed_names(element, lazy_bindings, shadowed);
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
/**
|
|
582
|
-
* Collect variable names declared in block-level statements that shadow lazy bindings.
|
|
583
|
-
* Scans VariableDeclarations (const/let/var) and FunctionDeclarations at the top level of a block.
|
|
584
|
-
*
|
|
585
|
-
* @param {any[]} statements
|
|
586
|
-
* @param {Map<string, LazyBinding>} lazy_bindings
|
|
587
|
-
* @returns {Set<string>}
|
|
588
|
-
*/
|
|
589
|
-
function collect_block_shadowed_names(statements, lazy_bindings) {
|
|
590
|
-
/** @type {Set<string>} */
|
|
591
|
-
const shadowed = new Set();
|
|
592
|
-
for (const stmt of statements) {
|
|
593
|
-
if (stmt.type === 'VariableDeclaration') {
|
|
594
|
-
for (const decl of stmt.declarations) {
|
|
595
|
-
// Skip lazy destructuring patterns — they ARE the lazy bindings,
|
|
596
|
-
// not local declarations that shadow them.
|
|
597
|
-
if (decl.id?.metadata?.lazy_id) continue;
|
|
598
|
-
if (decl.id) collect_shadowed_names(decl.id, lazy_bindings, shadowed);
|
|
599
|
-
}
|
|
600
|
-
} else if (stmt.type === 'FunctionDeclaration' && stmt.id) {
|
|
601
|
-
if (lazy_bindings.has(stmt.id.name)) {
|
|
602
|
-
shadowed.add(stmt.id.name);
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
return shadowed;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
/**
|
|
610
|
-
* Create a new lazy_bindings map with the shadowed names removed.
|
|
611
|
-
*
|
|
612
|
-
* @param {Map<string, LazyBinding>} lazy_bindings
|
|
613
|
-
* @param {Set<string>} shadowed
|
|
614
|
-
* @returns {Map<string, LazyBinding>}
|
|
615
|
-
*/
|
|
616
|
-
function remove_shadowed(lazy_bindings, shadowed) {
|
|
617
|
-
const result = new Map(lazy_bindings);
|
|
618
|
-
for (const name of shadowed) {
|
|
619
|
-
result.delete(name);
|
|
620
|
-
}
|
|
621
|
-
return result;
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
/**
|
|
625
|
-
* Replace lazy parameter patterns with their generated identifiers.
|
|
626
|
-
* A param `&{name, age}: Props` becomes `__lazy0: Props`.
|
|
627
|
-
*
|
|
628
|
-
* @param {any[]} params
|
|
629
|
-
* @returns {any[]}
|
|
630
|
-
*/
|
|
631
|
-
function replace_lazy_params(params) {
|
|
632
|
-
return params.map((param) => {
|
|
633
|
-
const pattern = param.type === 'AssignmentPattern' ? param.left : param;
|
|
634
|
-
|
|
635
|
-
if (
|
|
636
|
-
(pattern.type === 'ObjectPattern' || pattern.type === 'ArrayPattern') &&
|
|
637
|
-
pattern.lazy &&
|
|
638
|
-
pattern.metadata?.lazy_id
|
|
639
|
-
) {
|
|
640
|
-
const lazy_id = create_generated_identifier(pattern.metadata.lazy_id);
|
|
641
|
-
if (pattern.typeAnnotation) {
|
|
642
|
-
lazy_id.typeAnnotation = pattern.typeAnnotation;
|
|
643
|
-
}
|
|
644
|
-
if (param.type === 'AssignmentPattern') {
|
|
645
|
-
return { ...param, left: lazy_id };
|
|
646
|
-
}
|
|
647
|
-
return lazy_id;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
return param;
|
|
651
|
-
});
|
|
184
|
+
return { ast: final_program, code: result.code, map: result.map, css };
|
|
652
185
|
}
|
|
653
186
|
|
|
654
187
|
/**
|
|
@@ -1197,6 +730,18 @@ function collect_statement_bindings(statement, bindings) {
|
|
|
1197
730
|
) {
|
|
1198
731
|
bindings.set(statement.id.name, statement.id);
|
|
1199
732
|
}
|
|
733
|
+
|
|
734
|
+
// Statement-level lazy assignment: `&[x] = expr;` introduces `x` as a binding.
|
|
735
|
+
if (
|
|
736
|
+
statement.type === 'ExpressionStatement' &&
|
|
737
|
+
statement.expression?.type === 'AssignmentExpression' &&
|
|
738
|
+
statement.expression.operator === '=' &&
|
|
739
|
+
(statement.expression.left?.type === 'ObjectPattern' ||
|
|
740
|
+
statement.expression.left?.type === 'ArrayPattern') &&
|
|
741
|
+
statement.expression.left.lazy
|
|
742
|
+
) {
|
|
743
|
+
collect_pattern_bindings(statement.expression.left, bindings);
|
|
744
|
+
}
|
|
1200
745
|
}
|
|
1201
746
|
|
|
1202
747
|
/**
|
|
@@ -1457,176 +1002,6 @@ function create_component_lone_return_if_statement(node, render_nodes) {
|
|
|
1457
1002
|
);
|
|
1458
1003
|
}
|
|
1459
1004
|
|
|
1460
|
-
/**
|
|
1461
|
-
* Mark every selector inside the stylesheet as "used" so `renderStylesheets`
|
|
1462
|
-
* does not comment it out. We skip Ripple's selector-pruning pass because
|
|
1463
|
-
* React component boundaries are dynamic — any selector authored inside the
|
|
1464
|
-
* component's `<style>` block is considered intentional.
|
|
1465
|
-
*
|
|
1466
|
-
* @param {any} stylesheet
|
|
1467
|
-
* @returns {any}
|
|
1468
|
-
*/
|
|
1469
|
-
function prepare_stylesheet_for_render(stylesheet) {
|
|
1470
|
-
walk(stylesheet, null, {
|
|
1471
|
-
_(node, { next }) {
|
|
1472
|
-
if (node && node.metadata && typeof node.metadata === 'object') {
|
|
1473
|
-
node.metadata.used = true;
|
|
1474
|
-
if (node.type === 'RelativeSelector' && !node.metadata.is_global) {
|
|
1475
|
-
node.metadata.scoped = true;
|
|
1476
|
-
}
|
|
1477
|
-
}
|
|
1478
|
-
return next();
|
|
1479
|
-
},
|
|
1480
|
-
});
|
|
1481
|
-
return stylesheet;
|
|
1482
|
-
}
|
|
1483
|
-
|
|
1484
|
-
/**
|
|
1485
|
-
* @param {any} node
|
|
1486
|
-
* @returns {boolean}
|
|
1487
|
-
*/
|
|
1488
|
-
function is_style_element(node) {
|
|
1489
|
-
return (
|
|
1490
|
-
node &&
|
|
1491
|
-
node.type === 'Element' &&
|
|
1492
|
-
node.id &&
|
|
1493
|
-
node.id.type === 'Identifier' &&
|
|
1494
|
-
node.id.name === 'style'
|
|
1495
|
-
);
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
|
-
/**
|
|
1499
|
-
* @param {any} node
|
|
1500
|
-
* @returns {boolean}
|
|
1501
|
-
*/
|
|
1502
|
-
function is_composite_element(node) {
|
|
1503
|
-
if (!node || node.type !== 'Element' || !node.id) {
|
|
1504
|
-
return false;
|
|
1505
|
-
}
|
|
1506
|
-
|
|
1507
|
-
if (node.id.type === 'Identifier') {
|
|
1508
|
-
return /^[A-Z]/.test(node.id.name);
|
|
1509
|
-
}
|
|
1510
|
-
|
|
1511
|
-
return node.id.type === 'MemberExpression';
|
|
1512
|
-
}
|
|
1513
|
-
|
|
1514
|
-
/**
|
|
1515
|
-
* Recursively walk Element nodes within a component body and add the hash
|
|
1516
|
-
* class name so scope-qualified selectors (e.g. `.foo.hash`) match.
|
|
1517
|
-
*
|
|
1518
|
-
* @param {any} node
|
|
1519
|
-
* @param {string} hash
|
|
1520
|
-
* @returns {any}
|
|
1521
|
-
*/
|
|
1522
|
-
function annotate_with_hash(node, hash) {
|
|
1523
|
-
if (!node || typeof node !== 'object') return node;
|
|
1524
|
-
if (
|
|
1525
|
-
node.type === 'Component' ||
|
|
1526
|
-
node.type === 'FunctionDeclaration' ||
|
|
1527
|
-
node.type === 'FunctionExpression' ||
|
|
1528
|
-
node.type === 'ArrowFunctionExpression'
|
|
1529
|
-
) {
|
|
1530
|
-
return node;
|
|
1531
|
-
}
|
|
1532
|
-
|
|
1533
|
-
if (node.type === 'Element') {
|
|
1534
|
-
if (!is_style_element(node) && !is_composite_element(node)) {
|
|
1535
|
-
add_hash_class(node, hash);
|
|
1536
|
-
}
|
|
1537
|
-
if (Array.isArray(node.children)) {
|
|
1538
|
-
node.children = node.children
|
|
1539
|
-
.filter((/** @type {any} */ child) => !is_style_element(child))
|
|
1540
|
-
.map((/** @type {any} */ child) => annotate_with_hash(child, hash));
|
|
1541
|
-
}
|
|
1542
|
-
return node;
|
|
1543
|
-
}
|
|
1544
|
-
|
|
1545
|
-
for (const key of Object.keys(node)) {
|
|
1546
|
-
if (key === 'loc' || key === 'start' || key === 'end' || key === 'metadata' || key === 'css') {
|
|
1547
|
-
continue;
|
|
1548
|
-
}
|
|
1549
|
-
|
|
1550
|
-
const value = node[key];
|
|
1551
|
-
if (Array.isArray(value)) {
|
|
1552
|
-
node[key] = value.map((/** @type {any} */ child) => annotate_with_hash(child, hash));
|
|
1553
|
-
} else if (value && typeof value === 'object') {
|
|
1554
|
-
node[key] = annotate_with_hash(value, hash);
|
|
1555
|
-
}
|
|
1556
|
-
}
|
|
1557
|
-
|
|
1558
|
-
return node;
|
|
1559
|
-
}
|
|
1560
|
-
|
|
1561
|
-
/**
|
|
1562
|
-
* @param {any} component
|
|
1563
|
-
* @param {string} hash
|
|
1564
|
-
* @returns {void}
|
|
1565
|
-
*/
|
|
1566
|
-
function annotate_component_with_hash(component, hash) {
|
|
1567
|
-
/** @type {any[]} */
|
|
1568
|
-
const body = component.body;
|
|
1569
|
-
component.body = body
|
|
1570
|
-
.filter((/** @type {any} */ child) => !is_style_element(child))
|
|
1571
|
-
.map((/** @type {any} */ child) => annotate_with_hash(child, hash));
|
|
1572
|
-
}
|
|
1573
|
-
|
|
1574
|
-
/**
|
|
1575
|
-
* Ensure the element carries a `class` attribute containing the scoping hash.
|
|
1576
|
-
* @param {any} element
|
|
1577
|
-
* @param {string} hash
|
|
1578
|
-
*/
|
|
1579
|
-
function add_hash_class(element, hash) {
|
|
1580
|
-
const attrs = element.attributes || (element.attributes = []);
|
|
1581
|
-
const existing = attrs.find(
|
|
1582
|
-
(/** @type {any} */ a) =>
|
|
1583
|
-
a.type === 'Attribute' &&
|
|
1584
|
-
a.name &&
|
|
1585
|
-
a.name.type === 'Identifier' &&
|
|
1586
|
-
(a.name.name === 'class' || a.name.name === 'className'),
|
|
1587
|
-
);
|
|
1588
|
-
|
|
1589
|
-
if (!existing) {
|
|
1590
|
-
attrs.push({
|
|
1591
|
-
type: 'Attribute',
|
|
1592
|
-
name: { type: 'Identifier', name: 'class' },
|
|
1593
|
-
value: { type: 'Literal', value: hash, raw: JSON.stringify(hash) },
|
|
1594
|
-
});
|
|
1595
|
-
return;
|
|
1596
|
-
}
|
|
1597
|
-
|
|
1598
|
-
const value = existing.value;
|
|
1599
|
-
if (!value) {
|
|
1600
|
-
existing.value = { type: 'Literal', value: hash, raw: JSON.stringify(hash) };
|
|
1601
|
-
return;
|
|
1602
|
-
}
|
|
1603
|
-
|
|
1604
|
-
if (value.type === 'Literal' && typeof value.value === 'string') {
|
|
1605
|
-
const merged = `${value.value} ${hash}`;
|
|
1606
|
-
existing.value = { type: 'Literal', value: merged, raw: JSON.stringify(merged) };
|
|
1607
|
-
return;
|
|
1608
|
-
}
|
|
1609
|
-
|
|
1610
|
-
// Dynamic expression. Concatenate at runtime via template literal.
|
|
1611
|
-
const expression = value.type === 'JSXExpressionContainer' ? value.expression : value;
|
|
1612
|
-
existing.value = {
|
|
1613
|
-
type: 'TemplateLiteral',
|
|
1614
|
-
expressions: [expression],
|
|
1615
|
-
quasis: [
|
|
1616
|
-
{
|
|
1617
|
-
type: 'TemplateElement',
|
|
1618
|
-
value: { raw: '', cooked: '' },
|
|
1619
|
-
tail: false,
|
|
1620
|
-
},
|
|
1621
|
-
{
|
|
1622
|
-
type: 'TemplateElement',
|
|
1623
|
-
value: { raw: ` ${hash}`, cooked: ` ${hash}` },
|
|
1624
|
-
tail: true,
|
|
1625
|
-
},
|
|
1626
|
-
],
|
|
1627
|
-
};
|
|
1628
|
-
}
|
|
1629
|
-
|
|
1630
1005
|
/**
|
|
1631
1006
|
* @param {any} node
|
|
1632
1007
|
* @returns {boolean}
|
|
@@ -1641,6 +1016,10 @@ function is_jsx_child(node) {
|
|
|
1641
1016
|
t === 'JSXText' ||
|
|
1642
1017
|
t === 'Tsx' ||
|
|
1643
1018
|
t === 'TsxCompat' ||
|
|
1019
|
+
t === 'Element' ||
|
|
1020
|
+
t === 'Text' ||
|
|
1021
|
+
t === 'TSRXExpression' ||
|
|
1022
|
+
t === 'Html' ||
|
|
1644
1023
|
t === 'IfStatement' ||
|
|
1645
1024
|
t === 'ForOfStatement' ||
|
|
1646
1025
|
t === 'SwitchStatement' ||
|
|
@@ -1655,6 +1034,11 @@ function is_jsx_child(node) {
|
|
|
1655
1034
|
*/
|
|
1656
1035
|
function to_jsx_element(node, transform_context) {
|
|
1657
1036
|
if (node.type === 'JSXElement') return node;
|
|
1037
|
+
if ((node.children || []).some((/** @type {any} */ c) => c && c.type === 'Html')) {
|
|
1038
|
+
throw new Error(
|
|
1039
|
+
'`{html ...}` is not supported on the React target. Use `dangerouslySetInnerHTML={{ __html: ... }}` as an element attribute instead.',
|
|
1040
|
+
);
|
|
1041
|
+
}
|
|
1658
1042
|
if (is_dynamic_element_id(node.id)) {
|
|
1659
1043
|
return dynamic_element_to_jsx_child(node, transform_context);
|
|
1660
1044
|
}
|
|
@@ -2039,6 +1423,10 @@ function to_jsx_child(node, transform_context) {
|
|
|
2039
1423
|
return to_jsx_expression_container(to_text_expression(node.expression, node), node);
|
|
2040
1424
|
case 'TSRXExpression':
|
|
2041
1425
|
return to_jsx_expression_container(node.expression, node);
|
|
1426
|
+
case 'Html':
|
|
1427
|
+
throw new Error(
|
|
1428
|
+
'`{html ...}` is not supported on the React target. Use `dangerouslySetInnerHTML={{ __html: ... }}` as an element attribute instead.',
|
|
1429
|
+
);
|
|
2042
1430
|
case 'IfStatement':
|
|
2043
1431
|
return if_statement_to_jsx_child(node, transform_context);
|
|
2044
1432
|
case 'ForOfStatement':
|