@tsrx/core 0.1.16 → 0.1.17

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/README.md CHANGED
@@ -41,8 +41,9 @@ The TSRX website is the canonical source for language documentation:
41
41
 
42
42
  - [Getting Started](https://tsrx.dev/getting-started) — install TSRX for React,
43
43
  Preact, Solid, Vue, or Ripple and configure editor/AI tooling.
44
- - [Features](https://tsrx.dev/features) — examples of components, statement
45
- templates, control flow, scoped styles, submodules, and lazy destructuring.
44
+ - [Features](https://tsrx.dev/features) — examples of function components,
45
+ statement templates, control flow, scoped styles, submodules, and lazy
46
+ destructuring.
46
47
  - [Specification](https://tsrx.dev/specification) — the current grammar and
47
48
  parser-level semantics.
48
49
 
@@ -54,7 +55,7 @@ here and keeps package docs focused on the core parser API.
54
55
  - **`parseModule(source, filename, options?)`** — parse a TSRX module into an
55
56
  ESTree AST.
56
57
  - **Scope analysis** — `createScopes`, `Scope`, `ScopeRoot`, binding tracking
57
- (`import`, `prop`, `let`, `const`, `function`, `component`, `for_pattern`, …).
58
+ (`import`, `prop`, `let`, `const`, `function`, `for_pattern`, …).
58
59
  - **AST utilities** — pattern walkers, identifier extraction, builders, location
59
60
  helpers, obfuscation helpers.
60
61
  - **CSS support** — `parseStyle`, `analyzeCss`, `renderStylesheets`.
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.16",
6
+ "version": "0.1.17",
7
7
  "type": "module",
8
8
  "repository": {
9
9
  "type": "git",
@@ -323,26 +323,14 @@ function get_descendant_elements(node, adjacent_only) {
323
323
  }
324
324
  }
325
325
 
326
- if (/** @type {AST.Component} */ (current_node).body) {
327
- for (const child of /** @type {AST.Component} */ (current_node).body) {
328
- visit(child, depth + 1);
329
- }
330
- }
331
-
332
326
  // For template nodes and interpolation expressions
333
327
  if (
334
- (current_node.type === 'TSRXExpression' ||
335
- current_node.type === 'Text' ||
336
- current_node.type === 'Html') &&
337
- /** @type {AST.TSRXExpression | AST.Html | AST.TextNode} */ (current_node).expression &&
338
- typeof (
339
- /** @type {AST.TSRXExpression | AST.Html | AST.TextNode} */ (current_node).expression
340
- ) === 'object'
328
+ (current_node.type === 'TSRXExpression' || current_node.type === 'Text') &&
329
+ /** @type {AST.TSRXExpression | AST.TextNode} */ (current_node).expression &&
330
+ typeof (/** @type {AST.TSRXExpression | AST.TextNode} */ (current_node).expression) ===
331
+ 'object'
341
332
  ) {
342
- visit(
343
- /** @type {AST.TSRXExpression | AST.Html | AST.TextNode} */ (current_node).expression,
344
- depth + 1,
345
- );
333
+ visit(/** @type {AST.TSRXExpression | AST.TextNode} */ (current_node).expression, depth + 1);
346
334
  }
347
335
  }
348
336
 
@@ -399,7 +387,6 @@ function can_render_dynamic_content(element, check_classes = false) {
399
387
  */
400
388
  function get_possible_element_siblings(node, direction, adjacent_only) {
401
389
  const siblings = new Map();
402
- // Parent has to be an Element not a Component
403
390
  const parent = get_element_parent(node);
404
391
 
405
392
  if (!parent) {
@@ -428,9 +415,9 @@ function get_possible_element_siblings(node, direction, adjacent_only) {
428
415
  for (let i = start; i !== end; i += step) {
429
416
  const sibling = container[i];
430
417
 
431
- if (sibling.type === 'Element' || sibling.type === 'Component') {
418
+ if (sibling.type === 'Element') {
432
419
  siblings.set(sibling, true);
433
- // Don't break for dynamic elements (children, Components, dynamic components)
420
+ // Don't break for dynamic elements (children and dynamic components)
434
421
  // as they can render dynamic content or might render nothing
435
422
  const isDynamic = can_render_dynamic_content(sibling, false);
436
423
  if (adjacent_only && !isDynamic) {
@@ -534,12 +521,6 @@ function apply_combinator(relative_selector, rest_selectors, rule, node, directi
534
521
  break;
535
522
  }
536
523
  if (combinator.name === '+') break; // For adjacent, only check first element
537
- } else if (subsequent.type === 'Component') {
538
- // Skip components when looking for the target element
539
- if (combinator.name === '+') {
540
- // For adjacent, continue looking
541
- continue;
542
- }
543
524
  }
544
525
  }
545
526
  }
@@ -987,6 +968,10 @@ function relative_selector_might_apply_to_node(relative_selector, rule, element,
987
968
  }
988
969
 
989
970
  case 'TypeSelector': {
971
+ if (is_element_dynamic(/** @type {AST.Element} */ (element))) {
972
+ break;
973
+ }
974
+
990
975
  if (
991
976
  element.id.type === 'Identifier' &&
992
977
  element.id.name.toLowerCase() !== name.toLowerCase() &&
@@ -1106,11 +1091,11 @@ export function prune_css(css, element, styleClasses, topScopedClasses) {
1106
1091
  node.metadata.used = true;
1107
1092
  }
1108
1093
 
1109
- // Populate top_scoped_classes for truly standalone class selectors ({style} support).
1094
+ // Populate top_scoped_classes for truly standalone class selectors.
1110
1095
  // A class is standalone only when the entire effective selector chain (after resolving
1111
1096
  // nesting and stripping :global) is a single RelativeSelector with a single ClassSelector.
1112
1097
  // This prevents classes from compound selectors like `.wrapper .nested` or selectors
1113
- // inside :global() from being treated as valid {style} targets.
1098
+ // inside :global() from being exported through style refs.
1114
1099
  if (selectors.length === 1) {
1115
1100
  const sole_selector = selectors[0];
1116
1101
  if (
@@ -4,25 +4,22 @@
4
4
  */
5
5
 
6
6
  import { error } from '../errors.js';
7
+ import { DIAGNOSTIC_CODES } from '../diagnostics.js';
7
8
 
8
- export const COMPONENT_RETURN_VALUE_ERROR =
9
- 'Return statements inside components cannot have a return value.';
10
- export const COMPONENT_LOOP_RETURN_ERROR =
11
- 'Return statements are not allowed inside component for...of loops. Use continue instead.';
12
- export const COMPONENT_LOOP_BREAK_ERROR =
13
- 'Break statements are not allowed inside component for...of loops.';
14
- export const COMPONENT_FOR_STATEMENT_ERROR =
15
- 'For loops are not supported in components. Use for...of instead.';
16
- export const COMPONENT_FOR_IN_STATEMENT_ERROR =
17
- 'For...in loops are not supported in components. Use for...of instead.';
18
- export const COMPONENT_WHILE_STATEMENT_ERROR =
19
- 'While loops are not supported in components. Move the while loop into a function.';
20
- export const COMPONENT_DO_WHILE_STATEMENT_ERROR =
21
- 'Do...while loops are not supported in components. Move the do...while loop into a function.';
22
- export const CLASS_COMPONENT_AS_NON_ARROW_PROPERTY_ERROR =
23
- 'Components declared inside a class must be defined as an arrow function class property (e.g. `Foo = component() => { ... }`). Non-arrow component property values are not allowed.';
24
- export const COMPONENT_MULTIPLE_PARAMS_ERROR =
25
- 'Components accept a single props parameter. Move additional inputs into the props object instead.';
9
+ export const TSRX_RETURN_STATEMENT_ERROR =
10
+ 'Return statements are not allowed inside TSRX templates. Move the return before the TSRX return value, or use conditional rendering instead.';
11
+ export const TSRX_LOOP_RETURN_ERROR =
12
+ 'Return statements are not allowed inside TSRX template for...of loops. Use continue instead.';
13
+ export const TSRX_LOOP_BREAK_ERROR =
14
+ 'Break statements are not allowed inside TSRX template for...of loops.';
15
+ export const TSRX_FOR_STATEMENT_ERROR =
16
+ 'For loops are not supported in TSRX templates. Use for...of instead.';
17
+ export const TSRX_FOR_IN_STATEMENT_ERROR =
18
+ 'For...in loops are not supported in TSRX templates. Use for...of instead.';
19
+ export const TSRX_WHILE_STATEMENT_ERROR =
20
+ 'While loops are not supported in TSRX templates. Move the while loop into a function.';
21
+ export const TSRX_DO_WHILE_STATEMENT_ERROR =
22
+ 'Do...while loops are not supported in TSRX templates. Move the do...while loop into a function.';
26
23
 
27
24
  const invalid_nestings = {
28
25
  // <p> cannot contain block-level elements
@@ -184,17 +181,14 @@ export function get_statement_keyword_node(node, keyword) {
184
181
  * @param {CompileError[]} [errors]
185
182
  * @param {AST.CommentWithLocation[]} [comments]
186
183
  */
187
- export function validate_component_return_statement(node, filename, errors, comments) {
188
- if (node.argument === null) {
189
- return;
190
- }
191
-
184
+ export function validate_tsrx_return_statement(node, filename, errors, comments) {
192
185
  error(
193
- COMPONENT_RETURN_VALUE_ERROR,
186
+ TSRX_RETURN_STATEMENT_ERROR,
194
187
  filename ?? null,
195
188
  get_return_keyword_node(node),
196
189
  errors,
197
190
  comments,
191
+ DIAGNOSTIC_CODES.TEMPLATE_RETURN_STATEMENT,
198
192
  );
199
193
  }
200
194
 
@@ -204,14 +198,8 @@ export function validate_component_return_statement(node, filename, errors, comm
204
198
  * @param {CompileError[]} [errors]
205
199
  * @param {AST.CommentWithLocation[]} [comments]
206
200
  */
207
- export function validate_component_loop_return_statement(node, filename, errors, comments) {
208
- error(
209
- COMPONENT_LOOP_RETURN_ERROR,
210
- filename ?? null,
211
- get_return_keyword_node(node),
212
- errors,
213
- comments,
214
- );
201
+ export function validate_tsrx_loop_return_statement(node, filename, errors, comments) {
202
+ error(TSRX_LOOP_RETURN_ERROR, filename ?? null, get_return_keyword_node(node), errors, comments);
215
203
  }
216
204
 
217
205
  /**
@@ -220,9 +208,9 @@ export function validate_component_loop_return_statement(node, filename, errors,
220
208
  * @param {CompileError[]} [errors]
221
209
  * @param {AST.CommentWithLocation[]} [comments]
222
210
  */
223
- export function validate_component_loop_break_statement(node, filename, errors, comments) {
211
+ export function validate_tsrx_loop_break_statement(node, filename, errors, comments) {
224
212
  error(
225
- COMPONENT_LOOP_BREAK_ERROR,
213
+ TSRX_LOOP_BREAK_ERROR,
226
214
  filename ?? null,
227
215
  get_statement_keyword_node(node, 'break'),
228
216
  errors,
@@ -236,76 +224,21 @@ export function validate_component_loop_break_statement(node, filename, errors,
236
224
  * @param {CompileError[]} [errors]
237
225
  * @param {AST.CommentWithLocation[]} [comments]
238
226
  */
239
- export function validate_component_unsupported_loop_statement(node, filename, errors, comments) {
227
+ export function validate_tsrx_unsupported_loop_statement(node, filename, errors, comments) {
240
228
  let message;
241
229
  if (node.type === 'ForStatement') {
242
- message = COMPONENT_FOR_STATEMENT_ERROR;
230
+ message = TSRX_FOR_STATEMENT_ERROR;
243
231
  } else if (node.type === 'ForInStatement') {
244
- message = COMPONENT_FOR_IN_STATEMENT_ERROR;
232
+ message = TSRX_FOR_IN_STATEMENT_ERROR;
245
233
  } else if (node.type === 'WhileStatement') {
246
- message = COMPONENT_WHILE_STATEMENT_ERROR;
234
+ message = TSRX_WHILE_STATEMENT_ERROR;
247
235
  } else {
248
- message = COMPONENT_DO_WHILE_STATEMENT_ERROR;
236
+ message = TSRX_DO_WHILE_STATEMENT_ERROR;
249
237
  }
250
238
 
251
239
  error(message, filename ?? null, node, errors, comments);
252
240
  }
253
241
 
254
- /**
255
- * Validates that a component declares at most a single (props) parameter.
256
- * Components have one slot for props; additional positional parameters are
257
- * silently dropped or naively passed through depending on the target, so
258
- * reject them at analysis time. Reports one error per extra parameter so
259
- * every offending input gets its own TS diagnostic squiggle. In throwing
260
- * mode the first call raises and aborts before the loop continues.
261
- *
262
- * @param {AST.Component} component
263
- * @param {string | null | undefined} filename
264
- * @param {CompileError[]} [errors]
265
- * @param {AST.CommentWithLocation[]} [comments]
266
- */
267
- export function validate_component_params(component, filename, errors, comments) {
268
- const params = /** @type {AST.Pattern[] | undefined} */ (component.params);
269
- if (!params || params.length <= 1) {
270
- return;
271
- }
272
-
273
- for (let i = 1; i < params.length; i++) {
274
- error(COMPONENT_MULTIPLE_PARAMS_ERROR, filename ?? null, params[i], errors, comments);
275
- }
276
- }
277
-
278
- /**
279
- * Validates that components declared at the top level of a class body use the
280
- * only allowed form: an arrow function class property (regular or static).
281
- * Reports an error for non-arrow component property values such as
282
- * `Foo = component() { ... }`. The method form (`component foo() {}` inside
283
- * a class body) is rejected at parse time and never reaches this check.
284
- *
285
- * @param {AST.ClassBody} class_body
286
- * @param {string | null | undefined} filename
287
- * @param {CompileError[]} [errors]
288
- * @param {AST.CommentWithLocation[]} [comments]
289
- */
290
- export function validate_class_component_declarations(class_body, filename, errors, comments) {
291
- for (const member of class_body.body) {
292
- if (member.type !== 'PropertyDefinition') {
293
- continue;
294
- }
295
-
296
- const value = /** @type {any} */ (member).value;
297
- if (value && value.type === 'Component' && !value.metadata?.arrow) {
298
- error(
299
- CLASS_COMPONENT_AS_NON_ARROW_PROPERTY_ERROR,
300
- filename ?? null,
301
- member,
302
- errors,
303
- comments,
304
- );
305
- }
306
- }
307
- }
308
-
309
242
  /**
310
243
  * @param {AST.Element} element
311
244
  * @param {AnalysisContext} context
@@ -1,9 +1,7 @@
1
1
  export const DIAGNOSTIC_CODES = {
2
2
  JSX_EXPRESSION_VALUE: 'tsrx-jsx-expression-value',
3
- JSX_RETURN_IN_COMPONENT: 'tsrx-jsx-return-in-component',
4
- FUNCTION_COMPONENT_SYNTAX: 'tsrx-function-component-syntax',
5
3
  UNCLOSED_TAG: 'tsrx-unclosed-tag',
6
4
  MISMATCHED_CLOSING_TAG: 'tsrx-mismatched-closing-tag',
7
5
  TEMPLATE_EXPRESSION_TRAILING_SEMICOLON: 'tsrx-template-expression-trailing-semicolon',
8
- HTML_DIRECTIVE_AS_ATTRIBUTE_VALUE: 'tsrx-html-directive-as-attribute-value',
6
+ TEMPLATE_RETURN_STATEMENT: 'tsrx-template-return-statement',
9
7
  };
package/src/index.js CHANGED
@@ -86,7 +86,6 @@ export {
86
86
  build_fallback as buildFallback,
87
87
  build_assignment_value as buildAssignmentValue,
88
88
  is_class_node as isClassNode,
89
- is_component_node as isComponentNode,
90
89
  is_function_node as isFunctionNode,
91
90
  is_function_or_component_node as isFunctionOrComponentNode,
92
91
  is_inside_component as isInsideComponent,
@@ -142,35 +141,25 @@ export { escape, escape_script as escapeScript } from './utils/escaping.js';
142
141
 
143
142
  // Transform
144
143
  export {
145
- add_ref_target_type_to_ref_prop_attributes as addRefTargetTypeToRefPropAttributes,
146
144
  add_jsx_setup_declaration as addJsxSetupDeclaration,
147
145
  clone_switch_helper_invocation as cloneSwitchHelperInvocation,
148
146
  collect_param_bindings as collectParamBindings,
149
147
  collect_statement_bindings as collectStatementBindings,
150
148
  create_hook_safe_helper as createHookSafeHelper,
151
- create_host_html_attribute as createHostHtmlAttribute,
152
- create_host_html_conflict_error as createHostHtmlConflictError,
153
149
  create_element_ref_target_type as createElementRefTargetType,
154
150
  create_element_ref_target_type_for_name as createElementRefTargetTypeForName,
155
151
  createJsxTransform,
156
- CREATE_REF_PROP_INTERNAL_NAME,
157
152
  extract_jsx_setup_declarations as extractJsxSetupDeclarations,
158
- get_host_html_conflicting_attribute as getHostHtmlConflictingAttribute,
159
- get_invalid_html_child_error_message as getInvalidHtmlChildErrorMessage,
160
153
  is_component_like_element,
161
- is_ref_expression_attribute_value as isRefExpressionAttributeValue,
162
- is_ref_prop_expression as isRefPropExpression,
163
154
  MERGE_REFS_INTERNAL_NAME,
164
155
  merge_duplicate_refs as mergeDuplicateRefs,
156
+ NORMALIZE_SPREAD_PROPS_FOR_REF_ATTR_INTERNAL_NAME,
165
157
  NORMALIZE_SPREAD_PROPS_INTERNAL_NAME,
166
158
  plan_switch_lift as planSwitchLift,
167
- recover_invalid_html_child as recoverInvalidHtmlChild,
168
- rewrite_host_html_children as rewriteHostHtmlChildren,
169
159
  return_value_body_to_expression as returnValueBodyToExpression,
170
160
  rewrite_loop_continues_to_bare_returns as rewriteLoopContinuesToBareReturns,
171
161
  to_jsx_attribute as toJsxAttribute,
172
162
  validate_at_most_one_ref_attribute as validateAtMostOneRefAttribute,
173
- component_to_function_declaration as componentToFunctionDeclaration,
174
163
  } from './transform/jsx/index.js';
175
164
  export {
176
165
  ensure_function_metadata as ensureFunctionMetadata,
@@ -178,6 +167,11 @@ export {
178
167
  tsx_node_to_jsx_expression as tsxNodeToJsxExpression,
179
168
  tsx_with_ts_locations as tsxWithTsLocations,
180
169
  } from './transform/jsx/helpers.js';
170
+ export {
171
+ collect_style_ref_attributes as collectStyleRefAttributes,
172
+ create_style_class_map as createStyleClassMap,
173
+ create_style_ref_setup_statements as createStyleRefSetupStatements,
174
+ } from './transform/style-ref.js';
181
175
  export {
182
176
  clone_expression_node,
183
177
  clone_identifier,
@@ -224,7 +218,7 @@ export {
224
218
  } from './transform/lazy.js';
225
219
  export {
226
220
  find_first_top_level_await as findFirstTopLevelAwait,
227
- find_first_top_level_await_in_component_body as findFirstTopLevelAwaitInComponentBody,
221
+ find_first_top_level_await_in_tsrx_function_body as findFirstTopLevelAwaitInTsrxFunctionBody,
228
222
  } from './transform/await.js';
229
223
  export {
230
224
  is_interleaved_body as isInterleavedBody,
@@ -243,22 +237,18 @@ export {
243
237
  export { analyze_css as analyzeCss } from './analyze/css-analyze.js';
244
238
  export { prune_css as pruneCss } from './analyze/prune.js';
245
239
  export {
246
- CLASS_COMPONENT_AS_NON_ARROW_PROPERTY_ERROR,
247
- COMPONENT_DO_WHILE_STATEMENT_ERROR,
248
- COMPONENT_FOR_IN_STATEMENT_ERROR,
249
- COMPONENT_FOR_STATEMENT_ERROR,
250
- COMPONENT_LOOP_BREAK_ERROR,
251
- COMPONENT_LOOP_RETURN_ERROR,
252
- COMPONENT_MULTIPLE_PARAMS_ERROR,
253
- COMPONENT_RETURN_VALUE_ERROR,
254
- COMPONENT_WHILE_STATEMENT_ERROR,
240
+ TSRX_DO_WHILE_STATEMENT_ERROR,
241
+ TSRX_FOR_IN_STATEMENT_ERROR,
242
+ TSRX_FOR_STATEMENT_ERROR,
243
+ TSRX_LOOP_BREAK_ERROR,
244
+ TSRX_LOOP_RETURN_ERROR,
245
+ TSRX_RETURN_STATEMENT_ERROR,
246
+ TSRX_WHILE_STATEMENT_ERROR,
255
247
  get_return_keyword_node as getReturnKeywordNode,
256
248
  get_statement_keyword_node as getStatementKeywordNode,
257
- validate_class_component_declarations as validateClassComponentDeclarations,
258
- validate_component_loop_break_statement as validateComponentLoopBreakStatement,
259
- validate_component_loop_return_statement as validateComponentLoopReturnStatement,
260
- validate_component_params as validateComponentParams,
261
- validate_component_return_statement as validateComponentReturnStatement,
262
- validate_component_unsupported_loop_statement as validateComponentUnsupportedLoopStatement,
249
+ validate_tsrx_loop_break_statement as validateTsrxLoopBreakStatement,
250
+ validate_tsrx_loop_return_statement as validateTsrxLoopReturnStatement,
251
+ validate_tsrx_return_statement as validateTsrxReturnStatement,
252
+ validate_tsrx_unsupported_loop_statement as validateTsrxUnsupportedLoopStatement,
263
253
  validate_nesting as validateNesting,
264
254
  } from './analyze/validation.js';
@@ -145,6 +145,36 @@ function elementTemplateClosingTagPlugin(Base) {
145
145
  return false;
146
146
  }
147
147
 
148
+ /**
149
+ * @param {any} parser
150
+ */
151
+ function isOpeningTagAfterReturnKeyword(parser) {
152
+ if (parser.input.charCodeAt(parser.start + 1) === 47 /* '/' */) return false;
153
+
154
+ let index = parser.start - 1;
155
+ while (index >= 0) {
156
+ const ch = parser.input.charCodeAt(index);
157
+ if (ch === 32 /* ' ' */ || ch === 9 /* '\t' */) {
158
+ index--;
159
+ continue;
160
+ }
161
+ if (ch === 10 /* '\n' */ || ch === 13 /* '\r' */) return false;
162
+ break;
163
+ }
164
+
165
+ const end = index + 1;
166
+ const start = end - 'return'.length;
167
+ if (start < 0 || parser.input.slice(start, end) !== 'return') return false;
168
+ const before = start > 0 ? parser.input.charCodeAt(start - 1) : -1;
169
+ return !(
170
+ (before >= 48 /* '0' */ && before <= 57) ||
171
+ (before >= 65 /* 'A' */ && before <= 90) ||
172
+ (before >= 97 /* 'a' */ && before <= 122) ||
173
+ before === 36 /* '$' */ ||
174
+ before === 95 /* '_' */
175
+ );
176
+ }
177
+
148
178
  return class extends Base {
149
179
  /** @param {number} code */
150
180
  // @ts-ignore — extending acorn's Parser with internal hooks
@@ -165,7 +195,13 @@ function elementTemplateClosingTagPlugin(Base) {
165
195
  // @ts-ignore — extending acorn's Parser with internal hooks
166
196
  canInsertSemicolon() {
167
197
  const self = /** @type {any} */ (this);
168
- if (self.type === jsxTagStart && inElementTemplateBodyAnywhere(self)) return true;
198
+ if (
199
+ self.type === jsxTagStart &&
200
+ inElementTemplateBodyAnywhere(self) &&
201
+ !isOpeningTagAfterReturnKeyword(self)
202
+ ) {
203
+ return true;
204
+ }
169
205
  // @ts-ignore
170
206
  return super.canInsertSemicolon();
171
207
  }
@@ -592,7 +628,6 @@ export function get_comment_handlers(source, comments, index = 0) {
592
628
  if (
593
629
  parent.type === 'BlockStatement' ||
594
630
  parent.type === 'Program' ||
595
- parent.type === 'Component' ||
596
631
  parent.type === 'ClassBody'
597
632
  ) {
598
633
  node_array = parent.body;
@@ -783,8 +818,6 @@ export function get_comment_handlers(source, comments, index = 0) {
783
818
  const isStatementContext =
784
819
  parent.type === 'BlockStatement' || parent.type === 'Program';
785
820
 
786
- // Don't apply for Component - let Prettier handle comment attachment there
787
- // Component bodies have different comment handling via metadata.elementLeadingComments
788
821
  if (!isStatementContext) {
789
822
  return;
790
823
  }