@ripple-ts/prettier-plugin 0.2.157 → 0.2.159

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": "@ripple-ts/prettier-plugin",
3
- "version": "0.2.157",
3
+ "version": "0.2.159",
4
4
  "description": "Ripple plugin for Prettier",
5
5
  "type": "module",
6
6
  "module": "src/index.js",
@@ -25,7 +25,7 @@
25
25
  },
26
26
  "devDependencies": {
27
27
  "prettier": "^3.6.2",
28
- "ripple": "0.2.157"
28
+ "ripple": "0.2.159"
29
29
  },
30
30
  "dependencies": {},
31
31
  "files": [
package/src/index.js CHANGED
@@ -1168,6 +1168,11 @@ function printRippleNode(node, path, options, print, args) {
1168
1168
  break;
1169
1169
  }
1170
1170
 
1171
+ case 'JSXExpressionContainer': {
1172
+ nodeContent = concat(['{', path.call(print, 'expression'), '}']);
1173
+ break;
1174
+ }
1175
+
1171
1176
  case 'NewExpression':
1172
1177
  nodeContent = printNewExpression(node, path, options, print);
1173
1178
  break;
@@ -3641,6 +3646,45 @@ function printProperty(node, path, options, print) {
3641
3646
 
3642
3647
  const parts = [];
3643
3648
 
3649
+ // Handle getter/setter methods
3650
+ if (node.kind === 'get' || node.kind === 'set') {
3651
+ const methodParts = [];
3652
+ const funcValue = node.value;
3653
+
3654
+ // Add get/set keyword
3655
+ methodParts.push(node.kind, ' ');
3656
+
3657
+ // Print key (with computed property brackets if needed)
3658
+ if (node.computed) {
3659
+ methodParts.push('[', path.call(print, 'key'), ']');
3660
+ } else if (node.key.type === 'Literal' && typeof node.key.value === 'string') {
3661
+ const key = node.key.value;
3662
+ const isValidIdentifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key);
3663
+ if (isValidIdentifier) {
3664
+ methodParts.push(key);
3665
+ } else {
3666
+ methodParts.push(formatStringLiteral(key, options));
3667
+ }
3668
+ } else {
3669
+ methodParts.push(path.call(print, 'key'));
3670
+ }
3671
+
3672
+ // Print parameters by calling into the value path
3673
+ const paramsPart = path.call(
3674
+ (valuePath) => printFunctionParameters(valuePath, options, print),
3675
+ 'value',
3676
+ );
3677
+ methodParts.push(group(paramsPart));
3678
+
3679
+ // Handle return type annotation
3680
+ if (funcValue.returnType) {
3681
+ methodParts.push(': ', path.call(print, 'value', 'returnType'));
3682
+ }
3683
+
3684
+ methodParts.push(' ', path.call(print, 'value', 'body'));
3685
+ return concat(methodParts);
3686
+ }
3687
+
3644
3688
  // Handle method shorthand: increment() {} instead of increment: function() {}
3645
3689
  if (node.method && node.value.type === 'FunctionExpression') {
3646
3690
  const methodParts = [];
@@ -4325,27 +4369,57 @@ function printTsxCompat(node, path, options, print) {
4325
4369
  }
4326
4370
 
4327
4371
  // Print JSXElement children - they remain as JSX
4328
- // Filter out whitespace-only JSXText nodes
4372
+ // Filter out whitespace-only JSXText nodes and merge adjacent text-like nodes
4329
4373
  const finalChildren = [];
4374
+ let accumulatedText = '';
4330
4375
 
4331
4376
  for (let i = 0; i < node.children.length; i++) {
4332
4377
  const child = node.children[i];
4333
4378
 
4334
- // Skip whitespace-only JSXText nodes
4335
- if (child.type === 'JSXText' && !child.value.trim()) {
4336
- continue;
4337
- }
4379
+ // Check if this is a text-like node (JSXText or Identifier in JSX context)
4380
+ const isTextLike = child.type === 'JSXText' || child.type === 'Identifier';
4338
4381
 
4339
- const printedChild = path.call(print, 'children', i);
4340
- finalChildren.push(printedChild);
4382
+ if (isTextLike) {
4383
+ // Get the text content
4384
+ let text;
4385
+ if (child.type === 'JSXText') {
4386
+ text = child.value.trim();
4387
+ } else if (child.type === 'Identifier') {
4388
+ text = child.name;
4389
+ }
4341
4390
 
4342
- if (i < node.children.length - 1) {
4343
- // Only add hardline if the next child is not whitespace-only
4344
- const nextChild = node.children[i + 1];
4345
- if (nextChild && !(nextChild.type === 'JSXText' && !nextChild.value.trim())) {
4391
+ if (text) {
4392
+ if (accumulatedText) {
4393
+ accumulatedText += ' ' + text;
4394
+ } else {
4395
+ accumulatedText = text;
4396
+ }
4397
+ }
4398
+ } else {
4399
+ // Before adding non-text node, flush accumulated text
4400
+ if (accumulatedText) {
4401
+ if (finalChildren.length > 0) {
4402
+ finalChildren.push(hardline);
4403
+ }
4404
+ finalChildren.push(accumulatedText);
4405
+ accumulatedText = '';
4406
+ }
4407
+
4408
+ if (finalChildren.length > 0) {
4346
4409
  finalChildren.push(hardline);
4347
4410
  }
4411
+
4412
+ const printedChild = path.call(print, 'children', i);
4413
+ finalChildren.push(printedChild);
4414
+ }
4415
+ }
4416
+
4417
+ // Don't forget any remaining accumulated text
4418
+ if (accumulatedText) {
4419
+ if (finalChildren.length > 0) {
4420
+ finalChildren.push(hardline);
4348
4421
  }
4422
+ finalChildren.push(accumulatedText);
4349
4423
  }
4350
4424
 
4351
4425
  // Format the TsxCompat element
@@ -4404,26 +4478,45 @@ function printJSXElement(node, path, options, print) {
4404
4478
  return concat(['<', tagName, attributesDoc, '></', tagName, '>']);
4405
4479
  }
4406
4480
 
4407
- // Format children - filter out empty text nodes
4481
+ // Format children - filter out empty text nodes and merge adjacent text nodes
4408
4482
  const childrenDocs = [];
4483
+ let currentText = '';
4484
+
4409
4485
  for (let i = 0; i < node.children.length; i++) {
4410
4486
  const child = node.children[i];
4411
4487
 
4412
4488
  if (child.type === 'JSXText') {
4413
- // Handle JSX text nodes - only include if not just whitespace
4414
- const text = child.value;
4415
- if (text.trim()) {
4416
- childrenDocs.push(text);
4489
+ // Accumulate text content, preserving spaces between words
4490
+ const trimmed = child.value.trim();
4491
+ if (trimmed) {
4492
+ if (currentText) {
4493
+ currentText += ' ' + trimmed;
4494
+ } else {
4495
+ currentText = trimmed;
4496
+ }
4417
4497
  }
4418
- } else if (child.type === 'JSXExpressionContainer') {
4419
- // Handle JSX expression containers
4420
- childrenDocs.push(concat(['{', path.call(print, 'children', i, 'expression'), '}']));
4421
4498
  } else {
4422
- // Handle nested JSX elements
4423
- childrenDocs.push(path.call(print, 'children', i));
4499
+ // If we have accumulated text, push it before the non-text node
4500
+ if (currentText) {
4501
+ childrenDocs.push(currentText);
4502
+ currentText = '';
4503
+ }
4504
+
4505
+ if (child.type === 'JSXExpressionContainer') {
4506
+ // Handle JSX expression containers
4507
+ childrenDocs.push(concat(['{', path.call(print, 'children', i, 'expression'), '}']));
4508
+ } else {
4509
+ // Handle nested JSX elements
4510
+ childrenDocs.push(path.call(print, 'children', i));
4511
+ }
4424
4512
  }
4425
4513
  }
4426
4514
 
4515
+ // Don't forget any remaining text
4516
+ if (currentText) {
4517
+ childrenDocs.push(currentText);
4518
+ }
4519
+
4427
4520
  // Check if content can be inlined (single text node or single expression)
4428
4521
  if (childrenDocs.length === 1 && typeof childrenDocs[0] === 'string') {
4429
4522
  return concat(['<', tagName, attributesDoc, '>', childrenDocs[0], '</', tagName, '>']);
package/src/index.test.js CHANGED
@@ -3812,6 +3812,108 @@ component Polygon() {
3812
3812
  const result = await format(input, { singleQuote: true });
3813
3813
  expect(result).toBeWithNewline(expected);
3814
3814
  });
3815
+
3816
+ it('should format JSXExpressionContainer with function calls', async () => {
3817
+ const input = `function foo(){return 123}component App(){<div><tsx:react>{foo()}</tsx:react></div>}`;
3818
+
3819
+ const expected = `function foo() {
3820
+ return 123;
3821
+ }
3822
+ component App() {
3823
+ <div>
3824
+ <tsx:react>
3825
+ {foo()}
3826
+ </tsx:react>
3827
+ </div>
3828
+ }`;
3829
+
3830
+ const result = await format(input);
3831
+ expect(result).toBeWithNewline(expected);
3832
+ });
3833
+
3834
+ it('should format JSXExpressionContainer with function calls', async () => {
3835
+ const input = `function foo(){return 123}component App(){<div><tsx:react>{foo()}<div>Hello world</div>Hello world</tsx:react></div>}`;
3836
+
3837
+ const expected = `function foo() {
3838
+ return 123;
3839
+ }
3840
+ component App() {
3841
+ <div>
3842
+ <tsx:react>
3843
+ {foo()}
3844
+ <div>Hello world</div>
3845
+ Hello world
3846
+ </tsx:react>
3847
+ </div>
3848
+ }`;
3849
+
3850
+ const result = await format(input);
3851
+ expect(result).toBeWithNewline(expected);
3852
+ });
3853
+
3854
+ it('should format JSXExpressionContainer with function calls #2', async () => {
3855
+ const input = `export component App() {
3856
+ <tsx:react>
3857
+ Hello world
3858
+ <DemoContext.Provider value={"Hello from Context!"}>
3859
+ <Child count={@count} />
3860
+ </DemoContext.Provider>
3861
+ </tsx:react>
3862
+ }`;
3863
+ const expected = `export component App() {
3864
+ <tsx:react>
3865
+ Hello world
3866
+ <DemoContext.Provider value={"Hello from Context!"}>
3867
+ <Child count={@count} />
3868
+ </DemoContext.Provider>
3869
+ </tsx:react>
3870
+ }`;
3871
+
3872
+ const result = await format(input);
3873
+ expect(result).toBeWithNewline(expected);
3874
+ });
3875
+ it('should format JSXExpressionContainer with complex expressions', async () => {
3876
+ const input = `component App(){let count=track(0);<tsx:react><div>{count*2+10}</div>{getMessage("test")}</tsx:react>}`;
3877
+
3878
+ const expected = `component App() {
3879
+ let count = track(0);
3880
+ <tsx:react>
3881
+ <div>
3882
+ {count * 2 + 10}
3883
+ </div>
3884
+ {getMessage('test')}
3885
+ </tsx:react>
3886
+ }`;
3887
+
3888
+ const result = await format(input, { singleQuote: true });
3889
+ expect(result).toBeWithNewline(expected);
3890
+ });
3891
+ });
3892
+
3893
+ describe('object getters and setters', () => {
3894
+ it('should preserve get and set keywords in object methods', async () => {
3895
+ const input = `const foo = {
3896
+ get bar() {
3897
+ return 0
3898
+ },
3899
+
3900
+ set baz(arg: 0) {
3901
+ //
3902
+ }
3903
+ }`;
3904
+ const expected = `const foo = {
3905
+ get bar() {
3906
+ return 0;
3907
+ },
3908
+
3909
+ set baz(arg: 0) {
3910
+ //
3911
+ },
3912
+ };`;
3913
+
3914
+ const result = await format(input);
3915
+ expect(result).toBeWithNewline(expected);
3916
+ });
3815
3917
  });
3816
3918
  });
3817
3919
  });