@tsrx/prettier-plugin 0.3.41 → 0.3.43

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tsrx/prettier-plugin",
3
- "version": "0.3.41",
3
+ "version": "0.3.43",
4
4
  "description": "Ripple plugin for Prettier",
5
5
  "type": "module",
6
6
  "module": "src/index.js",
@@ -26,11 +26,11 @@
26
26
  "devDependencies": {
27
27
  "@types/node": "^24.3.0",
28
28
  "prettier": "^3.8.3",
29
- "ripple": "0.3.41"
29
+ "ripple": "0.3.43"
30
30
  },
31
31
  "dependencies": {
32
- "@tsrx/core": "0.0.21",
33
- "@tsrx/ripple": "0.0.23"
32
+ "@tsrx/core": "0.0.23",
33
+ "@tsrx/ripple": "0.0.25"
34
34
  },
35
35
  "files": [
36
36
  "src/"
package/src/index.js CHANGED
@@ -1427,8 +1427,8 @@ function printRippleNode(node, path, options, print, args) {
1427
1427
  break;
1428
1428
  }
1429
1429
 
1430
- case 'StyleIdentifier': {
1431
- nodeContent = '#style';
1430
+ case 'Style': {
1431
+ nodeContent = ['style ', path.call(print, 'value')];
1432
1432
  break;
1433
1433
  }
1434
1434
 
@@ -1444,11 +1444,6 @@ function printRippleNode(node, path, options, print, args) {
1444
1444
  break;
1445
1445
  }
1446
1446
 
1447
- case 'ServerIdentifier': {
1448
- nodeContent = '#server';
1449
- break;
1450
- }
1451
-
1452
1447
  case 'UnaryExpression':
1453
1448
  nodeContent = printUnaryExpression(node, path, options, print);
1454
1449
  break;
@@ -1695,15 +1690,17 @@ function printRippleNode(node, path, options, print, args) {
1695
1690
  nodeContent = printFunctionExpression(node, path, options, print);
1696
1691
  break;
1697
1692
 
1693
+ case 'TSModuleBlock':
1698
1694
  case 'BlockStatement': {
1699
1695
  // Apply the same block formatting pattern as component bodies
1700
1696
  if (!node.body || node.body.length === 0) {
1701
1697
  // Handle innerComments for empty blocks
1702
1698
  if (innerCommentParts.length > 0) {
1699
+ const blockNode = /** @type {AST.BlockStatement} */ (node);
1703
1700
  // Check if we need to preserve blank lines between comments
1704
- if (node.innerComments && node.innerComments.length > 0) {
1701
+ if (blockNode.innerComments && blockNode.innerComments.length > 0) {
1705
1702
  const commentDocs = [];
1706
- const comments = node.innerComments;
1703
+ const comments = blockNode.innerComments;
1707
1704
 
1708
1705
  for (let i = 0; i < comments.length; i++) {
1709
1706
  const comment = comments[i];
@@ -1804,9 +1801,14 @@ function printRippleNode(node, path, options, print, args) {
1804
1801
  break;
1805
1802
  }
1806
1803
 
1807
- case 'ServerBlock': {
1808
- const blockContent = path.call(print, 'body');
1809
- nodeContent = ['#server ', blockContent];
1804
+ case 'TSModuleDeclaration': {
1805
+ nodeContent = [
1806
+ node.metadata?.module_keyword ?? 'module',
1807
+ ' ',
1808
+ path.call(print, 'id'),
1809
+ ' ',
1810
+ path.call(print, 'body'),
1811
+ ];
1810
1812
  break;
1811
1813
  }
1812
1814
 
@@ -2387,11 +2389,13 @@ function printImportDeclaration(node, path, options, _print) {
2387
2389
  parts.push(' from');
2388
2390
  }
2389
2391
 
2390
- parts.push(
2391
- ' ',
2392
- formatStringLiteral(/** @type {string} */ (node.source.value), options),
2393
- semi(options),
2394
- );
2392
+ const source = /** @type {AST.Literal | AST.Identifier} */ (/** @type {unknown} */ (node.source));
2393
+ const sourceDoc =
2394
+ source.type === 'Identifier'
2395
+ ? source.name
2396
+ : formatStringLiteral(/** @type {string} */ (source.value), options);
2397
+
2398
+ parts.push(' ', sourceDoc, semi(options));
2395
2399
 
2396
2400
  return parts;
2397
2401
  }
@@ -2430,8 +2434,15 @@ function printExportNamedDeclaration(node, path, options, print) {
2430
2434
  parts.push(' }');
2431
2435
 
2432
2436
  if (node.source) {
2437
+ const source = /** @type {AST.Literal | AST.Identifier} */ (
2438
+ /** @type {unknown} */ (node.source)
2439
+ );
2433
2440
  parts.push(' from ');
2434
- parts.push(formatStringLiteral(/** @type {string} */ (node.source.value), options));
2441
+ parts.push(
2442
+ source.type === 'Identifier'
2443
+ ? source.name
2444
+ : formatStringLiteral(/** @type {string} */ (source.value), options),
2445
+ );
2435
2446
  }
2436
2447
  parts.push(semi(options));
2437
2448
 
@@ -5748,6 +5759,12 @@ function printJSXElement(node, path, options, print) {
5748
5759
  const hasAttributes = openingElement.attributes && openingElement.attributes.length > 0;
5749
5760
  const hasChildren = node.children && node.children.length > 0;
5750
5761
 
5762
+ /** @type {Doc} */
5763
+ let typeArgsDoc = '';
5764
+ if (openingElement.typeArguments) {
5765
+ typeArgsDoc = path.call(print, 'openingElement', 'typeArguments');
5766
+ }
5767
+
5751
5768
  // Format attributes
5752
5769
  /** @type {Doc} */
5753
5770
  let attributesDoc = '';
@@ -5778,11 +5795,11 @@ function printJSXElement(node, path, options, print) {
5778
5795
  }
5779
5796
 
5780
5797
  if (isSelfClosing) {
5781
- return ['<', tagName, attributesDoc, ' />'];
5798
+ return ['<', tagName, typeArgsDoc, attributesDoc, ' />'];
5782
5799
  }
5783
5800
 
5784
5801
  if (!hasChildren) {
5785
- return ['<', tagName, attributesDoc, '></', tagName, '>'];
5802
+ return ['<', tagName, typeArgsDoc, attributesDoc, '></', tagName, '>'];
5786
5803
  }
5787
5804
 
5788
5805
  // Format children - filter out empty text nodes and merge adjacent text nodes
@@ -5826,7 +5843,7 @@ function printJSXElement(node, path, options, print) {
5826
5843
 
5827
5844
  // Check if content can be inlined (single text node or single expression)
5828
5845
  if (childrenDocs.length === 1 && typeof childrenDocs[0] === 'string') {
5829
- return ['<', tagName, attributesDoc, '>', childrenDocs[0], '</', tagName, '>'];
5846
+ return ['<', tagName, typeArgsDoc, attributesDoc, '>', childrenDocs[0], '</', tagName, '>'];
5830
5847
  }
5831
5848
 
5832
5849
  // Multiple children or complex children - format with line breaks
@@ -5842,6 +5859,7 @@ function printJSXElement(node, path, options, print) {
5842
5859
  return group([
5843
5860
  '<',
5844
5861
  tagName,
5862
+ typeArgsDoc,
5845
5863
  attributesDoc,
5846
5864
  '>',
5847
5865
  indent([hardline, ...formattedChildren]),
@@ -6019,6 +6037,12 @@ function is_attribute_value_breakable(value, is_nested_in_object = false) {
6019
6037
  function printElement(element, path, options, print) {
6020
6038
  const node = /** @type {AST.Element & AST.NodeWithLocation} */ (element);
6021
6039
  const tagName = printMemberExpressionSimple(node.id, options);
6040
+ const openingElement = /** @type {any} */ (node.openingElement);
6041
+ /** @type {Doc} */
6042
+ let typeArgsDoc = '';
6043
+ if (openingElement?.typeArguments) {
6044
+ typeArgsDoc = path.call(print, 'openingElement', 'typeArguments');
6045
+ }
6022
6046
  const elementLeadingComments = getElementLeadingComments(node);
6023
6047
 
6024
6048
  // `metadata.elementLeadingComments` may include comments that actually appear *inside* the element
@@ -6095,7 +6119,7 @@ function printElement(element, path, options, print) {
6095
6119
  }
6096
6120
 
6097
6121
  if (isSelfClosing && !hasInnerComments && !hasAttributes) {
6098
- const elementDoc = group(['<', tagName, ' />']);
6122
+ const elementDoc = group(['<', tagName, typeArgsDoc, ' />']);
6099
6123
  return metadataCommentParts.length > 0 ? [...metadataCommentParts, elementDoc] : elementDoc;
6100
6124
  }
6101
6125
 
@@ -6146,6 +6170,7 @@ function printElement(element, path, options, print) {
6146
6170
  const openingTag = group([
6147
6171
  '<',
6148
6172
  tagName,
6173
+ typeArgsDoc,
6149
6174
  hasAttributes
6150
6175
  ? indent([
6151
6176
  ...attrDocs,
package/src/index.test.js CHANGED
@@ -3477,6 +3477,46 @@ declare function processData<T>(data: T): Promise<T>;`;
3477
3477
  expect(result).toBeWithNewline(expected);
3478
3478
  });
3479
3479
 
3480
+ it('should preserve generic type arguments on JSX component tags', async () => {
3481
+ const input = `type User = { name: string };
3482
+ component RenderProp<Item>(props: { children: (item: Item) => any }) {}
3483
+ export component App() {
3484
+ <RenderProp<User>>
3485
+ {(item) => item.name}
3486
+ </RenderProp>
3487
+ }`;
3488
+
3489
+ const expected = `type User = { name: string };
3490
+ component RenderProp<Item>(props: { children: (item: Item) => any }) {}
3491
+ export component App() {
3492
+ <RenderProp<User>>
3493
+ {(item) => item.name}
3494
+ </RenderProp>
3495
+ }`;
3496
+
3497
+ const result = await format(input);
3498
+ expect(result).toBeWithNewline(expected);
3499
+ });
3500
+
3501
+ it('should preserve generic type arguments on self-closing JSX component tags', async () => {
3502
+ const input = `component Box<T>({ value }: { value: T }) {
3503
+ <div>{String(value)}</div>
3504
+ }
3505
+ export component App() {
3506
+ <Box<string> value="hi" />
3507
+ }`;
3508
+
3509
+ const expected = `component Box<T>({ value }: { value: T }) {
3510
+ <div>{String(value)}</div>
3511
+ }
3512
+ export component App() {
3513
+ <Box<string> value="hi" />
3514
+ }`;
3515
+
3516
+ const result = await format(input);
3517
+ expect(result).toBeWithNewline(expected);
3518
+ });
3519
+
3480
3520
  it('should preserve multiple generics on method shorthand', async () => {
3481
3521
  const input = `const obj = {
3482
3522
  method<V, T, U>(): { build: () => V; data: T; key: U } {