@tsrx/solid 0.0.17 → 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 -2
- package/src/index.js +19 -4
- package/src/transform.js +78 -128
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.19",
|
|
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.19"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"solid-js": ">=1.8 || >=2.0.0-beta"
|
package/src/index.js
CHANGED
|
@@ -26,9 +26,19 @@ export function parse(source, filename, options) {
|
|
|
26
26
|
*/
|
|
27
27
|
export function compile(source, filename, options) {
|
|
28
28
|
const errors = /** @type {CompileError[]} */ ([]);
|
|
29
|
+
const comments = /** @type {AST.CommentWithLocation[]} */ ([]);
|
|
29
30
|
const collect = !!options?.loose;
|
|
30
|
-
const ast = parseModule(
|
|
31
|
-
|
|
31
|
+
const ast = parseModule(
|
|
32
|
+
source,
|
|
33
|
+
filename,
|
|
34
|
+
collect ? { loose: true, errors, comments } : undefined,
|
|
35
|
+
);
|
|
36
|
+
const { ast: _ast, ...result } = transform(
|
|
37
|
+
ast,
|
|
38
|
+
source,
|
|
39
|
+
filename,
|
|
40
|
+
collect ? { loose: true, errors, comments } : undefined,
|
|
41
|
+
);
|
|
32
42
|
return { ...result, errors };
|
|
33
43
|
}
|
|
34
44
|
|
|
@@ -42,8 +52,13 @@ export function compile(source, filename, options) {
|
|
|
42
52
|
*/
|
|
43
53
|
export function compile_to_volar_mappings(source, filename, options) {
|
|
44
54
|
const errors = /** @type {import('@tsrx/core/types').CompileError[]} */ ([]);
|
|
45
|
-
const
|
|
46
|
-
const
|
|
55
|
+
const comments = /** @type {AST.CommentWithLocation[]} */ ([]);
|
|
56
|
+
const ast = parseModule(source, filename, { ...options, errors, comments });
|
|
57
|
+
const transformed = transform(ast, source, filename, {
|
|
58
|
+
loose: true,
|
|
59
|
+
errors,
|
|
60
|
+
comments,
|
|
61
|
+
});
|
|
47
62
|
const result = createVolarMappingsResult({
|
|
48
63
|
ast: transformed.ast,
|
|
49
64
|
ast_from_source: ast,
|
package/src/transform.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
/** @import * as AST from 'estree' */
|
|
2
2
|
/** @import * as ESTreeJSX from 'estree-jsx' */
|
|
3
|
+
/** @import { JsxTransformContext } from '@tsrx/core/types' */
|
|
3
4
|
|
|
4
5
|
import {
|
|
5
6
|
createJsxTransform,
|
|
7
|
+
error,
|
|
8
|
+
mergeDuplicateRefs,
|
|
9
|
+
toJsxAttribute,
|
|
10
|
+
validateAtMostOneRefAttribute,
|
|
6
11
|
setLocation,
|
|
7
12
|
applyLazyTransforms as apply_lazy_transforms,
|
|
8
13
|
collectLazyBindingsFromComponent as collect_lazy_bindings_from_component,
|
|
@@ -15,7 +20,6 @@ import {
|
|
|
15
20
|
clone_expression_node,
|
|
16
21
|
clone_identifier,
|
|
17
22
|
clone_jsx_name,
|
|
18
|
-
create_compile_error,
|
|
19
23
|
create_generated_identifier,
|
|
20
24
|
create_null_literal,
|
|
21
25
|
flatten_switch_consequent,
|
|
@@ -28,15 +32,19 @@ import {
|
|
|
28
32
|
} from '@tsrx/core';
|
|
29
33
|
|
|
30
34
|
/**
|
|
31
|
-
*
|
|
35
|
+
* Solid extends the shared `JsxTransformContext` with `needs_*` flags that
|
|
36
|
+
* track which Solid runtime primitives (`Show`, `For`, `Switch`, `Match`,
|
|
37
|
+
* `Errored`, `Loading`) the lowered output requires. The factory seeds these
|
|
38
|
+
* via `hooks.initialState`; everything else (filename, loose, errors,
|
|
39
|
+
* helper_state, …) comes from the shared base.
|
|
40
|
+
*
|
|
41
|
+
* @typedef {JsxTransformContext & {
|
|
32
42
|
* needs_show: boolean,
|
|
33
43
|
* needs_for: boolean,
|
|
34
44
|
* needs_switch: boolean,
|
|
35
45
|
* needs_match: boolean,
|
|
36
46
|
* needs_errored: boolean,
|
|
37
47
|
* needs_loading: boolean,
|
|
38
|
-
* lazy_next_id: number,
|
|
39
|
-
* current_css_hash: string | null,
|
|
40
48
|
* }} TransformContext
|
|
41
49
|
*/
|
|
42
50
|
|
|
@@ -71,6 +79,10 @@ const solid_platform = {
|
|
|
71
79
|
jsx: {
|
|
72
80
|
rewriteClassAttr: false,
|
|
73
81
|
acceptedTsxKinds: ['solid'],
|
|
82
|
+
// Solid's runtime accepts an array of refs natively, so multiple
|
|
83
|
+
// `ref` attributes collapse to `ref={[a, b, ...]}` rather than
|
|
84
|
+
// going through a `mergeRefs` helper.
|
|
85
|
+
multiRefStrategy: 'array',
|
|
74
86
|
},
|
|
75
87
|
validation: {
|
|
76
88
|
requireUseServerForAwait: true,
|
|
@@ -88,14 +100,20 @@ const solid_platform = {
|
|
|
88
100
|
needs_errored: false,
|
|
89
101
|
needs_loading: false,
|
|
90
102
|
}),
|
|
91
|
-
validateComponentAwait: (await_expression, _component,
|
|
103
|
+
validateComponentAwait: (await_expression, _component, ctx, _requires, source) => {
|
|
92
104
|
const await_start = get_await_keyword_start(await_expression, source);
|
|
93
105
|
const adjusted_node = /** @type {any} */ ({
|
|
94
106
|
...await_expression,
|
|
95
107
|
start: await_start,
|
|
96
108
|
end: await_start + 'await'.length,
|
|
97
109
|
});
|
|
98
|
-
|
|
110
|
+
error(
|
|
111
|
+
'`await` is not allowed inside Solid components.',
|
|
112
|
+
ctx?.filename ?? null,
|
|
113
|
+
adjusted_node,
|
|
114
|
+
ctx?.errors,
|
|
115
|
+
ctx?.comments,
|
|
116
|
+
);
|
|
99
117
|
},
|
|
100
118
|
controlFlow: {
|
|
101
119
|
ifStatement: if_statement_to_jsx_child,
|
|
@@ -106,8 +124,12 @@ const solid_platform = {
|
|
|
106
124
|
componentToFunction: (component, ctx) =>
|
|
107
125
|
component_to_function_declaration(component, /** @type {any} */ (ctx)),
|
|
108
126
|
injectImports: (program, ctx) => inject_solid_imports(program, /** @type {any} */ (ctx)),
|
|
109
|
-
transformElementAttributes
|
|
110
|
-
|
|
127
|
+
// `transformElementAttributes` is intentionally omitted: the
|
|
128
|
+
// `transformElement` hook below short-circuits core's element walker
|
|
129
|
+
// before `to_jsx_element` runs, so the dispatch path that would call
|
|
130
|
+
// `transformElementAttributes` is never reached for Solid. Attribute
|
|
131
|
+
// lowering happens in Solid's local `transform_element_attributes`,
|
|
132
|
+
// which `to_jsx_element` and `create_dynamic_jsx_element` call directly.
|
|
111
133
|
transformElement: (inner, ctx, raw_children) =>
|
|
112
134
|
to_jsx_element(/** @type {any} */ (inner), /** @type {any} */ (ctx), raw_children),
|
|
113
135
|
},
|
|
@@ -321,7 +343,7 @@ function to_jsx_child(node, transform_context) {
|
|
|
321
343
|
// containers wrapped. See helpers.js.
|
|
322
344
|
return tsx_node_to_jsx_expression(node, true);
|
|
323
345
|
case 'TsxCompat':
|
|
324
|
-
return tsx_compat_node_to_jsx_expression(node, true);
|
|
346
|
+
return tsx_compat_node_to_jsx_expression(node, transform_context, true);
|
|
325
347
|
case 'Element':
|
|
326
348
|
return to_jsx_element(node, transform_context);
|
|
327
349
|
case 'Text':
|
|
@@ -847,17 +869,24 @@ function try_statement_to_jsx_child(node, transform_context) {
|
|
|
847
869
|
const finalizer = node.finalizer;
|
|
848
870
|
|
|
849
871
|
if (finalizer) {
|
|
850
|
-
|
|
851
|
-
finalizer,
|
|
872
|
+
error(
|
|
852
873
|
'Solid 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.',
|
|
874
|
+
transform_context.filename,
|
|
875
|
+
finalizer,
|
|
876
|
+
transform_context.errors,
|
|
877
|
+
transform_context.comments,
|
|
853
878
|
);
|
|
854
879
|
}
|
|
855
880
|
|
|
856
881
|
if (!pending && !handler) {
|
|
857
|
-
|
|
858
|
-
node,
|
|
882
|
+
error(
|
|
859
883
|
'Component try statements must have a `pending` or `catch` block.',
|
|
884
|
+
transform_context.filename,
|
|
885
|
+
node,
|
|
886
|
+
transform_context.errors,
|
|
887
|
+
transform_context.comments,
|
|
860
888
|
);
|
|
889
|
+
return to_jsx_expression_container(create_null_literal());
|
|
861
890
|
}
|
|
862
891
|
|
|
863
892
|
const try_body_nodes = node.block.body || [];
|
|
@@ -1045,7 +1074,22 @@ function to_jsx_element(node, transform_context, pre_walk_children) {
|
|
|
1045
1074
|
}
|
|
1046
1075
|
|
|
1047
1076
|
if (!node.id) {
|
|
1048
|
-
|
|
1077
|
+
error(
|
|
1078
|
+
TEMPLATE_FRAGMENT_ERROR,
|
|
1079
|
+
transform_context.filename,
|
|
1080
|
+
node,
|
|
1081
|
+
transform_context.errors,
|
|
1082
|
+
transform_context.comments,
|
|
1083
|
+
);
|
|
1084
|
+
return set_loc(
|
|
1085
|
+
/** @type {any} */ ({
|
|
1086
|
+
type: 'JSXFragment',
|
|
1087
|
+
openingFragment: { type: 'JSXOpeningFragment' },
|
|
1088
|
+
closingFragment: { type: 'JSXClosingFragment' },
|
|
1089
|
+
children: [],
|
|
1090
|
+
}),
|
|
1091
|
+
node,
|
|
1092
|
+
);
|
|
1049
1093
|
}
|
|
1050
1094
|
|
|
1051
1095
|
if (is_dynamic_element_id(node.id)) {
|
|
@@ -1175,44 +1219,6 @@ function create_element_children(children, transform_context) {
|
|
|
1175
1219
|
return children.map((/** @type {any} */ child) => to_jsx_child(child, transform_context));
|
|
1176
1220
|
}
|
|
1177
1221
|
|
|
1178
|
-
/**
|
|
1179
|
-
* Attribute transform. Unlike React, Solid uses the native `class` attribute
|
|
1180
|
-
* (not `className`). `RefAttribute` and `SpreadAttribute` nodes are handled
|
|
1181
|
-
* at the element level by {@link transform_element_attributes} so this
|
|
1182
|
-
* function only sees plain attributes.
|
|
1183
|
-
*
|
|
1184
|
-
* @param {any} attr
|
|
1185
|
-
* @returns {any}
|
|
1186
|
-
*/
|
|
1187
|
-
function to_jsx_attribute(attr) {
|
|
1188
|
-
if (!attr) return attr;
|
|
1189
|
-
if (attr.type === 'JSXAttribute' || attr.type === 'JSXSpreadAttribute') return attr;
|
|
1190
|
-
|
|
1191
|
-
const attr_name = attr.name;
|
|
1192
|
-
const name =
|
|
1193
|
-
attr_name && attr_name.type === 'Identifier' ? identifier_to_jsx_name(attr_name) : attr_name;
|
|
1194
|
-
|
|
1195
|
-
let value = attr.value;
|
|
1196
|
-
if (value) {
|
|
1197
|
-
if (value.type === 'Literal' && typeof value.value === 'string') {
|
|
1198
|
-
// Keep string literal as attribute string.
|
|
1199
|
-
} else if (value.type !== 'JSXExpressionContainer') {
|
|
1200
|
-
value = to_jsx_expression_container(value);
|
|
1201
|
-
}
|
|
1202
|
-
}
|
|
1203
|
-
|
|
1204
|
-
return set_loc(
|
|
1205
|
-
/** @type {any} */ ({
|
|
1206
|
-
type: 'JSXAttribute',
|
|
1207
|
-
name,
|
|
1208
|
-
value: value || null,
|
|
1209
|
-
shorthand: false,
|
|
1210
|
-
metadata: { path: [] },
|
|
1211
|
-
}),
|
|
1212
|
-
attr,
|
|
1213
|
-
);
|
|
1214
|
-
}
|
|
1215
|
-
|
|
1216
1222
|
/**
|
|
1217
1223
|
* Detect whether an `Element` node represents a composite component (tag
|
|
1218
1224
|
* name starts with an uppercase letter, or is a member expression like
|
|
@@ -1254,26 +1260,17 @@ function has_text_content_attribute(attributes) {
|
|
|
1254
1260
|
}
|
|
1255
1261
|
|
|
1256
1262
|
/**
|
|
1257
|
-
* Transform a list of raw attributes into JSX attributes
|
|
1258
|
-
* `{ref expr}` handling to the element level.
|
|
1259
|
-
*
|
|
1260
|
-
* `{ref expr}` compiles to `ref={expr}` on both DOM elements and composite
|
|
1261
|
-
* components. On DOM elements, Solid's JSX transform takes over: if `expr`
|
|
1262
|
-
* is a mutable `let`-declared identifier it assigns the element to the
|
|
1263
|
-
* variable; if `expr` is a function (or other callable) it invokes it
|
|
1264
|
-
* with the element. On composite components, `ref` is passed through as a
|
|
1265
|
-
* regular prop; the receiving child can consume it explicitly as
|
|
1266
|
-
* `props.ref` or spread `{...props}` onto a DOM element, where Solid's
|
|
1267
|
-
* spread runtime automatically applies the `ref` entry. Solid's merge
|
|
1268
|
-
* proxies drop Symbol keys, so the Symbol-based forwarding used by
|
|
1269
|
-
* Ripple doesn't port; the Solid target relies on its native `ref` prop
|
|
1270
|
-
* support instead.
|
|
1263
|
+
* Transform a list of raw attributes into JSX attributes.
|
|
1271
1264
|
*
|
|
1272
|
-
*
|
|
1273
|
-
*
|
|
1274
|
-
*
|
|
1275
|
-
*
|
|
1276
|
-
*
|
|
1265
|
+
* Per-attribute conversion (RefAttribute → `ref={expr}`, SpreadAttribute →
|
|
1266
|
+
* `{...expr}`, plain Attribute → JSXAttribute, JSXAttribute pass-through)
|
|
1267
|
+
* is delegated to `@tsrx/core`'s shared {@link toJsxAttribute}. The list
|
|
1268
|
+
* is then run through {@link mergeDuplicateRefs} so multiple ref attributes
|
|
1269
|
+
* on the same element — whether from `{ref expr}` or TSX-style `ref={expr}` —
|
|
1270
|
+
* collapse to a single `ref={[a, b, ...]}` array (the strategy chosen by
|
|
1271
|
+
* Solid's `multiRefStrategy: 'array'`). Solid's runtime iterates array refs
|
|
1272
|
+
* natively, so this works on both DOM elements and composite components
|
|
1273
|
+
* (when the child spreads `props` or forwards `props.ref`).
|
|
1277
1274
|
*
|
|
1278
1275
|
* @param {any[]} raw_attrs
|
|
1279
1276
|
* @param {boolean} is_composite
|
|
@@ -1282,66 +1279,15 @@ function has_text_content_attribute(attributes) {
|
|
|
1282
1279
|
*/
|
|
1283
1280
|
function transform_element_attributes(raw_attrs, is_composite, transform_context) {
|
|
1284
1281
|
void is_composite;
|
|
1285
|
-
|
|
1282
|
+
validateAtMostOneRefAttribute(raw_attrs, /** @type {any} */ (transform_context));
|
|
1286
1283
|
/** @type {any[]} */
|
|
1287
1284
|
const result = [];
|
|
1288
|
-
/** @type {any[]} */
|
|
1289
|
-
const ref_attrs = [];
|
|
1290
1285
|
|
|
1291
1286
|
for (const attr of raw_attrs) {
|
|
1292
1287
|
if (!attr) continue;
|
|
1293
|
-
|
|
1294
|
-
ref_attrs.push(attr);
|
|
1295
|
-
continue;
|
|
1296
|
-
}
|
|
1297
|
-
if (attr.type === 'SpreadAttribute') {
|
|
1298
|
-
result.push(
|
|
1299
|
-
set_loc(
|
|
1300
|
-
/** @type {any} */ ({
|
|
1301
|
-
type: 'JSXSpreadAttribute',
|
|
1302
|
-
argument: attr.argument,
|
|
1303
|
-
}),
|
|
1304
|
-
attr,
|
|
1305
|
-
),
|
|
1306
|
-
);
|
|
1307
|
-
continue;
|
|
1308
|
-
}
|
|
1309
|
-
result.push(to_jsx_attribute(attr));
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
if (ref_attrs.length === 1) {
|
|
1313
|
-
result.push(build_ref_attribute(ref_attrs[0].argument, ref_attrs[0]));
|
|
1314
|
-
} else if (ref_attrs.length > 1) {
|
|
1315
|
-
const array_expr = /** @type {any} */ ({
|
|
1316
|
-
type: 'ArrayExpression',
|
|
1317
|
-
elements: ref_attrs.map((attr) => attr.argument),
|
|
1318
|
-
metadata: { path: [] },
|
|
1319
|
-
});
|
|
1320
|
-
result.push(build_ref_attribute(array_expr, ref_attrs[0]));
|
|
1288
|
+
result.push(toJsxAttribute(attr, /** @type {any} */ (transform_context)));
|
|
1321
1289
|
}
|
|
1322
|
-
|
|
1323
|
-
return result;
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
/**
|
|
1327
|
-
* Build a `ref={expr}` JSX attribute, passing the expression through
|
|
1328
|
-
* unchanged so Solid's JSX transform can apply its normal ref semantics.
|
|
1329
|
-
*
|
|
1330
|
-
* @param {any} argument
|
|
1331
|
-
* @param {any} source_node
|
|
1332
|
-
* @returns {any}
|
|
1333
|
-
*/
|
|
1334
|
-
function build_ref_attribute(argument, source_node) {
|
|
1335
|
-
return set_loc(
|
|
1336
|
-
/** @type {any} */ ({
|
|
1337
|
-
type: 'JSXAttribute',
|
|
1338
|
-
name: { type: 'JSXIdentifier', name: 'ref', metadata: { path: [] } },
|
|
1339
|
-
value: to_jsx_expression_container(argument),
|
|
1340
|
-
shorthand: false,
|
|
1341
|
-
metadata: { path: [] },
|
|
1342
|
-
}),
|
|
1343
|
-
source_node,
|
|
1344
|
-
);
|
|
1290
|
+
return mergeDuplicateRefs(result, /** @type {any} */ (transform_context));
|
|
1345
1291
|
}
|
|
1346
1292
|
|
|
1347
1293
|
/**
|
|
@@ -1493,14 +1439,18 @@ function build_return_expression(render_nodes) {
|
|
|
1493
1439
|
|
|
1494
1440
|
/**
|
|
1495
1441
|
* @param {any} node
|
|
1442
|
+
* @param {TransformContext} transform_context
|
|
1496
1443
|
* @param {boolean} [in_jsx_child]
|
|
1497
1444
|
* @returns {any}
|
|
1498
1445
|
*/
|
|
1499
|
-
function tsx_compat_node_to_jsx_expression(node, in_jsx_child = false) {
|
|
1446
|
+
function tsx_compat_node_to_jsx_expression(node, transform_context, in_jsx_child = false) {
|
|
1500
1447
|
if (node.kind !== 'solid') {
|
|
1501
|
-
|
|
1502
|
-
node,
|
|
1448
|
+
error(
|
|
1503
1449
|
`Solid TSRX does not support <tsx:${node.kind}> blocks. Use <tsx> or <tsx:solid>.`,
|
|
1450
|
+
transform_context.filename,
|
|
1451
|
+
node,
|
|
1452
|
+
transform_context.errors,
|
|
1453
|
+
transform_context.comments,
|
|
1504
1454
|
);
|
|
1505
1455
|
}
|
|
1506
1456
|
return tsx_node_to_jsx_expression(node, in_jsx_child);
|