@tsrx/solid 0.0.27 → 0.1.0
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 +6 -2
- package/src/index.js +2 -0
- package/src/ref.js +1 -0
- package/src/transform.js +230 -4
- package/types/index.d.ts +2 -0
- package/types/ref.d.ts +1 -0
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.1.0",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"publishConfig": {
|
|
9
9
|
"access": "public"
|
|
@@ -17,12 +17,16 @@
|
|
|
17
17
|
".": {
|
|
18
18
|
"types": "./types/index.d.ts",
|
|
19
19
|
"default": "./src/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./ref": {
|
|
22
|
+
"types": "./types/ref.d.ts",
|
|
23
|
+
"default": "./src/ref.js"
|
|
20
24
|
}
|
|
21
25
|
},
|
|
22
26
|
"dependencies": {
|
|
23
27
|
"esrap": "^2.1.0",
|
|
24
28
|
"zimmerframe": "^1.1.2",
|
|
25
|
-
"@tsrx/core": "0.0
|
|
29
|
+
"@tsrx/core": "0.1.0"
|
|
26
30
|
},
|
|
27
31
|
"peerDependencies": {
|
|
28
32
|
"solid-js": ">=1.8 || >=2.0.0-beta"
|
package/src/index.js
CHANGED
package/src/ref.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@tsrx/core/runtime/ref';
|
package/src/transform.js
CHANGED
|
@@ -9,13 +9,18 @@ import {
|
|
|
9
9
|
toJsxAttribute,
|
|
10
10
|
validateAtMostOneRefAttribute,
|
|
11
11
|
setLocation,
|
|
12
|
+
addJsxSetupDeclaration as add_jsx_setup_declaration,
|
|
12
13
|
applyLazyTransforms as apply_lazy_transforms,
|
|
13
14
|
collectLazyBindingsFromComponent as collect_lazy_bindings_from_component,
|
|
15
|
+
extractJsxSetupDeclarations as extract_jsx_setup_declarations,
|
|
14
16
|
replaceLazyParams as replace_lazy_params,
|
|
15
17
|
rewriteLoopContinuesToBareReturns as rewrite_loop_continues_to_bare_returns,
|
|
18
|
+
isRefPropExpression as is_ref_prop_expression,
|
|
16
19
|
isInterleavedBody as is_interleaved_body_core,
|
|
17
20
|
isCapturableJsxChild as is_capturable_jsx_child,
|
|
18
21
|
captureJsxChild,
|
|
22
|
+
CREATE_REF_PROP_INTERNAL_NAME,
|
|
23
|
+
NORMALIZE_SPREAD_PROPS_INTERNAL_NAME,
|
|
19
24
|
tsxNodeToJsxExpression as tsx_node_to_jsx_expression,
|
|
20
25
|
// Shared AST builders (truly platform-agnostic utilities).
|
|
21
26
|
clone_expression_node,
|
|
@@ -49,6 +54,7 @@ import { builders as b } from '@tsrx/core';
|
|
|
49
54
|
* needs_match: boolean,
|
|
50
55
|
* needs_errored: boolean,
|
|
51
56
|
* needs_loading: boolean,
|
|
57
|
+
* needs_normalize_spread_props: boolean,
|
|
52
58
|
* }} TransformContext
|
|
53
59
|
*/
|
|
54
60
|
|
|
@@ -79,6 +85,7 @@ const solid_platform = {
|
|
|
79
85
|
// import injection goes through `hooks.injectImports`.
|
|
80
86
|
suspense: 'solid-js',
|
|
81
87
|
errorBoundary: 'solid-js',
|
|
88
|
+
refProp: '@tsrx/solid/ref',
|
|
82
89
|
},
|
|
83
90
|
jsx: {
|
|
84
91
|
rewriteClassAttr: false,
|
|
@@ -103,6 +110,7 @@ const solid_platform = {
|
|
|
103
110
|
needs_match: false,
|
|
104
111
|
needs_errored: false,
|
|
105
112
|
needs_loading: false,
|
|
113
|
+
needs_normalize_spread_props: false,
|
|
106
114
|
}),
|
|
107
115
|
validateComponentAwait: (await_expression, _component, ctx, _requires, source) => {
|
|
108
116
|
const await_start = get_await_keyword_start(await_expression, source);
|
|
@@ -244,6 +252,7 @@ function component_to_function_declaration(component, transform_context) {
|
|
|
244
252
|
}
|
|
245
253
|
if (early_interleaved) {
|
|
246
254
|
const jsx = to_jsx_child(child, transform_context);
|
|
255
|
+
outer.push(...extract_jsx_setup_declarations(jsx));
|
|
247
256
|
if (is_capturable_jsx_child(jsx)) {
|
|
248
257
|
const { declaration, reference } = captureJsxChild(jsx, early_capture_index++);
|
|
249
258
|
outer.push(declaration);
|
|
@@ -288,6 +297,7 @@ function component_to_function_declaration(component, transform_context) {
|
|
|
288
297
|
for (const child of effective_body) {
|
|
289
298
|
if (is_jsx_child(child)) {
|
|
290
299
|
const jsx = to_jsx_child(child, transform_context);
|
|
300
|
+
statements.push(...extract_jsx_setup_declarations(jsx));
|
|
291
301
|
if (interleaved && is_capturable_jsx_child(jsx)) {
|
|
292
302
|
const { declaration, reference } = captureJsxChild(jsx, capture_index++);
|
|
293
303
|
statements.push(declaration);
|
|
@@ -401,6 +411,8 @@ function to_jsx_child(node, transform_context) {
|
|
|
401
411
|
// We're inside a JSX child position by construction; keep `{expr}`
|
|
402
412
|
// containers wrapped. See helpers.js.
|
|
403
413
|
return tsx_node_to_jsx_expression(node, true);
|
|
414
|
+
case 'Tsrx':
|
|
415
|
+
return tsrx_node_to_jsx_expression(node, transform_context, true);
|
|
404
416
|
case 'TsxCompat':
|
|
405
417
|
return tsx_compat_node_to_jsx_expression(node, transform_context, true);
|
|
406
418
|
case 'Element':
|
|
@@ -426,6 +438,40 @@ function to_jsx_child(node, transform_context) {
|
|
|
426
438
|
}
|
|
427
439
|
}
|
|
428
440
|
|
|
441
|
+
/**
|
|
442
|
+
* Lower a `<tsrx>` node's native TSRX template body to a Solid JSX expression.
|
|
443
|
+
*
|
|
444
|
+
* @param {any} node
|
|
445
|
+
* @param {TransformContext} transform_context
|
|
446
|
+
* @param {boolean} [in_jsx_child]
|
|
447
|
+
* @returns {any}
|
|
448
|
+
*/
|
|
449
|
+
function tsrx_node_to_jsx_expression(node, transform_context, in_jsx_child = false) {
|
|
450
|
+
const children = (node.children || []).filter(
|
|
451
|
+
(/** @type {any} */ child) =>
|
|
452
|
+
child &&
|
|
453
|
+
child.type !== 'EmptyStatement' &&
|
|
454
|
+
(child.type !== 'JSXText' || child.value.trim() !== ''),
|
|
455
|
+
);
|
|
456
|
+
|
|
457
|
+
let expression = body_to_jsx_child(children, transform_context);
|
|
458
|
+
if (is_branch_arrow(expression)) {
|
|
459
|
+
expression = b.call(expression);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (
|
|
463
|
+
in_jsx_child &&
|
|
464
|
+
expression.type !== 'JSXElement' &&
|
|
465
|
+
expression.type !== 'JSXFragment' &&
|
|
466
|
+
expression.type !== 'JSXText' &&
|
|
467
|
+
expression.type !== 'JSXExpressionContainer'
|
|
468
|
+
) {
|
|
469
|
+
return to_jsx_expression_container(expression, node);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return expression;
|
|
473
|
+
}
|
|
474
|
+
|
|
429
475
|
/**
|
|
430
476
|
* Convert a list of body nodes to a Solid JSX child.
|
|
431
477
|
*
|
|
@@ -482,6 +528,7 @@ function body_to_jsx_child(body_nodes, transform_context) {
|
|
|
482
528
|
|
|
483
529
|
if (is_jsx_child(child)) {
|
|
484
530
|
const jsx = to_jsx_child(child, transform_context);
|
|
531
|
+
statements.push(...extract_jsx_setup_declarations(jsx));
|
|
485
532
|
if (interleaved && is_capturable_jsx_child(jsx)) {
|
|
486
533
|
const { declaration, reference } = captureJsxChild(jsx, capture_index++);
|
|
487
534
|
statements.push(declaration);
|
|
@@ -669,7 +716,9 @@ function loop_body_to_callback_statements(body_nodes, transform_context) {
|
|
|
669
716
|
}
|
|
670
717
|
|
|
671
718
|
if (is_jsx_child(child)) {
|
|
672
|
-
|
|
719
|
+
const jsx = to_jsx_child(child, transform_context);
|
|
720
|
+
statements.push(...extract_jsx_setup_declarations(jsx));
|
|
721
|
+
children.push(jsx);
|
|
673
722
|
} else if (is_bare_render_expression(child)) {
|
|
674
723
|
children.push(to_jsx_expression_container(child, child));
|
|
675
724
|
} else {
|
|
@@ -1350,6 +1399,53 @@ const TEMPLATE_FRAGMENT_ERROR =
|
|
|
1350
1399
|
* @param {TransformContext} transform_context
|
|
1351
1400
|
*/
|
|
1352
1401
|
function inject_solid_imports(program, transform_context) {
|
|
1402
|
+
if (transform_context.needs_ref_prop || transform_context.needs_normalize_spread_props) {
|
|
1403
|
+
const specifiers = [];
|
|
1404
|
+
|
|
1405
|
+
if (transform_context.needs_ref_prop) {
|
|
1406
|
+
specifiers.push({
|
|
1407
|
+
type: 'ImportSpecifier',
|
|
1408
|
+
imported: { type: 'Identifier', name: 'create_ref_prop', metadata: { path: [] } },
|
|
1409
|
+
local: {
|
|
1410
|
+
type: 'Identifier',
|
|
1411
|
+
name: CREATE_REF_PROP_INTERNAL_NAME,
|
|
1412
|
+
metadata: { path: [] },
|
|
1413
|
+
},
|
|
1414
|
+
metadata: { path: [] },
|
|
1415
|
+
});
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
if (transform_context.needs_normalize_spread_props) {
|
|
1419
|
+
specifiers.push({
|
|
1420
|
+
type: 'ImportSpecifier',
|
|
1421
|
+
imported: {
|
|
1422
|
+
type: 'Identifier',
|
|
1423
|
+
name: 'normalize_spread_props',
|
|
1424
|
+
metadata: { path: [] },
|
|
1425
|
+
},
|
|
1426
|
+
local: {
|
|
1427
|
+
type: 'Identifier',
|
|
1428
|
+
name: NORMALIZE_SPREAD_PROPS_INTERNAL_NAME,
|
|
1429
|
+
metadata: { path: [] },
|
|
1430
|
+
},
|
|
1431
|
+
metadata: { path: [] },
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
program.body.unshift(
|
|
1436
|
+
/** @type {any} */ ({
|
|
1437
|
+
type: 'ImportDeclaration',
|
|
1438
|
+
specifiers,
|
|
1439
|
+
source: {
|
|
1440
|
+
type: 'Literal',
|
|
1441
|
+
value: '@tsrx/solid/ref',
|
|
1442
|
+
raw: "'@tsrx/solid/ref'",
|
|
1443
|
+
},
|
|
1444
|
+
metadata: { path: [] },
|
|
1445
|
+
}),
|
|
1446
|
+
);
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1353
1449
|
const needed = [];
|
|
1354
1450
|
if (transform_context.needs_show) needed.push('Show');
|
|
1355
1451
|
if (transform_context.needs_for) needed.push('For');
|
|
@@ -1610,16 +1706,146 @@ function has_text_content_attribute(attributes) {
|
|
|
1610
1706
|
* @returns {any[]}
|
|
1611
1707
|
*/
|
|
1612
1708
|
function transform_element_attributes(raw_attrs, is_composite, transform_context) {
|
|
1613
|
-
void is_composite;
|
|
1614
1709
|
validateAtMostOneRefAttribute(raw_attrs, /** @type {any} */ (transform_context));
|
|
1615
1710
|
/** @type {any[]} */
|
|
1616
1711
|
const result = [];
|
|
1617
1712
|
|
|
1618
|
-
for (const attr of
|
|
1713
|
+
for (const attr of normalize_solid_named_ref_attributes(
|
|
1714
|
+
raw_attrs,
|
|
1715
|
+
!is_composite,
|
|
1716
|
+
transform_context,
|
|
1717
|
+
)) {
|
|
1619
1718
|
if (!attr) continue;
|
|
1620
1719
|
result.push(toJsxAttribute(attr, /** @type {any} */ (transform_context)));
|
|
1621
1720
|
}
|
|
1622
|
-
return mergeDuplicateRefs(
|
|
1721
|
+
return mergeDuplicateRefs(
|
|
1722
|
+
normalize_solid_host_ref_spreads(result, !is_composite, transform_context),
|
|
1723
|
+
/** @type {any} */ (transform_context),
|
|
1724
|
+
);
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
/**
|
|
1728
|
+
* @param {any[]} attrs
|
|
1729
|
+
* @param {boolean} is_host
|
|
1730
|
+
* @param {TransformContext} transform_context
|
|
1731
|
+
* @returns {any[]}
|
|
1732
|
+
*/
|
|
1733
|
+
function normalize_solid_named_ref_attributes(attrs, is_host, transform_context) {
|
|
1734
|
+
if (!is_host) return attrs;
|
|
1735
|
+
|
|
1736
|
+
return attrs.map((attr) => {
|
|
1737
|
+
if (
|
|
1738
|
+
!attr ||
|
|
1739
|
+
attr.type !== 'Attribute' ||
|
|
1740
|
+
attr.name?.type !== 'Identifier' ||
|
|
1741
|
+
attr.name.name === 'ref' ||
|
|
1742
|
+
!(
|
|
1743
|
+
attr.value?.type === 'RefExpression' ||
|
|
1744
|
+
is_ref_prop_expression(attr.value) ||
|
|
1745
|
+
(attr.value?.type === 'JSXExpressionContainer' &&
|
|
1746
|
+
is_ref_prop_expression(attr.value.expression))
|
|
1747
|
+
)
|
|
1748
|
+
) {
|
|
1749
|
+
return attr;
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
if (transform_context.typeOnly) {
|
|
1753
|
+
return {
|
|
1754
|
+
...attr,
|
|
1755
|
+
name: {
|
|
1756
|
+
...attr.name,
|
|
1757
|
+
metadata: { ...(attr.name.metadata || {}), disable_verification: true },
|
|
1758
|
+
},
|
|
1759
|
+
};
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
return {
|
|
1763
|
+
...attr,
|
|
1764
|
+
name: { ...attr.name, name: 'ref' },
|
|
1765
|
+
};
|
|
1766
|
+
});
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
/**
|
|
1770
|
+
* @param {any[]} attrs
|
|
1771
|
+
* @param {boolean} is_host
|
|
1772
|
+
* @param {TransformContext} transform_context
|
|
1773
|
+
* @returns {any[]}
|
|
1774
|
+
*/
|
|
1775
|
+
function normalize_solid_host_ref_spreads(attrs, is_host, transform_context) {
|
|
1776
|
+
if (!is_host) return attrs;
|
|
1777
|
+
|
|
1778
|
+
const ref_exprs = attrs
|
|
1779
|
+
.filter((attr) => is_solid_jsx_ref_attribute(attr))
|
|
1780
|
+
.map((attr) => attr.value.expression);
|
|
1781
|
+
const needs_synthetic_spread_ref = ref_exprs.length > 0;
|
|
1782
|
+
|
|
1783
|
+
return attrs.flatMap((attr) => {
|
|
1784
|
+
if (!attr || attr.type !== 'JSXSpreadAttribute') {
|
|
1785
|
+
return [attr];
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
transform_context.needs_normalize_spread_props = true;
|
|
1789
|
+
const normalized = b.call(NORMALIZE_SPREAD_PROPS_INTERNAL_NAME, attr.argument);
|
|
1790
|
+
|
|
1791
|
+
if (needs_synthetic_spread_ref) {
|
|
1792
|
+
const normalized_id = create_generated_identifier(
|
|
1793
|
+
create_solid_spread_props_name(transform_context),
|
|
1794
|
+
);
|
|
1795
|
+
const spread = {
|
|
1796
|
+
...attr,
|
|
1797
|
+
argument: clone_identifier(normalized_id),
|
|
1798
|
+
};
|
|
1799
|
+
const ref_attr = b.jsx_attribute(
|
|
1800
|
+
b.jsx_id('ref'),
|
|
1801
|
+
b.jsx_expression_container(b.member(clone_identifier(normalized_id), 'ref'), attr),
|
|
1802
|
+
false,
|
|
1803
|
+
attr,
|
|
1804
|
+
);
|
|
1805
|
+
ref_attr.metadata = { ...(ref_attr.metadata || {}) };
|
|
1806
|
+
/** @type {any} */ (ref_attr.metadata).from_ref_keyword = true;
|
|
1807
|
+
add_jsx_setup_declaration(spread, b.let(clone_identifier(normalized_id), normalized));
|
|
1808
|
+
|
|
1809
|
+
return [spread, ref_attr];
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
return [
|
|
1813
|
+
{
|
|
1814
|
+
...attr,
|
|
1815
|
+
argument: normalized,
|
|
1816
|
+
},
|
|
1817
|
+
];
|
|
1818
|
+
});
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
/**
|
|
1822
|
+
* @param {TransformContext} transform_context
|
|
1823
|
+
* @returns {string}
|
|
1824
|
+
*/
|
|
1825
|
+
function create_solid_spread_props_name(transform_context) {
|
|
1826
|
+
if (transform_context.helper_state) {
|
|
1827
|
+
transform_context.helper_state.next_id += 1;
|
|
1828
|
+
return `${transform_context.helper_state.base_name}__spread_props${transform_context.helper_state.next_id}`;
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
transform_context.local_statement_component_index += 1;
|
|
1832
|
+
return `_tsrx_spread_props_${transform_context.local_statement_component_index}`;
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
/**
|
|
1836
|
+
* @param {any} attr
|
|
1837
|
+
* @returns {boolean}
|
|
1838
|
+
*/
|
|
1839
|
+
function is_solid_jsx_ref_attribute(attr) {
|
|
1840
|
+
return !!(
|
|
1841
|
+
attr &&
|
|
1842
|
+
attr.type === 'JSXAttribute' &&
|
|
1843
|
+
attr.name?.type === 'JSXIdentifier' &&
|
|
1844
|
+
attr.name.name === 'ref' &&
|
|
1845
|
+
attr.value?.type === 'JSXExpressionContainer' &&
|
|
1846
|
+
attr.value.expression &&
|
|
1847
|
+
attr.value.expression.type !== 'JSXEmptyExpression'
|
|
1848
|
+
);
|
|
1623
1849
|
}
|
|
1624
1850
|
|
|
1625
1851
|
/**
|
package/types/index.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import type { CompileFn, ParseOptions, VolarCompileFn } from '@tsrx/core/types';
|
|
|
3
3
|
|
|
4
4
|
export function parse(source: string, filename?: string, options?: ParseOptions): Program;
|
|
5
5
|
|
|
6
|
+
export { isRefProp } from './ref.js';
|
|
7
|
+
|
|
6
8
|
export const compile: CompileFn;
|
|
7
9
|
|
|
8
10
|
export const compile_to_volar_mappings: VolarCompileFn;
|
package/types/ref.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@tsrx/core/runtime/ref';
|