@ripple-ts/prettier-plugin 0.2.192 → 0.2.193

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.192",
3
+ "version": "0.2.193",
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.192"
28
+ "ripple": "0.2.193"
29
29
  },
30
30
  "dependencies": {},
31
31
  "files": [
package/src/index.js CHANGED
@@ -688,6 +688,10 @@ function printRippleNode(node, path, options, print, args) {
688
688
  nodeContent = printForStatement(node, path, options, print);
689
689
  break;
690
690
 
691
+ case 'ForInStatement':
692
+ nodeContent = printForInStatement(node, path, options, print);
693
+ break;
694
+
691
695
  case 'WhileStatement':
692
696
  nodeContent = printWhileStatement(node, path, options, print);
693
697
  break;
@@ -2345,7 +2349,8 @@ function printVariableDeclaration(node, path, options, print) {
2345
2349
  const parentNode = path.getParentNode();
2346
2350
  const isForLoopInit =
2347
2351
  (parentNode && parentNode.type === 'ForStatement' && parentNode.init === node) ||
2348
- (parentNode && parentNode.type === 'ForOfStatement' && parentNode.left === node);
2352
+ (parentNode && parentNode.type === 'ForOfStatement' && parentNode.left === node) ||
2353
+ (parentNode && parentNode.type === 'ForInStatement' && parentNode.left === node);
2349
2354
 
2350
2355
  const declarations = path.map(print, 'declarations');
2351
2356
  const declarationParts = join(', ', declarations);
@@ -2880,6 +2885,19 @@ function printIfStatement(node, path, options, print) {
2880
2885
  return concat(parts);
2881
2886
  }
2882
2887
 
2888
+ function printForInStatement(node, path, options, print) {
2889
+ const parts = [];
2890
+ parts.push('for (');
2891
+ parts.push(path.call(print, 'left'));
2892
+ parts.push(' in ');
2893
+ parts.push(path.call(print, 'right'));
2894
+
2895
+ parts.push(') ');
2896
+ parts.push(path.call(print, 'body'));
2897
+
2898
+ return parts;
2899
+ }
2900
+
2883
2901
  function printForOfStatement(node, path, options, print) {
2884
2902
  const parts = [];
2885
2903
  parts.push('for (');
@@ -4404,6 +4422,14 @@ function createElementLevelCommentParts(comments) {
4404
4422
  return parts;
4405
4423
  }
4406
4424
 
4425
+ function createElementLevelCommentPartsTrimmed(comments) {
4426
+ const parts = createElementLevelCommentParts(comments);
4427
+ if (parts.length > 0 && parts[parts.length - 1] === hardline) {
4428
+ parts.pop();
4429
+ }
4430
+ return parts;
4431
+ }
4432
+
4407
4433
  function printTsxCompat(node, path, options, print) {
4408
4434
  const tagName = `<tsx:${node.kind}>`;
4409
4435
  const closingTagName = `</tsx:${node.kind}>`;
@@ -4701,10 +4727,37 @@ function printElement(node, path, options, print) {
4701
4727
  const tagName = printMemberExpressionSimple(node.id, options);
4702
4728
 
4703
4729
  const elementLeadingComments = getElementLeadingComments(node);
4730
+ const openingTagEndIndex =
4731
+ node?.metadata && typeof node.metadata.openingTagEnd === 'number'
4732
+ ? node.metadata.openingTagEnd
4733
+ : null;
4734
+ const nodeStartIndex = typeof node.start === 'number' ? node.start : null;
4735
+ const nodeEndIndex = typeof node.end === 'number' ? node.end : null;
4736
+
4737
+ // `metadata.elementLeadingComments` may include comments that actually appear *inside* the element
4738
+ // body (after the opening tag). Those must not be hoisted before the element.
4739
+ const outerElementLeadingComments =
4740
+ openingTagEndIndex == null || nodeStartIndex == null
4741
+ ? elementLeadingComments
4742
+ : elementLeadingComments.filter(
4743
+ (comment) => typeof comment.start !== 'number' || comment.start < nodeStartIndex,
4744
+ );
4745
+ const innerElementBodyComments =
4746
+ openingTagEndIndex != null && nodeEndIndex != null
4747
+ ? elementLeadingComments.filter(
4748
+ (comment) =>
4749
+ typeof comment.start === 'number' &&
4750
+ comment.start >= openingTagEndIndex &&
4751
+ comment.start < nodeEndIndex,
4752
+ )
4753
+ : [];
4754
+
4704
4755
  const metadataCommentParts =
4705
- elementLeadingComments.length > 0 ? createElementLevelCommentParts(elementLeadingComments) : [];
4756
+ outerElementLeadingComments.length > 0
4757
+ ? createElementLevelCommentParts(outerElementLeadingComments)
4758
+ : [];
4706
4759
  const fallbackElementComments = [];
4707
- const shouldLiftTextLevelComments = elementLeadingComments.length === 0;
4760
+ const shouldLiftTextLevelComments = outerElementLeadingComments.length === 0;
4708
4761
 
4709
4762
  const hasChildren = Array.isArray(node.children) && node.children.length > 0;
4710
4763
  const hasInnerComments = Array.isArray(node.innerComments) && node.innerComments.length > 0;
@@ -4787,10 +4840,41 @@ function printElement(node, path, options, print) {
4787
4840
  // Has children - use unified children processing
4788
4841
  // Build children with whitespace preservation
4789
4842
  const finalChildren = [];
4843
+ const sortedInnerElementBodyComments =
4844
+ innerElementBodyComments.length > 0
4845
+ ? innerElementBodyComments
4846
+ .slice()
4847
+ .sort((a, b) => (a.start ?? 0) - (b.start ?? 0))
4848
+ : [];
4849
+ let innerElementBodyCommentIndex = 0;
4790
4850
 
4791
4851
  for (let i = 0; i < node.children.length; i++) {
4792
4852
  const currentChild = node.children[i];
4793
4853
  const nextChild = node.children[i + 1];
4854
+
4855
+ // Insert any element-body comments that appear before this child.
4856
+ if (innerElementBodyCommentIndex < sortedInnerElementBodyComments.length) {
4857
+ const currentChildStart = typeof currentChild.start === 'number' ? currentChild.start : null;
4858
+ if (currentChildStart != null) {
4859
+ const commentsBefore = [];
4860
+ while (innerElementBodyCommentIndex < sortedInnerElementBodyComments.length) {
4861
+ const comment = sortedInnerElementBodyComments[innerElementBodyCommentIndex];
4862
+ if (typeof comment.start !== 'number' || comment.start >= currentChildStart) {
4863
+ break;
4864
+ }
4865
+ commentsBefore.push(comment);
4866
+ innerElementBodyCommentIndex++;
4867
+ }
4868
+ if (commentsBefore.length > 0) {
4869
+ if (finalChildren.length > 0) {
4870
+ finalChildren.push(hardline);
4871
+ }
4872
+ finalChildren.push(...createElementLevelCommentPartsTrimmed(commentsBefore));
4873
+ finalChildren.push(hardline);
4874
+ }
4875
+ }
4876
+ }
4877
+
4794
4878
  const isTextLikeChild = currentChild.type === 'Text' || currentChild.type === 'Html';
4795
4879
  const hasTextLeadingComments =
4796
4880
  shouldLiftTextLevelComments &&
@@ -4827,7 +4911,58 @@ function printElement(node, path, options, print) {
4827
4911
  : printedChild;
4828
4912
  finalChildren.push(childDoc);
4829
4913
 
4914
+ // Insert element-body comments that fall between this child and the next child (or the closing tag).
4915
+ let insertedBodyCommentsBetween = false;
4916
+ if (innerElementBodyCommentIndex < sortedInnerElementBodyComments.length) {
4917
+ const currentChildEnd = getNodeEndIndex(currentChild);
4918
+ const nextChildStart = nextChild && typeof nextChild.start === 'number' ? nextChild.start : null;
4919
+ if (typeof currentChildEnd === 'number') {
4920
+ const commentsBetween = [];
4921
+ while (innerElementBodyCommentIndex < sortedInnerElementBodyComments.length) {
4922
+ const comment = sortedInnerElementBodyComments[innerElementBodyCommentIndex];
4923
+ if (typeof comment.start !== 'number') {
4924
+ innerElementBodyCommentIndex++;
4925
+ continue;
4926
+ }
4927
+ if (comment.start < currentChildEnd) {
4928
+ break;
4929
+ }
4930
+ if (nextChildStart != null && comment.start >= nextChildStart) {
4931
+ break;
4932
+ }
4933
+ commentsBetween.push(comment);
4934
+ innerElementBodyCommentIndex++;
4935
+ }
4936
+ if (commentsBetween.length > 0) {
4937
+ const firstComment = commentsBetween[0];
4938
+ const lastComment = commentsBetween[commentsBetween.length - 1];
4939
+
4940
+ // Preserve any blank line(s) that existed between the previous child and the comment block.
4941
+ const blankLinesBefore = getBlankLinesBetweenNodes(currentChild, firstComment);
4942
+ finalChildren.push(hardline);
4943
+ if (blankLinesBefore > 0) {
4944
+ finalChildren.push(hardline);
4945
+ }
4946
+
4947
+ finalChildren.push(...createElementLevelCommentPartsTrimmed(commentsBetween));
4948
+
4949
+ if (nextChild) {
4950
+ // Preserve any blank line(s) that existed between the comment block and the next child.
4951
+ const blankLinesAfter = getBlankLinesBetweenNodes(lastComment, nextChild);
4952
+ finalChildren.push(hardline);
4953
+ if (blankLinesAfter > 0) {
4954
+ finalChildren.push(hardline);
4955
+ }
4956
+ }
4957
+ insertedBodyCommentsBetween = true;
4958
+ }
4959
+ }
4960
+ }
4961
+
4830
4962
  if (nextChild) {
4963
+ if (insertedBodyCommentsBetween) {
4964
+ continue;
4965
+ }
4831
4966
  const whitespaceLinesCount = getBlankLinesBetweenNodes(currentChild, nextChild);
4832
4967
  const isTextOrHtmlChild =
4833
4968
  currentChild.type === 'Text' ||
package/src/index.test.js CHANGED
@@ -17,11 +17,15 @@ expect.extend({
17
17
  message: () => {
18
18
  const { matcherHint, EXPECTED_COLOR, RECEIVED_COLOR } = this.utils;
19
19
 
20
- // Just apply color without modifying the string
20
+ /**
21
+ * @param {string} str
22
+ * @param {(str: string) => string} colorFn
23
+ */
21
24
  const formatWithColor = (str, colorFn) => {
22
25
  return colorFn(str);
23
26
  };
24
27
 
28
+ // Just apply color without modifying the string
25
29
  return (
26
30
  matcherHint('toBeWithNewline') +
27
31
  '\n\nExpected:\n' +
@@ -1903,6 +1907,53 @@ function test() {
1903
1907
  expect(result).toBeWithNewline(expected);
1904
1908
  });
1905
1909
 
1910
+ it('should preserve the exact order with a commented out component a text literal sibling', async () => {
1911
+ const expected = `component Something({ children }) {
1912
+ const test = 'yo';
1913
+ <Another>
1914
+ {\`Content inside \${test} Another component\`}
1915
+ // component children() {
1916
+ // <span>{'Child Component'}</span>
1917
+ // }
1918
+ </Another>
1919
+ }`;
1920
+
1921
+ const result = await format(expected, { singleQuote: true });
1922
+ expect(result).toBeWithNewline(expected);
1923
+ });
1924
+
1925
+ it('should preserve the blank line between a commented out component and text literal sibling', async () => {
1926
+ const expected = `component Something({ children }) {
1927
+ const test = 'yo';
1928
+ <Another>
1929
+ {\`Content inside \${test} Another component\`}
1930
+
1931
+ // component children() {
1932
+ // <span>{'Child Component'}</span>
1933
+ // }
1934
+ </Another>
1935
+ }`;
1936
+
1937
+ const result = await format(expected, { singleQuote: true });
1938
+ expect(result).toBeWithNewline(expected);
1939
+ });
1940
+
1941
+ it('should preserve the blank line between a component and text literal sibling inside element', async () => {
1942
+ const expected = `component Something({ children }) {
1943
+ const test = 'yo';
1944
+ <Another>
1945
+ {\`Content inside \${test} Another component\`}
1946
+
1947
+ component children() {
1948
+ <span>{'Child Component'}</span>
1949
+ }
1950
+ </Another>
1951
+ }`;
1952
+
1953
+ const result = await format(expected, { singleQuote: true });
1954
+ expect(result).toBeWithNewline(expected);
1955
+ });
1956
+
1906
1957
  it('should preserve trailing comments in function parameters', async () => {
1907
1958
  const expected = `function test(
1908
1959
  // comment in params