@tsrx/react 0.1.0 → 0.1.1

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.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/src/transform.js +10 -120
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.0",
6
+ "version": "0.1.1",
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.6"
28
+ "@tsrx/core": "0.0.7"
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.
@@ -1712,24 +1603,23 @@ function for_of_statement_to_jsx_child(node, transform_context) {
1712
1603
  );
1713
1604
  }
1714
1605
 
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
1606
  const loop_params = get_for_of_iteration_params(node.left, node.index);
1723
1607
  const loop_body = node.body.type === 'BlockStatement' ? node.body.body : [node.body];
1724
1608
  const has_hooks = body_contains_top_level_hook_call(loop_body);
1725
- const explicit_key_expression = has_hooks ? find_key_expression_in_body(loop_body) : undefined;
1609
+ const body_key_expression = find_key_expression_in_body(loop_body);
1610
+ const explicit_key_expression =
1611
+ body_key_expression ?? (node.key ? clone_expression_node(node.key) : undefined);
1726
1612
  const key_expression =
1727
1613
  has_hooks && explicit_key_expression == null && node.index
1728
1614
  ? clone_expression_node(node.index)
1729
1615
  : explicit_key_expression;
1730
1616
  const implicit_non_hook_key_expression =
1731
- !has_hooks && node.index && find_key_expression_in_body(loop_body) == null
1732
- ? clone_expression_node(node.index)
1617
+ !has_hooks && body_key_expression == null
1618
+ ? node.key
1619
+ ? clone_expression_node(node.key)
1620
+ : node.index
1621
+ ? clone_expression_node(node.index)
1622
+ : undefined
1733
1623
  : undefined;
1734
1624
 
1735
1625
  // Add loop params to available bindings so hoisted helpers receive them as props