@tsrx/core 0.1.18 → 0.1.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 CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Core compiler infrastructure for TSRX syntax",
4
4
  "license": "MIT",
5
5
  "author": "Dominic Gannaway",
6
- "version": "0.1.18",
6
+ "version": "0.1.19",
7
7
  "type": "module",
8
8
  "repository": {
9
9
  "type": "git",
package/src/index.js CHANGED
@@ -162,7 +162,6 @@ export {
162
162
  validate_at_most_one_ref_attribute as validateAtMostOneRefAttribute,
163
163
  } from './transform/jsx/index.js';
164
164
  export {
165
- ensure_function_metadata as ensureFunctionMetadata,
166
165
  in_jsx_child_context as inJsxChildContext,
167
166
  tsx_node_to_jsx_expression as tsxNodeToJsxExpression,
168
167
  tsx_with_ts_locations as tsxWithTsLocations,
@@ -17,6 +17,23 @@ export function in_jsx_child_context(path) {
17
17
  return !!parent && parent.type === 'Element';
18
18
  }
19
19
 
20
+ /**
21
+ * Match Ripple's transform path metadata shape: every node seen by the walker
22
+ * carries its current ancestor path for downstream CSS pruning and mapping
23
+ * helpers.
24
+ *
25
+ * @param {any} node
26
+ * @param {any[]} path
27
+ * @returns {void}
28
+ */
29
+ export function set_node_path_metadata(node, path) {
30
+ if (!node.metadata) {
31
+ node.metadata = { path: [...path] };
32
+ } else {
33
+ node.metadata.path = [...path];
34
+ }
35
+ }
36
+
20
37
  /**
21
38
  * Flatten a `<tsx>` / fragment node's children into a single expression. In a
22
39
  * JSX-child position, a JSXExpressionContainer `{expr}` is valid and must stay
@@ -49,25 +66,6 @@ export function tsx_node_to_jsx_expression(node, in_jsx_child = false) {
49
66
  });
50
67
  }
51
68
 
52
- /**
53
- * Default `node.metadata` to `{ path: [] }` if missing, then continue the
54
- * walk. Use as the `FunctionDeclaration` / `FunctionExpression` /
55
- * `ArrowFunctionExpression` visitor in a zimmerframe walk so that downstream
56
- * consumers don't trip on an undefined metadata object.
57
- *
58
- * Ripple's analyze phase does this via `visit_function`; the tsrx-* targets
59
- * have no analyze phase, so we default metadata during the main walk.
60
- *
61
- * @param {any} node
62
- * @param {{ next: () => any }} ctx
63
- */
64
- export function ensure_function_metadata(node, { next }) {
65
- if (!node.metadata) {
66
- node.metadata = { path: [] };
67
- }
68
- return next();
69
- }
70
-
71
69
  /**
72
70
  * Wrap esrap's `tsx()` printer with location markers for nodes whose spans
73
71
  * (e.g. the leading `new ` of a NewExpression or the angle-bracket delimiters
@@ -8,8 +8,8 @@ import { error } from '../../errors.js';
8
8
  import { analyze_css } from '../../analyze/css-analyze.js';
9
9
  import { prune_css } from '../../analyze/prune.js';
10
10
  import {
11
- ensure_function_metadata,
12
11
  in_jsx_child_context,
12
+ set_node_path_metadata,
13
13
  tsx_node_to_jsx_expression,
14
14
  tsx_with_ts_locations,
15
15
  } from './helpers.js';
@@ -169,6 +169,8 @@ export function createJsxTransform(platform) {
169
169
  const collect = !!(options?.collect || options?.loose);
170
170
  /** @type {any[]} */
171
171
  const stylesheets = [];
172
+ /** @type {AST.Statement[]} */
173
+ const type_only_style_anchors = [];
172
174
 
173
175
  /** @type {TransformContext} */
174
176
  const transform_context = {
@@ -183,6 +185,7 @@ export function createJsxTransform(platform) {
183
185
  needs_for_of_iterable: false,
184
186
  needs_iteration_value_type: false,
185
187
  stylesheets,
188
+ type_only_style_anchors,
186
189
  module_scoped_hook_components:
187
190
  options?.moduleScopedHookComponents ?? !!platform.hooks?.moduleScopedHookComponents,
188
191
  helper_state: null,
@@ -204,13 +207,12 @@ export function createJsxTransform(platform) {
204
207
  preallocate_lazy_ids(/** @type {any} */ (ast), transform_context);
205
208
  }
206
209
 
207
- walk(/** @type {any} */ (ast), transform_context, {
208
- FunctionDeclaration: collect_native_function_tsrx_metadata,
209
- FunctionExpression: collect_native_function_tsrx_metadata,
210
- ArrowFunctionExpression: collect_native_function_tsrx_metadata,
211
- });
212
-
213
210
  const transformed = walk(/** @type {any} */ (ast), transform_context, {
211
+ _(node, { next, path }) {
212
+ set_node_path_metadata(node, path);
213
+ return next();
214
+ },
215
+
214
216
  Tsx(node, { next, path }) {
215
217
  const inner = /** @type {any} */ (next() ?? node);
216
218
  const in_jsx_child = in_jsx_child_context(path);
@@ -219,27 +221,24 @@ export function createJsxTransform(platform) {
219
221
  );
220
222
  },
221
223
 
222
- Tsrx(node, { next, path, state }) {
223
- /** @type {{ css: any, style_refs: any[] } | null} */
224
- let style_context = null;
225
- const inner = with_tsrx_fragment_styles(node, state, (context) => {
226
- style_context = context;
227
- return next() ?? node;
228
- });
224
+ Tsrx(node, { next, path, state, visit }) {
225
+ const parent = /** @type {AST.ArrowFunctionExpression} */ (path.at(-1));
226
+ if (parent?.metadata?.native_tsrx && parent.body === node) {
227
+ return /** @type {any} */ (visit(create_native_tsrx_render_block(node, state), state));
228
+ }
229
+
230
+ const style_context = prepare_tsrx_fragment_styles(node, state);
231
+ const target = style_context?.fragment ?? next() ?? node;
232
+ const in_jsx_child = in_jsx_child_context(path);
233
+ const expression = tsrx_node_to_jsx_expression(target, state, in_jsx_child);
229
234
  for (const statement of create_tsrx_style_ref_setup_statements(
230
- node,
235
+ target,
231
236
  style_context,
232
237
  state,
233
238
  )) {
234
- add_jsx_setup_declaration(inner, statement);
239
+ add_jsx_setup_declaration(expression, statement);
235
240
  }
236
- const in_jsx_child = in_jsx_child_context(path);
237
- return /** @type {any} */ (
238
- wrap_jsx_setup_declarations(
239
- tsrx_node_to_jsx_expression(inner, state, in_jsx_child),
240
- in_jsx_child,
241
- )
242
- );
241
+ return /** @type {any} */ (wrap_jsx_setup_declarations(expression, in_jsx_child));
243
242
  },
244
243
 
245
244
  TsxCompat(node, { next, path, state }) {
@@ -259,7 +258,7 @@ export function createJsxTransform(platform) {
259
258
  if (stylesheet) {
260
259
  analyze_css(stylesheet);
261
260
  state.stylesheets.push(stylesheet);
262
- return /** @type {any} */ (create_style_class_map_from_stylesheet(stylesheet));
261
+ return /** @type {any} */ (create_style_expression_value(node, stylesheet, state));
263
262
  }
264
263
  }
265
264
 
@@ -288,9 +287,9 @@ export function createJsxTransform(platform) {
288
287
  return /** @type {any} */ (to_jsx_expression_container(inner.expression, inner));
289
288
  },
290
289
 
291
- // Default .metadata on every function-like node so downstream consumers
292
- // do not trip on an undefined metadata object. Ripple's analyze phase
293
- // does this via visit_function; tsrx-react has no analyze phase.
290
+ BlockStatement: transform_block_statement,
291
+ ReturnStatement: transform_return_statement,
292
+
294
293
  // If an uppercase JS function contains hook-bearing TSRX, give it a
295
294
  // temporary helper scope so extracted hook helpers get stable identities.
296
295
  FunctionDeclaration: transform_function,
@@ -303,17 +302,24 @@ export function createJsxTransform(platform) {
303
302
  return visited;
304
303
  }
305
304
  const is_component = is_component_like_jsx_name(visited.name);
306
- return {
307
- ...visited,
308
- attributes: merge_duplicate_refs(
305
+ return b.jsx_opening_element(
306
+ visited.name,
307
+ merge_duplicate_refs(
309
308
  normalize_host_ref_spreads(visited.attributes || [], !is_component, transform_context),
310
309
  transform_context,
311
310
  ),
312
- };
311
+ visited.selfClosing,
312
+ visited.typeArguments,
313
+ visited,
314
+ );
313
315
  },
314
316
  });
315
317
 
316
- const expanded = expand_component_helpers(/** @type {AST.Program} */ (transformed));
318
+ const transformed_program = /** @type {AST.Program} */ (transformed);
319
+ if (type_only_style_anchors.length > 0) {
320
+ transformed_program.body.unshift(...type_only_style_anchors);
321
+ }
322
+ const expanded = expand_component_helpers(transformed_program);
317
323
  if (platform.hooks?.injectImports) {
318
324
  platform.hooks.injectImports(expanded, transform_context, suspense_source);
319
325
  } else {
@@ -593,48 +599,56 @@ function is_interleaved_body(body_nodes) {
593
599
  * @param {TransformContext} transform_context
594
600
  * @returns {boolean}
595
601
  */
596
- function function_needs_component_body_hook_split(node, transform_context) {
602
+ function needs_hook_split(node, transform_context) {
597
603
  return (
598
604
  transform_context.platform.hooks?.componentBodyHookHelpers === true &&
599
605
  node.body?.type === 'BlockStatement' &&
600
- find_component_body_hook_split_index(node.body.body || [], transform_context) !== -1
606
+ find_hook_split_index(node.body.body || [], transform_context) !== -1
601
607
  );
602
608
  }
603
609
 
604
610
  /**
605
611
  * @param {any} node
606
612
  * @param {TransformContext} transform_context
607
- * @returns {void}
613
+ * @returns {any}
608
614
  */
609
- function rewrite_component_body_conditional_hook_splits(node, transform_context) {
615
+ function create_hook_split_block(node, transform_context) {
610
616
  if (
611
617
  transform_context.platform.hooks?.componentBodyHookHelpers !== true ||
612
618
  !should_extract_hook_helpers(transform_context) ||
613
619
  node.body?.type !== 'BlockStatement'
614
620
  ) {
615
- return;
621
+ return null;
616
622
  }
617
623
 
618
624
  const body = node.body.body || [];
619
- const split_index = find_component_body_hook_split_index(body, transform_context);
625
+ const split_index = find_hook_split_index(body, transform_context);
620
626
  if (split_index === -1) {
621
- return;
627
+ return null;
622
628
  }
623
629
 
624
630
  const split_statement = body[split_index];
625
631
  const continuation_body = body.slice(split_index + 1);
626
632
  const helper = create_hook_safe_helper(
627
- continuation_body,
633
+ expand_native_tsrx_return_statement_list(continuation_body, transform_context),
628
634
  undefined,
629
635
  get_body_source_node(continuation_body) || split_statement,
630
636
  transform_context,
631
637
  );
632
638
 
633
- node.body.body = [
634
- ...body.slice(0, split_index + 1),
635
- ...helper.setup_statements,
636
- set_loc(b.return(helper.component_element), split_statement),
637
- ];
639
+ const block = b.block(
640
+ [
641
+ ...body.slice(0, split_index + 1),
642
+ ...helper.setup_statements,
643
+ set_loc(b.return(helper.component_element), split_statement),
644
+ ],
645
+ node.body,
646
+ );
647
+ block.metadata = {
648
+ ...(block.metadata || {}),
649
+ hook_split_block: true,
650
+ };
651
+ return block;
638
652
  }
639
653
 
640
654
  /**
@@ -642,7 +656,7 @@ function rewrite_component_body_conditional_hook_splits(node, transform_context)
642
656
  * @param {TransformContext} transform_context
643
657
  * @returns {number}
644
658
  */
645
- function find_component_body_hook_split_index(body_nodes, transform_context) {
659
+ function find_hook_split_index(body_nodes, transform_context) {
646
660
  for (let i = 0; i < body_nodes.length; i += 1) {
647
661
  if (!is_component_body_conditional_return_statement(body_nodes[i])) {
648
662
  continue;
@@ -945,22 +959,82 @@ function create_helper_state(base_name) {
945
959
  };
946
960
  }
947
961
 
962
+ /**
963
+ * @param {{ helpers: any[], statics: any[] }} helper_state
964
+ * @returns {{ generated_helpers: any[], generated_statics: any[] } | null}
965
+ */
966
+ function create_generated_helper_metadata(helper_state) {
967
+ if (helper_state.helpers.length === 0 && helper_state.statics.length === 0) {
968
+ return null;
969
+ }
970
+ return {
971
+ generated_helpers: helper_state.helpers,
972
+ generated_statics: helper_state.statics,
973
+ };
974
+ }
975
+
976
+ /**
977
+ * @param {any} metadata
978
+ * @returns {any}
979
+ */
980
+ function strip_function_transform_metadata(metadata) {
981
+ const { native_tsrx, hook_split, ...next_metadata } = metadata || {};
982
+ return next_metadata;
983
+ }
984
+
985
+ /**
986
+ * @param {AST.BlockStatement} node
987
+ * @param {{ next: () => any, visit: (node: any, state?: TransformContext) => any, state: TransformContext, path: AST.Node[] }} context
988
+ * @returns {any}
989
+ */
990
+ function transform_block_statement(node, { next, visit, state, path }) {
991
+ if (node.metadata?.hook_split_block || node.metadata?.native_return_block) {
992
+ return next() ?? node;
993
+ }
994
+
995
+ const parent = /** @type {any} */ (path.at(-1));
996
+ if (parent?.metadata?.hook_split && parent.body === node) {
997
+ const block = create_hook_split_block(parent, state);
998
+ if (block) {
999
+ return visit(block, state);
1000
+ }
1001
+ }
1002
+
1003
+ if (get_active_native_tsrx_function(path)) {
1004
+ const block = create_native_tsrx_statement_list_block(node, state);
1005
+ if (block) {
1006
+ return visit(block, state);
1007
+ }
1008
+ }
1009
+
1010
+ return next() ?? node;
1011
+ }
1012
+
948
1013
  /**
949
1014
  * @param {any} node
950
- * @param {{ next: (state?: TransformContext) => any, state: TransformContext }} context
1015
+ * @param {{ next: () => any, visit: (node: any, state?: TransformContext) => any, state: TransformContext, path: AST.Node[] }} context
951
1016
  * @returns {any}
952
1017
  */
953
- function collect_native_function_tsrx_metadata(node, { next, state }) {
954
- if (!function_has_native_tsrx_return(node)) {
955
- return next(state);
1018
+ function transform_return_statement(node, { next, visit, state, path }) {
1019
+ if (get_active_native_tsrx_function(path) && node.argument?.type === 'Tsrx') {
1020
+ return visit(create_native_tsrx_render_block(node.argument, state), state);
956
1021
  }
957
1022
 
958
- node.metadata = {
959
- ...(node.metadata || {}),
960
- native_tsrx_function: true,
961
- };
1023
+ return next() ?? node;
1024
+ }
962
1025
 
963
- return next(state);
1026
+ /**
1027
+ * @param {AST.Node[]} path
1028
+ * @returns {any | null}
1029
+ */
1030
+ function get_active_native_tsrx_function(path) {
1031
+ for (let i = path.length - 1; i >= 0; i -= 1) {
1032
+ const node = /** @type {any} */ (path[i]);
1033
+ if (is_function_or_class_boundary(node)) {
1034
+ return node.metadata?.native_tsrx ? node : null;
1035
+ }
1036
+ }
1037
+ return null;
964
1038
  }
965
1039
 
966
1040
  /**
@@ -978,47 +1052,49 @@ function transform_function(node, context) {
978
1052
 
979
1053
  /**
980
1054
  * @param {any} node
981
- * @param {{ next: () => any, state: TransformContext, path: AST.Node[] }} context
1055
+ * @param {{ next: () => any, state: TransformContext }} context
982
1056
  * @returns {any}
983
1057
  */
984
- function transform_native_tsrx_function(node, { next, state, path }) {
1058
+ function transform_native_tsrx_function(node, { next, state }) {
985
1059
  const helper_state =
986
- state.helper_state || create_helper_state(get_function_helper_base_name(node, path));
1060
+ state.helper_state || create_helper_state(get_function_helper_base_name(node));
987
1061
  const saved_helper_state = state.helper_state;
988
1062
  const saved_bindings = state.available_bindings;
989
1063
  const saved_hook_helpers_enabled = state.hook_helpers_enabled;
990
1064
 
991
1065
  state.helper_state = helper_state;
992
- state.hook_helpers_enabled = is_uppercase_function_like(node, path);
1066
+ state.hook_helpers_enabled = is_uppercase_function_like(node);
1067
+ node.metadata = {
1068
+ ...(node.metadata || {}),
1069
+ native_tsrx: true,
1070
+ ...(needs_hook_split(node, state) ? { hook_split: true } : {}),
1071
+ };
993
1072
  state.available_bindings = merge_binding_maps(
994
1073
  saved_bindings,
995
1074
  collect_function_scope_bindings(node),
996
1075
  );
997
1076
 
998
- validate_native_tsrx_function_await(node, state);
999
- expand_native_tsrx_function_returns(node, state);
1000
- rewrite_component_body_conditional_hook_splits(node, state);
1077
+ validate_native_await(node, state);
1001
1078
 
1002
1079
  const inner = /** @type {any} */ (next() ?? node);
1080
+ if (
1081
+ inner !== node &&
1082
+ node.type === 'ArrowFunctionExpression' &&
1083
+ node.body?.type === 'Tsrx' &&
1084
+ inner.body?.type === 'BlockStatement'
1085
+ ) {
1086
+ inner.expression = false;
1087
+ }
1003
1088
 
1004
1089
  state.helper_state = saved_helper_state;
1005
1090
  state.available_bindings = saved_bindings;
1006
1091
  state.hook_helpers_enabled = saved_hook_helpers_enabled;
1007
1092
 
1008
- ensure_function_metadata(inner, { next: () => inner });
1009
1093
  inner.metadata = {
1010
- ...(inner.metadata || {}),
1094
+ ...strip_function_transform_metadata(inner.metadata),
1011
1095
  native_tsrx_function: true,
1096
+ ...(!saved_helper_state ? create_generated_helper_metadata(helper_state) || {} : {}),
1012
1097
  };
1013
- if (!saved_helper_state && (helper_state.helpers.length || helper_state.statics.length)) {
1014
- inner.metadata.generated_helpers = helper_state.helpers;
1015
- inner.metadata.generated_statics = helper_state.statics;
1016
- }
1017
-
1018
- const wrapped = state.platform.hooks?.wrapNativeFunctionComponent?.(inner, state, path);
1019
- if (wrapped) {
1020
- return wrapped;
1021
- }
1022
1098
 
1023
1099
  return inner;
1024
1100
  }
@@ -1028,8 +1104,8 @@ function transform_native_tsrx_function(node, { next, state, path }) {
1028
1104
  * @param {TransformContext} transform_context
1029
1105
  * @returns {void}
1030
1106
  */
1031
- function validate_native_tsrx_function_await(node, transform_context) {
1032
- const await_node = find_first_top_level_await_in_native_tsrx_function(node);
1107
+ function validate_native_await(node, transform_context) {
1108
+ const await_node = find_native_await(node);
1033
1109
  if (!await_node) {
1034
1110
  return;
1035
1111
  }
@@ -1055,7 +1131,7 @@ function validate_native_tsrx_function_await(node, transform_context) {
1055
1131
  * @param {any} node
1056
1132
  * @returns {any | null}
1057
1133
  */
1058
- function find_first_top_level_await_in_native_tsrx_function(node) {
1134
+ function find_native_await(node) {
1059
1135
  if (
1060
1136
  node.type === 'ArrowFunctionExpression' &&
1061
1137
  node.body?.type !== 'BlockStatement' &&
@@ -1065,16 +1141,16 @@ function find_first_top_level_await_in_native_tsrx_function(node) {
1065
1141
  }
1066
1142
 
1067
1143
  const body = node.body?.type === 'BlockStatement' ? node.body.body || [] : [];
1068
- return find_first_top_level_await_in_native_tsrx_statements(body);
1144
+ return find_native_await_in_list(body);
1069
1145
  }
1070
1146
 
1071
1147
  /**
1072
1148
  * @param {any[]} statements
1073
1149
  * @returns {any | null}
1074
1150
  */
1075
- function find_first_top_level_await_in_native_tsrx_statements(statements) {
1151
+ function find_native_await_in_list(statements) {
1076
1152
  for (const statement of statements) {
1077
- const found = find_first_top_level_await_in_native_tsrx_statement(statement);
1153
+ const found = find_native_await_in_statement(statement);
1078
1154
  if (found) return found;
1079
1155
  }
1080
1156
  return null;
@@ -1084,7 +1160,7 @@ function find_first_top_level_await_in_native_tsrx_statements(statements) {
1084
1160
  * @param {any} statement
1085
1161
  * @returns {any | null}
1086
1162
  */
1087
- function find_first_top_level_await_in_native_tsrx_statement(statement) {
1163
+ function find_native_await_in_statement(statement) {
1088
1164
  if (!statement || typeof statement !== 'object') return null;
1089
1165
 
1090
1166
  if (statement.type === 'ReturnStatement' && statement.argument?.type === 'Tsrx') {
@@ -1103,21 +1179,19 @@ function find_first_top_level_await_in_native_tsrx_statement(statement) {
1103
1179
  }
1104
1180
 
1105
1181
  if (statement.type === 'BlockStatement') {
1106
- return find_first_top_level_await_in_native_tsrx_statements(statement.body || []);
1182
+ return find_native_await_in_list(statement.body || []);
1107
1183
  }
1108
1184
 
1109
1185
  if (statement.type === 'IfStatement') {
1110
1186
  return (
1111
- find_first_top_level_await_in_native_tsrx_statement(statement.consequent) ||
1112
- find_first_top_level_await_in_native_tsrx_statement(statement.alternate)
1187
+ find_native_await_in_statement(statement.consequent) ||
1188
+ find_native_await_in_statement(statement.alternate)
1113
1189
  );
1114
1190
  }
1115
1191
 
1116
1192
  if (statement.type === 'SwitchStatement') {
1117
1193
  for (const switch_case of statement.cases || []) {
1118
- const found = find_first_top_level_await_in_native_tsrx_statements(
1119
- switch_case.consequent || [],
1120
- );
1194
+ const found = find_native_await_in_list(switch_case.consequent || []);
1121
1195
  if (found) return found;
1122
1196
  }
1123
1197
  return null;
@@ -1125,9 +1199,9 @@ function find_first_top_level_await_in_native_tsrx_statement(statement) {
1125
1199
 
1126
1200
  if (statement.type === 'TryStatement') {
1127
1201
  return (
1128
- find_first_top_level_await_in_native_tsrx_statement(statement.block) ||
1129
- find_first_top_level_await_in_native_tsrx_statement(statement.handler?.body) ||
1130
- find_first_top_level_await_in_native_tsrx_statement(statement.finalizer)
1202
+ find_native_await_in_statement(statement.block) ||
1203
+ find_native_await_in_statement(statement.handler?.body) ||
1204
+ find_native_await_in_statement(statement.finalizer)
1131
1205
  );
1132
1206
  }
1133
1207
 
@@ -1136,32 +1210,34 @@ function find_first_top_level_await_in_native_tsrx_statement(statement) {
1136
1210
 
1137
1211
  /**
1138
1212
  * @param {any} node
1139
- * @param {{ next: () => any, state: TransformContext, path: AST.Node[] }} context
1213
+ * @param {{ next: () => any, state: TransformContext }} context
1140
1214
  * @returns {any}
1141
1215
  */
1142
- function transform_function_with_hook_helpers(node, { next, state, path }) {
1216
+ function transform_function_with_hook_helpers(node, { next, state }) {
1143
1217
  const has_hook_bearing_tsrx = function_contains_hook_bearing_tsrx(node, state);
1144
- const has_component_body_hook_split = function_needs_component_body_hook_split(node, state);
1218
+ const has_hook_split = needs_hook_split(node, state);
1145
1219
  if (
1146
1220
  state.helper_state ||
1147
- !is_uppercase_function_like(node, path) ||
1148
- (!has_hook_bearing_tsrx && !has_component_body_hook_split)
1221
+ !is_uppercase_function_like(node) ||
1222
+ (!has_hook_bearing_tsrx && !has_hook_split)
1149
1223
  ) {
1150
- return ensure_function_metadata(node, { next });
1224
+ return next() ?? node;
1151
1225
  }
1152
1226
 
1153
- const helper_state = create_helper_state(get_function_helper_base_name(node, path));
1227
+ const helper_state = create_helper_state(get_function_helper_base_name(node));
1154
1228
  const saved_helper_state = state.helper_state;
1155
1229
  const saved_bindings = state.available_bindings;
1156
1230
  const saved_hook_helpers_enabled = state.hook_helpers_enabled;
1157
1231
 
1158
1232
  state.helper_state = helper_state;
1159
1233
  state.hook_helpers_enabled = true;
1160
- state.available_bindings = collect_function_scope_bindings(node);
1161
-
1162
- if (has_component_body_hook_split) {
1163
- rewrite_component_body_conditional_hook_splits(node, state);
1234
+ if (has_hook_split) {
1235
+ node.metadata = {
1236
+ ...(node.metadata || {}),
1237
+ hook_split: true,
1238
+ };
1164
1239
  }
1240
+ state.available_bindings = collect_function_scope_bindings(node);
1165
1241
 
1166
1242
  const inner = /** @type {any} */ (next() ?? node);
1167
1243
 
@@ -1169,48 +1245,41 @@ function transform_function_with_hook_helpers(node, { next, state, path }) {
1169
1245
  state.available_bindings = saved_bindings;
1170
1246
  state.hook_helpers_enabled = saved_hook_helpers_enabled;
1171
1247
 
1172
- ensure_function_metadata(inner, { next: () => inner });
1173
- if (helper_state.helpers.length || helper_state.statics.length) {
1174
- inner.metadata = {
1175
- ...(inner.metadata || {}),
1176
- generated_helpers: helper_state.helpers,
1177
- generated_statics: helper_state.statics,
1178
- };
1179
- }
1248
+ inner.metadata = {
1249
+ ...strip_function_transform_metadata(inner.metadata),
1250
+ ...(create_generated_helper_metadata(helper_state) || {}),
1251
+ };
1180
1252
 
1181
1253
  return inner;
1182
1254
  }
1183
1255
 
1184
1256
  /**
1185
1257
  * @param {any} node
1186
- * @param {AST.Node[]} [path]
1187
1258
  * @returns {string}
1188
1259
  */
1189
- function get_function_helper_base_name(node, path = []) {
1190
- return get_function_like_name(node, path) || 'Tsrx';
1260
+ function get_function_helper_base_name(node) {
1261
+ return get_function_like_name(node) || 'Tsrx';
1191
1262
  }
1192
1263
 
1193
1264
  /**
1194
1265
  * @param {any} node
1195
- * @param {AST.Node[]} path
1196
1266
  * @returns {boolean}
1197
1267
  */
1198
- function is_uppercase_function_like(node, path) {
1199
- const name = get_function_like_name(node, path);
1268
+ function is_uppercase_function_like(node) {
1269
+ const name = get_function_like_name(node);
1200
1270
  return !!(name && /^[A-Z]/.test(name));
1201
1271
  }
1202
1272
 
1203
1273
  /**
1204
1274
  * @param {any} node
1205
- * @param {AST.Node[]} path
1206
1275
  * @returns {string | null}
1207
1276
  */
1208
- function get_function_like_name(node, path) {
1277
+ function get_function_like_name(node) {
1209
1278
  if (node.id?.type === 'Identifier') {
1210
1279
  return node.id.name;
1211
1280
  }
1212
1281
 
1213
- const parent = /** @type {any} */ (path.at(-1));
1282
+ const parent = /** @type {any} */ (node.metadata?.path?.at(-1));
1214
1283
  if (!parent) return null;
1215
1284
 
1216
1285
  if (parent.type === 'VariableDeclarator' && parent.init === node) {
@@ -1419,7 +1488,7 @@ function collect_tsrx_stylesheet(node) {
1419
1488
  /**
1420
1489
  * @param {any} node
1421
1490
  * @param {TransformContext} transform_context
1422
- * @returns {{ css: any, style_refs: any[] } | null}
1491
+ * @returns {{ css: any, style_refs: any[], fragment: any } | null}
1423
1492
  */
1424
1493
  function prepare_tsrx_fragment_styles(node, transform_context) {
1425
1494
  const css = collect_tsrx_stylesheet(node);
@@ -1428,21 +1497,21 @@ function prepare_tsrx_fragment_styles(node, transform_context) {
1428
1497
  const style_refs = collect_style_ref_attributes(node);
1429
1498
  apply_css_definition_metadata(node, css, style_refs.length > 0);
1430
1499
  transform_context.stylesheets.push(css);
1431
- annotate_tsrx_with_hash(
1500
+ const fragment = annotate_tsrx_with_hash(
1432
1501
  node,
1433
1502
  css.hash,
1434
1503
  transform_context.platform.jsx.classAttrName ??
1435
1504
  (transform_context.platform.jsx.rewriteClassAttr ? 'className' : 'class'),
1436
1505
  transform_context.typeOnly,
1437
1506
  );
1438
- return { css, style_refs };
1507
+ return { css, style_refs, fragment };
1439
1508
  }
1440
1509
 
1441
1510
  /**
1442
1511
  * @template T
1443
1512
  * @param {any} node
1444
1513
  * @param {TransformContext} transform_context
1445
- * @param {(style_context: { css: any, style_refs: any[] } | null) => T} callback
1514
+ * @param {(style_context: { css: any, style_refs: any[], fragment: any } | null) => T} callback
1446
1515
  * @returns {T}
1447
1516
  */
1448
1517
  function with_tsrx_fragment_styles(node, transform_context, callback) {
@@ -1452,7 +1521,7 @@ function with_tsrx_fragment_styles(node, transform_context, callback) {
1452
1521
 
1453
1522
  /**
1454
1523
  * @param {any} fragment
1455
- * @param {{ css: any, style_refs: any[] } | null} style_context
1524
+ * @param {{ css: any, style_refs: any[], fragment: any } | null} style_context
1456
1525
  * @param {TransformContext} transform_context
1457
1526
  * @returns {AST.Statement[]}
1458
1527
  */
@@ -1472,6 +1541,64 @@ function create_tsrx_style_ref_setup_statements(fragment, style_context, transfo
1472
1541
  );
1473
1542
  }
1474
1543
 
1544
+ /**
1545
+ * @param {any} node
1546
+ * @param {any} stylesheet
1547
+ * @param {TransformContext} transform_context
1548
+ * @returns {AST.Expression}
1549
+ */
1550
+ function create_style_expression_value(node, stylesheet, transform_context) {
1551
+ const class_map = create_style_class_map_from_stylesheet(stylesheet);
1552
+ if (!transform_context.typeOnly) {
1553
+ return class_map;
1554
+ }
1555
+
1556
+ add_type_only_style_anchor(node, transform_context);
1557
+ return class_map;
1558
+ }
1559
+
1560
+ /**
1561
+ * @param {any} node
1562
+ * @param {TransformContext} transform_context
1563
+ */
1564
+ function add_type_only_style_anchor(node, transform_context) {
1565
+ const style_anchor = b.jsx_element(clone_expression_node(node, true), [], []);
1566
+ disable_style_anchor_verification(style_anchor);
1567
+
1568
+ const anchor_id = create_generated_identifier(create_style_anchor_name(transform_context));
1569
+ transform_context.type_only_style_anchors.push(
1570
+ b.const(anchor_id, style_anchor),
1571
+ b.stmt(clone_identifier(anchor_id)),
1572
+ );
1573
+ }
1574
+
1575
+ /**
1576
+ * @param {TransformContext} transform_context
1577
+ * @returns {string}
1578
+ */
1579
+ function create_style_anchor_name(transform_context) {
1580
+ transform_context.local_statement_component_index += 1;
1581
+ return `_tsrx_style_anchor_${transform_context.local_statement_component_index}`;
1582
+ }
1583
+
1584
+ /**
1585
+ * @param {ESTreeJSX.JSXElement} element
1586
+ */
1587
+ function disable_style_anchor_verification(element) {
1588
+ if (element.openingElement?.name) {
1589
+ element.openingElement.name.metadata = {
1590
+ ...(element.openingElement.name.metadata || {}),
1591
+ disable_verification: true,
1592
+ };
1593
+ }
1594
+ if (element.closingElement?.name) {
1595
+ element.closingElement.name.metadata = {
1596
+ ...(element.closingElement.name.metadata || {}),
1597
+ disable_verification: true,
1598
+ };
1599
+ }
1600
+ }
1601
+
1475
1602
  /**
1476
1603
  * @param {TransformContext} transform_context
1477
1604
  * @returns {string}
@@ -1549,15 +1676,22 @@ function collect_style_elements(node, styles) {
1549
1676
  * @param {string} hash
1550
1677
  * @param {'class' | 'className'} jsx_class_attr_name
1551
1678
  * @param {boolean} preserve_style_elements
1552
- * @returns {void}
1679
+ * @returns {any}
1553
1680
  */
1554
1681
  function annotate_tsrx_with_hash(node, hash, jsx_class_attr_name, preserve_style_elements) {
1555
- node.children = (node.children || []).map((/** @type {any} */ statement) =>
1556
- annotate_with_hash(statement, hash, jsx_class_attr_name, preserve_style_elements),
1682
+ const annotated = { ...node };
1683
+ annotated.children = (node.children || []).map((/** @type {any} */ statement) =>
1684
+ annotate_with_hash(
1685
+ clone_expression_node(statement),
1686
+ hash,
1687
+ jsx_class_attr_name,
1688
+ preserve_style_elements,
1689
+ ),
1557
1690
  );
1558
1691
  if (!preserve_style_elements) {
1559
- node.children = strip_style_elements(node.children);
1692
+ annotated.children = strip_style_elements(annotated.children);
1560
1693
  }
1694
+ return annotated;
1561
1695
  }
1562
1696
 
1563
1697
  /**
@@ -1632,32 +1766,58 @@ function is_style_expression_position(path) {
1632
1766
  }
1633
1767
 
1634
1768
  /**
1635
- * @param {any} node
1769
+ * @param {any} fragment
1636
1770
  * @param {TransformContext} transform_context
1637
- * @returns {void}
1771
+ * @returns {any}
1638
1772
  */
1639
- function expand_native_tsrx_function_returns(node, transform_context) {
1640
- if (node.type === 'ArrowFunctionExpression' && node.body?.type === 'Tsrx') {
1641
- const body = node.body;
1642
- const statements = with_tsrx_fragment_styles(body, transform_context, (style_context) => {
1643
- return [
1644
- ...create_tsrx_style_ref_setup_statements(body, style_context, transform_context),
1645
- ...build_render_statements(get_tsrx_render_children(body), true, transform_context),
1646
- ];
1647
- });
1648
- node.body = b.block(mark_native_pretransformed_jsx(statements), body);
1649
- node.expression = false;
1650
- return;
1651
- }
1773
+ function create_native_tsrx_render_block(fragment, transform_context) {
1774
+ const block = b.block(
1775
+ mark_native_pretransformed_jsx(
1776
+ create_native_tsrx_render_statements(fragment, transform_context),
1777
+ ),
1778
+ fragment,
1779
+ );
1780
+ block.metadata = {
1781
+ ...(block.metadata || {}),
1782
+ native_return_block: true,
1783
+ };
1784
+ return block;
1785
+ }
1652
1786
 
1653
- if (node.body?.type !== 'BlockStatement') {
1654
- return;
1787
+ /**
1788
+ * @param {any} block
1789
+ * @param {TransformContext} transform_context
1790
+ * @returns {any | null}
1791
+ */
1792
+ function create_native_tsrx_statement_list_block(block, transform_context) {
1793
+ const source_body = block.body || [];
1794
+ const body = expand_native_tsrx_return_statement_list(source_body, transform_context);
1795
+
1796
+ if (body === source_body) {
1797
+ return null;
1655
1798
  }
1656
1799
 
1657
- node.body.body = expand_native_tsrx_return_statement_list(
1658
- node.body.body || [],
1659
- transform_context,
1660
- );
1800
+ const next_block = b.block(mark_native_pretransformed_jsx(body), block);
1801
+ next_block.metadata = {
1802
+ ...(next_block.metadata || {}),
1803
+ native_return_block: true,
1804
+ };
1805
+ return next_block;
1806
+ }
1807
+
1808
+ /**
1809
+ * @param {any} fragment
1810
+ * @param {TransformContext} transform_context
1811
+ * @returns {AST.Statement[]}
1812
+ */
1813
+ function create_native_tsrx_render_statements(fragment, transform_context) {
1814
+ return with_tsrx_fragment_styles(fragment, transform_context, (style_context) => {
1815
+ const target = style_context?.fragment ?? fragment;
1816
+ return [
1817
+ ...create_tsrx_style_ref_setup_statements(target, style_context, transform_context),
1818
+ ...build_render_statements(get_tsrx_render_children(target), true, transform_context),
1819
+ ];
1820
+ });
1661
1821
  }
1662
1822
 
1663
1823
  /**
@@ -1666,9 +1826,15 @@ function expand_native_tsrx_function_returns(node, transform_context) {
1666
1826
  * @returns {any[]}
1667
1827
  */
1668
1828
  function expand_native_tsrx_return_statement_list(statements, transform_context) {
1669
- return statements.flatMap((statement) =>
1670
- expand_native_tsrx_return_statement(statement, transform_context),
1671
- );
1829
+ let changed = false;
1830
+ const next_statements = statements.flatMap((statement) => {
1831
+ const result = expand_native_tsrx_return_statement(statement, transform_context);
1832
+ if (result.length !== 1 || result[0] !== statement) {
1833
+ changed = true;
1834
+ }
1835
+ return result;
1836
+ });
1837
+ return changed ? next_statements : statements;
1672
1838
  }
1673
1839
 
1674
1840
  /**
@@ -1680,13 +1846,7 @@ function expand_native_tsrx_return_statement(statement, transform_context) {
1680
1846
  if (!statement || typeof statement !== 'object') return [statement];
1681
1847
 
1682
1848
  if (statement.type === 'ReturnStatement' && statement.argument?.type === 'Tsrx') {
1683
- const fragment = statement.argument;
1684
- return with_tsrx_fragment_styles(fragment, transform_context, (style_context) => {
1685
- return mark_native_pretransformed_jsx([
1686
- ...create_tsrx_style_ref_setup_statements(fragment, style_context, transform_context),
1687
- ...build_render_statements(get_tsrx_render_children(fragment), true, transform_context),
1688
- ]);
1689
- });
1849
+ return create_native_tsrx_render_statements(statement.argument, transform_context);
1690
1850
  }
1691
1851
 
1692
1852
  if (is_function_or_class_boundary(statement)) {
@@ -1694,52 +1854,65 @@ function expand_native_tsrx_return_statement(statement, transform_context) {
1694
1854
  }
1695
1855
 
1696
1856
  if (statement.type === 'BlockStatement') {
1697
- statement.body = expand_native_tsrx_return_statement_list(
1698
- statement.body || [],
1699
- transform_context,
1700
- );
1701
- return [statement];
1857
+ const body = expand_native_tsrx_return_statement_list(statement.body || [], transform_context);
1858
+ return body === statement.body ? [statement] : [b.block(body, statement)];
1702
1859
  }
1703
1860
 
1704
1861
  if (statement.type === 'IfStatement') {
1705
- statement.consequent = expand_embedded_native_return_statement(
1862
+ const consequent = expand_embedded_native_return_statement(
1706
1863
  statement.consequent,
1707
1864
  transform_context,
1708
1865
  );
1709
- if (statement.alternate) {
1710
- statement.alternate = expand_embedded_native_return_statement(
1711
- statement.alternate,
1712
- transform_context,
1713
- );
1866
+ const alternate = statement.alternate
1867
+ ? expand_embedded_native_return_statement(statement.alternate, transform_context)
1868
+ : statement.alternate;
1869
+ if (consequent === statement.consequent && alternate === statement.alternate) {
1870
+ return [statement];
1714
1871
  }
1715
- return [statement];
1872
+ return [set_loc(b.if(statement.test, consequent, alternate), statement)];
1716
1873
  }
1717
1874
 
1718
1875
  if (statement.type === 'SwitchStatement') {
1719
- for (const switch_case of statement.cases || []) {
1720
- switch_case.consequent = expand_native_tsrx_return_statement_list(
1876
+ let changed = false;
1877
+ const cases = (statement.cases || []).map((/** @type {any} */ switch_case) => {
1878
+ const consequent = expand_native_tsrx_return_statement_list(
1721
1879
  switch_case.consequent || [],
1722
1880
  transform_context,
1723
1881
  );
1724
- }
1725
- return [statement];
1882
+ if (consequent === switch_case.consequent) {
1883
+ return switch_case;
1884
+ }
1885
+ changed = true;
1886
+ return set_loc(b.switch_case(switch_case.test, consequent), switch_case);
1887
+ });
1888
+ return changed ? [set_loc(b.switch(statement.discriminant, cases), statement)] : [statement];
1726
1889
  }
1727
1890
 
1728
1891
  if (statement.type === 'TryStatement') {
1729
- statement.block = expand_embedded_native_return_statement(statement.block, transform_context);
1730
- if (statement.handler?.body) {
1731
- statement.handler.body = expand_embedded_native_return_statement(
1732
- statement.handler.body,
1733
- transform_context,
1734
- );
1735
- }
1736
- if (statement.finalizer) {
1737
- statement.finalizer = expand_embedded_native_return_statement(
1738
- statement.finalizer,
1739
- transform_context,
1740
- );
1892
+ const block = expand_embedded_native_return_statement(statement.block, transform_context);
1893
+ const handler_body = statement.handler?.body
1894
+ ? expand_embedded_native_return_statement(statement.handler.body, transform_context)
1895
+ : statement.handler?.body;
1896
+ const finalizer = statement.finalizer
1897
+ ? expand_embedded_native_return_statement(statement.finalizer, transform_context)
1898
+ : statement.finalizer;
1899
+ if (
1900
+ block === statement.block &&
1901
+ handler_body === statement.handler?.body &&
1902
+ finalizer === statement.finalizer
1903
+ ) {
1904
+ return [statement];
1741
1905
  }
1742
- return [statement];
1906
+ const handler =
1907
+ statement.handler && handler_body !== statement.handler.body
1908
+ ? b.catch_clause(
1909
+ statement.handler.param,
1910
+ statement.handler.resetParam,
1911
+ handler_body,
1912
+ statement.handler,
1913
+ )
1914
+ : statement.handler;
1915
+ return [set_loc(b.try(block, handler, finalizer, statement.pending ?? null), statement)];
1743
1916
  }
1744
1917
 
1745
1918
  return [statement];
@@ -2645,15 +2818,7 @@ function to_jsx_element(node, transform_context, raw_children = node.children ||
2645
2818
  if (node.type === 'JSXElement') return node;
2646
2819
  if (!node.id) {
2647
2820
  report_jsx_fragment_in_tsrx_error(node, transform_context);
2648
- return set_loc(
2649
- /** @type {any} */ ({
2650
- type: 'JSXFragment',
2651
- openingFragment: { type: 'JSXOpeningFragment' },
2652
- closingFragment: { type: 'JSXClosingFragment' },
2653
- children: [],
2654
- }),
2655
- node,
2656
- );
2821
+ return set_loc(b.jsx_fragment(), node);
2657
2822
  }
2658
2823
  if (is_dynamic_element_id(node.id)) {
2659
2824
  return dynamic_element_to_jsx_child(node, transform_context);
@@ -2707,7 +2872,11 @@ function to_jsx_element(node, transform_context, raw_children = node.children ||
2707
2872
  node.closingElement || node,
2708
2873
  );
2709
2874
 
2710
- return set_loc(b.jsx_element_fresh(openingElement, closingElement, children), node);
2875
+ const element = set_loc(b.jsx_element_fresh(openingElement, closingElement, children), node);
2876
+ if (transform_context.typeOnly && is_style_element(node)) {
2877
+ disable_style_anchor_verification(element);
2878
+ }
2879
+ return element;
2711
2880
  }
2712
2881
 
2713
2882
  /**
@@ -3632,12 +3801,7 @@ export function create_hook_safe_helper(
3632
3801
 
3633
3802
  if (key_expression) {
3634
3803
  component_element.openingElement.attributes.push(
3635
- /** @type {any} */ ({
3636
- type: 'JSXAttribute',
3637
- name: { type: 'JSXIdentifier', name: 'key', metadata: { path: [] } },
3638
- value: to_jsx_expression_container(key_expression, key_expression),
3639
- metadata: { path: [] },
3640
- }),
3804
+ b.jsx_attribute(b.jsx_id('key'), to_jsx_expression_container(key_expression, key_expression)),
3641
3805
  );
3642
3806
  }
3643
3807
 
@@ -3805,11 +3969,19 @@ function create_cached_helper_declaration(helper_id, cache_id, helper_init) {
3805
3969
  * @returns {AST.FunctionDeclaration}
3806
3970
  */
3807
3971
  function create_helper_function_declaration_from_expression(helper_id, helper_fn) {
3808
- return {
3809
- ...helper_fn,
3810
- type: 'FunctionDeclaration',
3811
- id: clone_identifier(helper_id),
3812
- };
3972
+ const declaration = set_loc(
3973
+ b.function_declaration(
3974
+ clone_identifier(helper_id),
3975
+ helper_fn.params,
3976
+ helper_fn.body,
3977
+ helper_fn.async,
3978
+ helper_fn.typeParameters,
3979
+ ),
3980
+ helper_fn,
3981
+ );
3982
+ declaration.generator = helper_fn.generator;
3983
+ declaration.metadata = { ...(helper_fn.metadata || {}), path: helper_fn.metadata?.path || [] };
3984
+ return declaration;
3813
3985
  }
3814
3986
 
3815
3987
  /**
@@ -4574,14 +4746,7 @@ function try_statement_to_jsx_child(node, transform_context) {
4574
4746
  ) ??
4575
4747
  create_jsx_element(
4576
4748
  'Suspense',
4577
- [
4578
- {
4579
- type: 'JSXAttribute',
4580
- name: { type: 'JSXIdentifier', name: 'fallback', metadata: { path: [] } },
4581
- value: fallback_content,
4582
- metadata: { path: [] },
4583
- },
4584
- ],
4749
+ [b.jsx_attribute(b.jsx_id('fallback'), fallback_content)],
4585
4750
  [result],
4586
4751
  );
4587
4752
  }
@@ -5066,14 +5231,12 @@ function build_switch_with_lift(switch_node, transform_context) {
5066
5231
  (/** @type {any} */ original_case, /** @type {number} */ i) => {
5067
5232
  const helper = case_helpers[i];
5068
5233
  if (helper) {
5069
- return /** @type {any} */ ({
5070
- type: 'SwitchCase',
5071
- test: original_case.test,
5072
- consequent: [
5234
+ return set_loc(
5235
+ b.switch_case(original_case.test, [
5073
5236
  create_component_return_statement([helper.component_element], original_case),
5074
- ],
5075
- metadata: { path: [] },
5076
- });
5237
+ ]),
5238
+ original_case,
5239
+ );
5077
5240
  }
5078
5241
 
5079
5242
  const { own_body, has_terminator } = case_info[i];
@@ -5082,12 +5245,7 @@ function build_switch_with_lift(switch_node, transform_context) {
5082
5245
  // Alias-pattern empty case (`case 'a': case 'b': ...`) — keep
5083
5246
  // the arm body empty so JS falls through to the next case at
5084
5247
  // runtime, where the helper invocation actually lives.
5085
- return /** @type {any} */ ({
5086
- type: 'SwitchCase',
5087
- test: original_case.test,
5088
- consequent: [],
5089
- metadata: { path: [] },
5090
- });
5248
+ return set_loc(b.switch_case(original_case.test, []), original_case);
5091
5249
  }
5092
5250
 
5093
5251
  const case_body = [];
@@ -5128,45 +5286,23 @@ function build_switch_with_lift(switch_node, transform_context) {
5128
5286
  // Empty body with explicit `break;` / bare `return;` — keep
5129
5287
  // a `break` so JS doesn't fall through into the next case
5130
5288
  // (which may now hold the lifted helper invocation).
5131
- case_body.push(
5132
- /** @type {any} */ ({
5133
- type: 'BreakStatement',
5134
- label: null,
5135
- metadata: { path: [] },
5136
- }),
5137
- );
5289
+ case_body.push(b.break);
5138
5290
  } else if (case_body.length > 0) {
5139
5291
  // Statements-only inline case without terminator. We've
5140
5292
  // already inlined the downstream chain via the helper
5141
5293
  // reference above, so emit a `break` to stop the runtime
5142
5294
  // from re-running downstream statements via JS fall-through.
5143
- case_body.push(
5144
- /** @type {any} */ ({
5145
- type: 'BreakStatement',
5146
- label: null,
5147
- metadata: { path: [] },
5148
- }),
5149
- );
5295
+ case_body.push(b.break);
5150
5296
  }
5151
5297
  }
5152
5298
 
5153
- return /** @type {any} */ ({
5154
- type: 'SwitchCase',
5155
- test: original_case.test,
5156
- consequent: case_body,
5157
- metadata: { path: [] },
5158
- });
5299
+ return set_loc(b.switch_case(original_case.test, case_body), original_case);
5159
5300
  },
5160
5301
  );
5161
5302
 
5162
5303
  return {
5163
5304
  setup_statements,
5164
- switch_statement: /** @type {any} */ ({
5165
- type: 'SwitchStatement',
5166
- discriminant: switch_node.discriminant,
5167
- cases: new_cases,
5168
- metadata: { path: [] },
5169
- }),
5305
+ switch_statement: b.switch(switch_node.discriminant, new_cases, switch_node),
5170
5306
  };
5171
5307
  }
5172
5308
 
@@ -5781,19 +5917,7 @@ function build_return_expression(render_nodes) {
5781
5917
  const first = render_nodes[0];
5782
5918
  const last = render_nodes[render_nodes.length - 1];
5783
5919
  return set_loc(
5784
- {
5785
- type: 'JSXFragment',
5786
- openingFragment: /** @type {any} */ ({
5787
- type: 'JSXOpeningFragment',
5788
- metadata: { path: [] },
5789
- }),
5790
- closingFragment: /** @type {any} */ ({
5791
- type: 'JSXClosingFragment',
5792
- metadata: { path: [] },
5793
- }),
5794
- children: render_nodes,
5795
- metadata: { path: [] },
5796
- },
5920
+ b.jsx_fragment(render_nodes),
5797
5921
  first?.loc && last?.loc
5798
5922
  ? {
5799
5923
  start: first.start,
package/types/index.d.ts CHANGED
@@ -102,11 +102,15 @@ interface BaseNodeMetaData {
102
102
  }
103
103
 
104
104
  interface FunctionMetaData extends BaseNodeMetaData {
105
+ native_tsrx?: boolean;
105
106
  native_tsrx_function?: boolean;
107
+ hook_split?: boolean;
106
108
  is_method?: boolean;
107
109
  tracked?: boolean;
108
110
  has_lazy_descendants?: boolean;
109
111
  synthetic_children?: boolean;
112
+ generated_helpers?: any[];
113
+ generated_statics?: any[];
110
114
  }
111
115
 
112
116
  // Strip parent, loc, and range from TSESTree nodes to match @sveltejs/acorn-typescript output
@@ -163,6 +167,13 @@ declare module 'estree' {
163
167
  };
164
168
  }
165
169
 
170
+ interface BlockStatement {
171
+ metadata: BaseNodeMetaData & {
172
+ hook_split_block?: boolean;
173
+ native_return_block?: boolean;
174
+ };
175
+ }
176
+
166
177
  type Accessibility = 'public' | 'protected' | 'private'; // missing in acorn-typescript types
167
178
  interface MethodDefinition {
168
179
  typeParameters?: TSTypeParameterDeclaration;
@@ -238,6 +249,7 @@ declare module 'estree' {
238
249
  }
239
250
 
240
251
  interface ExpressionMap {
252
+ Tsrx: Tsrx;
241
253
  Text: TextNode;
242
254
  JSXEmptyExpression: ESTreeJSX.JSXEmptyExpression;
243
255
  ParenthesizedExpression: ParenthesizedExpression;
@@ -343,7 +355,7 @@ declare module 'estree' {
343
355
  closingElement: ESTreeJSX.JSXClosingElement;
344
356
  }
345
357
 
346
- interface Tsrx extends AST.BaseNode {
358
+ interface Tsrx extends AST.BaseExpression {
347
359
  type: 'Tsrx';
348
360
  attributes: Array<any>;
349
361
  children: AST.Node[];
@@ -649,6 +661,12 @@ declare module 'estree-jsx' {
649
661
  };
650
662
  }
651
663
 
664
+ interface JSXOpeningElement {
665
+ metadata: BaseNodeMetaData & {
666
+ native_tsrx_pretransformed?: boolean;
667
+ };
668
+ }
669
+
652
670
  interface JSXExpressionContainer {
653
671
  text?: boolean;
654
672
  style?: boolean;
@@ -42,6 +42,7 @@ export interface JsxTransformContext {
42
42
  needs_for_of_iterable: boolean;
43
43
  needs_iteration_value_type: boolean;
44
44
  stylesheets: AST.CSS.StyleSheet[];
45
+ type_only_style_anchors: AST.Statement[];
45
46
  module_scoped_hook_components: boolean;
46
47
  helper_state: {
47
48
  base_name: string;
@@ -154,13 +155,6 @@ export interface JsxPlatformHooks {
154
155
  * state behaves like normal component state.
155
156
  */
156
157
  wrapHelperComponent?: (helperFn: any, helperId: any, ctx: any, sourceNode: any) => any;
157
- /**
158
- * Wrap an uppercase JavaScript function that returns native TSRX as a target
159
- * component. Vue uses this to turn `function App() { return <></>; }` into a
160
- * `defineVaporComponent(function App() { ... })` binding while lowercase
161
- * TSRX-returning callbacks stay plain functions.
162
- */
163
- wrapNativeFunctionComponent?: (fn: any, ctx: any, path: any[]) => any;
164
158
  /**
165
159
  * Emit hook-isolation helper components as unique module-scope declarations
166
160
  * instead of lazily creating and caching them from the parent component body.