@tsrx/solid 0.0.5 → 0.0.7
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 -2
- package/src/transform.js +119 -10
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Solid compiler built on @tsrx/core",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Dominic Gannaway",
|
|
6
|
-
"version": "0.0.
|
|
6
|
+
"version": "0.0.7",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"publishConfig": {
|
|
9
9
|
"access": "public"
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"esrap": "^2.1.0",
|
|
24
24
|
"zimmerframe": "^1.1.2",
|
|
25
|
-
"@tsrx/core": "0.0.
|
|
25
|
+
"@tsrx/core": "0.0.7"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"solid-js": ">=1.8 || >=2.0.0-beta"
|
package/src/transform.js
CHANGED
|
@@ -8,11 +8,15 @@ import {
|
|
|
8
8
|
renderStylesheets,
|
|
9
9
|
setLocation,
|
|
10
10
|
applyLazyTransforms as apply_lazy_transforms,
|
|
11
|
+
findFirstTopLevelAwaitInComponentBody as find_first_top_level_await_in_component_body,
|
|
11
12
|
collectLazyBindingsFromComponent as collect_lazy_bindings_from_component,
|
|
12
13
|
preallocateLazyIds as preallocate_lazy_ids,
|
|
13
14
|
replaceLazyParams as replace_lazy_params,
|
|
14
15
|
prepareStylesheetForRender as prepare_stylesheet_for_render,
|
|
15
16
|
annotateComponentWithHash as annotate_component_with_hash,
|
|
17
|
+
isInterleavedBody as is_interleaved_body_core,
|
|
18
|
+
isCapturableJsxChild as is_capturable_jsx_child,
|
|
19
|
+
captureJsxChild,
|
|
16
20
|
} from '@tsrx/core';
|
|
17
21
|
|
|
18
22
|
/**
|
|
@@ -69,6 +73,22 @@ export function transform(ast, source, filename) {
|
|
|
69
73
|
walk(/** @type {any} */ (ast), transform_context, {
|
|
70
74
|
Component(node, { next, state }) {
|
|
71
75
|
const as_any = /** @type {any} */ (node);
|
|
76
|
+
const await_expression = find_first_top_level_await_in_component_body(as_any.body || []);
|
|
77
|
+
|
|
78
|
+
if (await_expression) {
|
|
79
|
+
const await_start = get_await_keyword_start(await_expression, source);
|
|
80
|
+
const adjusted_node = /** @type {any} */ ({
|
|
81
|
+
...await_expression,
|
|
82
|
+
start: await_start,
|
|
83
|
+
end: await_start + 'await'.length,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
throw create_compile_error(
|
|
87
|
+
adjusted_node,
|
|
88
|
+
'`await` is not allowed inside Solid components.',
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
72
92
|
const css = as_any.css;
|
|
73
93
|
if (css) {
|
|
74
94
|
stylesheets.push(css);
|
|
@@ -161,6 +181,29 @@ export function transform(ast, source, filename) {
|
|
|
161
181
|
};
|
|
162
182
|
}
|
|
163
183
|
|
|
184
|
+
/**
|
|
185
|
+
* @param {any} await_node
|
|
186
|
+
* @param {string} source
|
|
187
|
+
* @returns {number}
|
|
188
|
+
*/
|
|
189
|
+
function get_await_keyword_start(await_node, source) {
|
|
190
|
+
if (await_node?.type === 'AwaitExpression') {
|
|
191
|
+
return await_node.start ?? 0;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (await_node?.type === 'ForOfStatement' && await_node.await === true) {
|
|
195
|
+
const statement_start = await_node.start ?? 0;
|
|
196
|
+
const statement_end = await_node.end ?? statement_start;
|
|
197
|
+
const statement_source = source.slice(statement_start, statement_end);
|
|
198
|
+
const await_offset = statement_source.search(/\bawait\b/);
|
|
199
|
+
|
|
200
|
+
if (await_offset !== -1) {
|
|
201
|
+
return statement_start + await_offset;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return await_node?.start ?? 0;
|
|
206
|
+
}
|
|
164
207
|
// =====================================================================
|
|
165
208
|
// Component → FunctionDeclaration
|
|
166
209
|
// =====================================================================
|
|
@@ -201,22 +244,53 @@ function component_to_function_declaration(component, transform_context) {
|
|
|
201
244
|
const early_if = /** @type {any} */ (body[early_idx]);
|
|
202
245
|
const before = body.slice(0, early_idx);
|
|
203
246
|
const after = body.slice(early_idx + 1);
|
|
247
|
+
|
|
248
|
+
// If mutations are interleaved with JSX children, the mutation and the
|
|
249
|
+
// JSX it affects can't both be hoisted out of order — that is the same
|
|
250
|
+
// bug `body_to_jsx_child` avoids. Capture each JSX child into a const
|
|
251
|
+
// at its source position so later mutations in the outer body don't
|
|
252
|
+
// retroactively change what earlier children rendered.
|
|
253
|
+
const early_interleaved = is_interleaved_body([...before, ...after]);
|
|
254
|
+
|
|
204
255
|
/** @type {any[]} */
|
|
205
256
|
const before_non_jsx = [];
|
|
206
257
|
/** @type {any[]} */
|
|
207
258
|
const before_jsx = [];
|
|
208
|
-
for (const child of before) {
|
|
209
|
-
if (is_jsx_child(child)) before_jsx.push(child);
|
|
210
|
-
else before_non_jsx.push(child);
|
|
211
|
-
}
|
|
212
259
|
/** @type {any[]} */
|
|
213
260
|
const after_non_jsx = [];
|
|
214
261
|
/** @type {any[]} */
|
|
215
262
|
const after_jsx = [];
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
263
|
+
let early_capture_index = 0;
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* @param {any[]} nodes
|
|
267
|
+
* @param {any[]} outer
|
|
268
|
+
* @param {any[]} jsx_bucket
|
|
269
|
+
*/
|
|
270
|
+
const collect = (nodes, outer, jsx_bucket) => {
|
|
271
|
+
for (const child of nodes) {
|
|
272
|
+
if (is_jsx_child(child)) {
|
|
273
|
+
if (early_interleaved) {
|
|
274
|
+
const jsx = to_jsx_child(child, transform_context);
|
|
275
|
+
if (is_capturable_jsx_child(jsx)) {
|
|
276
|
+
const { declaration, reference } = captureJsxChild(jsx, early_capture_index++);
|
|
277
|
+
outer.push(declaration);
|
|
278
|
+
jsx_bucket.push(reference);
|
|
279
|
+
} else {
|
|
280
|
+
jsx_bucket.push(jsx);
|
|
281
|
+
}
|
|
282
|
+
} else {
|
|
283
|
+
jsx_bucket.push(child);
|
|
284
|
+
}
|
|
285
|
+
} else {
|
|
286
|
+
outer.push(child);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
collect(before, before_non_jsx, before_jsx);
|
|
292
|
+
collect(after, after_non_jsx, after_jsx);
|
|
293
|
+
|
|
220
294
|
const lifted = [...before_jsx, ...after_jsx];
|
|
221
295
|
if (lifted.length > 0) {
|
|
222
296
|
transform_context.needs_show = true;
|
|
@@ -228,10 +302,19 @@ function component_to_function_declaration(component, transform_context) {
|
|
|
228
302
|
|
|
229
303
|
const statements = [];
|
|
230
304
|
const render_nodes = [];
|
|
305
|
+
const interleaved = is_interleaved_body(effective_body);
|
|
306
|
+
let capture_index = 0;
|
|
231
307
|
|
|
232
308
|
for (const child of effective_body) {
|
|
233
309
|
if (is_jsx_child(child)) {
|
|
234
|
-
|
|
310
|
+
const jsx = to_jsx_child(child, transform_context);
|
|
311
|
+
if (interleaved && is_capturable_jsx_child(jsx)) {
|
|
312
|
+
const { declaration, reference } = captureJsxChild(jsx, capture_index++);
|
|
313
|
+
statements.push(declaration);
|
|
314
|
+
render_nodes.push(reference);
|
|
315
|
+
} else {
|
|
316
|
+
render_nodes.push(jsx);
|
|
317
|
+
}
|
|
235
318
|
} else {
|
|
236
319
|
statements.push(child);
|
|
237
320
|
}
|
|
@@ -376,13 +459,28 @@ function to_jsx_child(node, transform_context) {
|
|
|
376
459
|
* @returns {any}
|
|
377
460
|
*/
|
|
378
461
|
function body_to_jsx_child(body_nodes, transform_context) {
|
|
462
|
+
// When non-JSX statements are interleaved with JSX children, preserve
|
|
463
|
+
// source order by capturing each JSX child into a const at its textual
|
|
464
|
+
// position. Otherwise all statements would run before any JSX is
|
|
465
|
+
// constructed, so every JSX child would observe the final state of
|
|
466
|
+
// mutable variables instead of the value at its point in the source.
|
|
467
|
+
const interleaved = is_interleaved_body(body_nodes);
|
|
468
|
+
|
|
379
469
|
/** @type {any[]} */
|
|
380
470
|
const statements = [];
|
|
381
471
|
/** @type {any[]} */
|
|
382
472
|
const children = [];
|
|
473
|
+
let capture_index = 0;
|
|
383
474
|
for (const child of body_nodes) {
|
|
384
475
|
if (is_jsx_child(child)) {
|
|
385
|
-
|
|
476
|
+
const jsx = to_jsx_child(child, transform_context);
|
|
477
|
+
if (interleaved && is_capturable_jsx_child(jsx)) {
|
|
478
|
+
const { declaration, reference } = captureJsxChild(jsx, capture_index++);
|
|
479
|
+
statements.push(declaration);
|
|
480
|
+
children.push(reference);
|
|
481
|
+
} else {
|
|
482
|
+
children.push(jsx);
|
|
483
|
+
}
|
|
386
484
|
} else {
|
|
387
485
|
statements.push(child);
|
|
388
486
|
}
|
|
@@ -427,6 +525,17 @@ function body_to_jsx_child(body_nodes, transform_context) {
|
|
|
427
525
|
});
|
|
428
526
|
}
|
|
429
527
|
|
|
528
|
+
/**
|
|
529
|
+
* Solid-specific binding of the core `isInterleavedBody` helper with this
|
|
530
|
+
* target's `is_jsx_child` predicate.
|
|
531
|
+
*
|
|
532
|
+
* @param {any[]} body_nodes
|
|
533
|
+
* @returns {boolean}
|
|
534
|
+
*/
|
|
535
|
+
function is_interleaved_body(body_nodes) {
|
|
536
|
+
return is_interleaved_body_core(body_nodes, is_jsx_child);
|
|
537
|
+
}
|
|
538
|
+
|
|
430
539
|
/**
|
|
431
540
|
* @param {any} node
|
|
432
541
|
* @returns {boolean}
|