@tsrx/react 0.1.0 → 0.1.2
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 +16 -133
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "React compiler built on @tsrx/core",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Dominic Gannaway",
|
|
6
|
-
"version": "0.1.
|
|
6
|
+
"version": "0.1.2",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"publishConfig": {
|
|
9
9
|
"access": "public"
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"esrap": "^2.1.0",
|
|
27
27
|
"zimmerframe": "^1.1.2",
|
|
28
|
-
"@tsrx/core": "0.0.
|
|
28
|
+
"@tsrx/core": "0.0.8"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
31
|
"react": ">=18"
|
package/src/transform.js
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
isInterleavedBody as is_interleaved_body_core,
|
|
18
18
|
isCapturableJsxChild as is_capturable_jsx_child,
|
|
19
19
|
captureJsxChild,
|
|
20
|
+
isHoistSafeJsxNode as is_hoist_safe_jsx_node,
|
|
20
21
|
} from '@tsrx/core';
|
|
21
22
|
|
|
22
23
|
/**
|
|
@@ -894,116 +895,6 @@ function references_scope_bindings(node, scope_bindings) {
|
|
|
894
895
|
return false;
|
|
895
896
|
}
|
|
896
897
|
|
|
897
|
-
/**
|
|
898
|
-
* @param {AST.Literal} node
|
|
899
|
-
* @returns {boolean}
|
|
900
|
-
*/
|
|
901
|
-
function is_static_literal(node) {
|
|
902
|
-
return (
|
|
903
|
-
node.value === null ||
|
|
904
|
-
typeof node.value === 'string' ||
|
|
905
|
-
typeof node.value === 'number' ||
|
|
906
|
-
typeof node.value === 'boolean' ||
|
|
907
|
-
typeof node.value === 'bigint'
|
|
908
|
-
);
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
/**
|
|
912
|
-
* @param {any} node
|
|
913
|
-
* @returns {boolean}
|
|
914
|
-
*/
|
|
915
|
-
function is_hoist_safe_expression(node) {
|
|
916
|
-
if (!node || typeof node !== 'object') return false;
|
|
917
|
-
|
|
918
|
-
switch (node.type) {
|
|
919
|
-
case 'Literal':
|
|
920
|
-
return is_static_literal(node);
|
|
921
|
-
case 'TemplateLiteral':
|
|
922
|
-
return node.expressions.length === 0;
|
|
923
|
-
case 'UnaryExpression':
|
|
924
|
-
return node.operator !== 'delete' && is_hoist_safe_expression(node.argument);
|
|
925
|
-
case 'BinaryExpression':
|
|
926
|
-
case 'LogicalExpression':
|
|
927
|
-
return is_hoist_safe_expression(node.left) && is_hoist_safe_expression(node.right);
|
|
928
|
-
case 'ConditionalExpression':
|
|
929
|
-
return (
|
|
930
|
-
is_hoist_safe_expression(node.test) &&
|
|
931
|
-
is_hoist_safe_expression(node.consequent) &&
|
|
932
|
-
is_hoist_safe_expression(node.alternate)
|
|
933
|
-
);
|
|
934
|
-
case 'SequenceExpression':
|
|
935
|
-
return node.expressions.every(is_hoist_safe_expression);
|
|
936
|
-
case 'ParenthesizedExpression':
|
|
937
|
-
return is_hoist_safe_expression(node.expression);
|
|
938
|
-
case 'JSXElement':
|
|
939
|
-
return is_hoist_safe_jsx_node(node);
|
|
940
|
-
case 'JSXFragment':
|
|
941
|
-
return node.children.every(is_hoist_safe_jsx_child);
|
|
942
|
-
default:
|
|
943
|
-
return false;
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
/**
|
|
948
|
-
* @param {any} node
|
|
949
|
-
* @returns {boolean}
|
|
950
|
-
*/
|
|
951
|
-
function is_hoist_safe_jsx_child(node) {
|
|
952
|
-
if (!node || typeof node !== 'object') return false;
|
|
953
|
-
|
|
954
|
-
switch (node.type) {
|
|
955
|
-
case 'JSXText':
|
|
956
|
-
return true;
|
|
957
|
-
case 'JSXElement':
|
|
958
|
-
return is_hoist_safe_jsx_node(node);
|
|
959
|
-
case 'JSXFragment':
|
|
960
|
-
return node.children.every(is_hoist_safe_jsx_child);
|
|
961
|
-
case 'JSXExpressionContainer':
|
|
962
|
-
return (
|
|
963
|
-
node.expression.type !== 'JSXEmptyExpression' && is_hoist_safe_expression(node.expression)
|
|
964
|
-
);
|
|
965
|
-
default:
|
|
966
|
-
return false;
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
/**
|
|
971
|
-
* @param {ESTreeJSX.JSXAttribute | ESTreeJSX.JSXSpreadAttribute} attribute
|
|
972
|
-
* @returns {boolean}
|
|
973
|
-
*/
|
|
974
|
-
function is_hoist_safe_jsx_attribute(attribute) {
|
|
975
|
-
if (attribute.type === 'JSXSpreadAttribute') return false;
|
|
976
|
-
if (attribute.value == null) return true;
|
|
977
|
-
|
|
978
|
-
if (attribute.value.type === 'Literal') {
|
|
979
|
-
return is_static_literal(attribute.value);
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
if (attribute.value.type === 'JSXExpressionContainer') {
|
|
983
|
-
return (
|
|
984
|
-
attribute.value.expression.type !== 'JSXEmptyExpression' &&
|
|
985
|
-
is_hoist_safe_expression(attribute.value.expression)
|
|
986
|
-
);
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
return false;
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
/**
|
|
993
|
-
* @param {ESTreeJSX.JSXElement | ESTreeJSX.JSXFragment} node
|
|
994
|
-
* @returns {boolean}
|
|
995
|
-
*/
|
|
996
|
-
function is_hoist_safe_jsx_node(node) {
|
|
997
|
-
if (node.type === 'JSXFragment') {
|
|
998
|
-
return node.children.every(is_hoist_safe_jsx_child);
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
return (
|
|
1002
|
-
node.openingElement.attributes.every(is_hoist_safe_jsx_attribute) &&
|
|
1003
|
-
node.children.every(is_hoist_safe_jsx_child)
|
|
1004
|
-
);
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
898
|
/**
|
|
1008
899
|
* Hoist static JSX elements from render_nodes to module level.
|
|
1009
900
|
* A JSX element is static if it doesn't reference any component-scope bindings.
|
|
@@ -1200,6 +1091,9 @@ function is_jsx_child(node) {
|
|
|
1200
1091
|
);
|
|
1201
1092
|
}
|
|
1202
1093
|
|
|
1094
|
+
const TEMPLATE_FRAGMENT_ERROR =
|
|
1095
|
+
'JSX fragment syntax is not needed in TSRX templates. TSRX renders in immediate mode, so everything is already a fragment. Use `<>...</>` only within <tsx>...</tsx>.';
|
|
1096
|
+
|
|
1203
1097
|
/**
|
|
1204
1098
|
* @param {any} node
|
|
1205
1099
|
* @param {TransformContext} transform_context
|
|
@@ -1212,23 +1106,13 @@ function to_jsx_element(node, transform_context) {
|
|
|
1212
1106
|
'`{html ...}` is not supported on the React target. Use `dangerouslySetInnerHTML={{ __html: ... }}` as an element attribute instead.',
|
|
1213
1107
|
);
|
|
1214
1108
|
}
|
|
1109
|
+
if (!node.id) {
|
|
1110
|
+
throw create_compile_error(node, TEMPLATE_FRAGMENT_ERROR);
|
|
1111
|
+
}
|
|
1215
1112
|
if (is_dynamic_element_id(node.id)) {
|
|
1216
1113
|
return dynamic_element_to_jsx_child(node, transform_context);
|
|
1217
1114
|
}
|
|
1218
1115
|
|
|
1219
|
-
if (!node.id) {
|
|
1220
|
-
const children = create_element_children(node.children || [], transform_context);
|
|
1221
|
-
return set_loc(
|
|
1222
|
-
/** @type {any} */ ({
|
|
1223
|
-
type: 'JSXFragment',
|
|
1224
|
-
openingFragment: { type: 'JSXOpeningFragment' },
|
|
1225
|
-
closingFragment: { type: 'JSXClosingFragment' },
|
|
1226
|
-
children,
|
|
1227
|
-
}),
|
|
1228
|
-
node,
|
|
1229
|
-
);
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
1116
|
const name = identifier_to_jsx_name(node.id);
|
|
1233
1117
|
const attributes = (node.attributes || []).map(to_jsx_attribute);
|
|
1234
1118
|
const selfClosing = !!node.selfClosing;
|
|
@@ -1712,24 +1596,23 @@ function for_of_statement_to_jsx_child(node, transform_context) {
|
|
|
1712
1596
|
);
|
|
1713
1597
|
}
|
|
1714
1598
|
|
|
1715
|
-
if (node.key) {
|
|
1716
|
-
throw create_compile_error(
|
|
1717
|
-
node.key,
|
|
1718
|
-
'React TSRX does not support `key` in `for` control flow. Put the key on the rendered element instead, for example `<div key={i}>...</div>`.',
|
|
1719
|
-
);
|
|
1720
|
-
}
|
|
1721
|
-
|
|
1722
1599
|
const loop_params = get_for_of_iteration_params(node.left, node.index);
|
|
1723
1600
|
const loop_body = node.body.type === 'BlockStatement' ? node.body.body : [node.body];
|
|
1724
1601
|
const has_hooks = body_contains_top_level_hook_call(loop_body);
|
|
1725
|
-
const
|
|
1602
|
+
const body_key_expression = find_key_expression_in_body(loop_body);
|
|
1603
|
+
const explicit_key_expression =
|
|
1604
|
+
body_key_expression ?? (node.key ? clone_expression_node(node.key) : undefined);
|
|
1726
1605
|
const key_expression =
|
|
1727
1606
|
has_hooks && explicit_key_expression == null && node.index
|
|
1728
1607
|
? clone_expression_node(node.index)
|
|
1729
1608
|
: explicit_key_expression;
|
|
1730
1609
|
const implicit_non_hook_key_expression =
|
|
1731
|
-
!has_hooks &&
|
|
1732
|
-
?
|
|
1610
|
+
!has_hooks && body_key_expression == null
|
|
1611
|
+
? node.key
|
|
1612
|
+
? clone_expression_node(node.key)
|
|
1613
|
+
: node.index
|
|
1614
|
+
? clone_expression_node(node.index)
|
|
1615
|
+
: undefined
|
|
1733
1616
|
: undefined;
|
|
1734
1617
|
|
|
1735
1618
|
// Add loop params to available bindings so hoisted helpers receive them as props
|