@openrewrite/rewrite 8.92.16 → 8.92.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.
Files changed (79) hide show
  1. package/dist/javascript/comparator.d.ts.map +1 -1
  2. package/dist/javascript/comparator.js +4 -0
  3. package/dist/javascript/comparator.js.map +1 -1
  4. package/dist/javascript/format/tabs-and-indents-visitor.d.ts.map +1 -1
  5. package/dist/javascript/format/tabs-and-indents-visitor.js +31 -4
  6. package/dist/javascript/format/tabs-and-indents-visitor.js.map +1 -1
  7. package/dist/javascript/markers.d.ts +12 -0
  8. package/dist/javascript/markers.d.ts.map +1 -1
  9. package/dist/javascript/markers.js +17 -2
  10. package/dist/javascript/markers.js.map +1 -1
  11. package/dist/javascript/node-resolution-result.js +3 -2
  12. package/dist/javascript/node-resolution-result.js.map +1 -1
  13. package/dist/javascript/parser.d.ts +9 -0
  14. package/dist/javascript/parser.d.ts.map +1 -1
  15. package/dist/javascript/parser.js +185 -88
  16. package/dist/javascript/parser.js.map +1 -1
  17. package/dist/javascript/print.d.ts +10 -1
  18. package/dist/javascript/print.d.ts.map +1 -1
  19. package/dist/javascript/print.js +120 -77
  20. package/dist/javascript/print.js.map +1 -1
  21. package/dist/javascript/templating/engine.d.ts.map +1 -1
  22. package/dist/javascript/templating/engine.js +8 -3
  23. package/dist/javascript/templating/engine.js.map +1 -1
  24. package/dist/javascript/type-mapping.d.ts +1 -0
  25. package/dist/javascript/type-mapping.d.ts.map +1 -1
  26. package/dist/javascript/type-mapping.js +18 -3
  27. package/dist/javascript/type-mapping.js.map +1 -1
  28. package/dist/print.d.ts +6 -1
  29. package/dist/print.d.ts.map +1 -1
  30. package/dist/print.js +21 -7
  31. package/dist/print.js.map +1 -1
  32. package/dist/rewrite-javascript-version.txt +1 -1
  33. package/dist/rpc/java-rpc-client.d.ts +2 -0
  34. package/dist/rpc/java-rpc-client.d.ts.map +1 -1
  35. package/dist/rpc/java-rpc-client.js +1 -0
  36. package/dist/rpc/java-rpc-client.js.map +1 -1
  37. package/dist/rpc/queue.d.ts +8 -0
  38. package/dist/rpc/queue.d.ts.map +1 -1
  39. package/dist/rpc/queue.js +45 -3
  40. package/dist/rpc/queue.js.map +1 -1
  41. package/dist/rpc/request/get-object.d.ts +4 -0
  42. package/dist/rpc/request/get-object.d.ts.map +1 -1
  43. package/dist/rpc/request/get-object.js +23 -1
  44. package/dist/rpc/request/get-object.js.map +1 -1
  45. package/dist/rpc/request/parse.d.ts.map +1 -1
  46. package/dist/rpc/request/parse.js +3 -1
  47. package/dist/rpc/request/parse.js.map +1 -1
  48. package/dist/rpc/request/print.d.ts +8 -2
  49. package/dist/rpc/request/print.d.ts.map +1 -1
  50. package/dist/rpc/request/print.js +12 -9
  51. package/dist/rpc/request/print.js.map +1 -1
  52. package/dist/rpc/rewrite-rpc.d.ts +3 -2
  53. package/dist/rpc/rewrite-rpc.d.ts.map +1 -1
  54. package/dist/rpc/rewrite-rpc.js +9 -3
  55. package/dist/rpc/rewrite-rpc.js.map +1 -1
  56. package/dist/rpc/server.d.ts.map +1 -1
  57. package/dist/rpc/server.js +19 -5
  58. package/dist/rpc/server.js.map +1 -1
  59. package/dist/test/java-rpc.d.ts.map +1 -1
  60. package/dist/test/java-rpc.js +3 -0
  61. package/dist/test/java-rpc.js.map +1 -1
  62. package/package.json +1 -1
  63. package/src/javascript/comparator.ts +10 -0
  64. package/src/javascript/format/tabs-and-indents-visitor.ts +30 -3
  65. package/src/javascript/markers.ts +34 -4
  66. package/src/javascript/node-resolution-result.ts +3 -2
  67. package/src/javascript/parser.ts +200 -91
  68. package/src/javascript/print.ts +123 -76
  69. package/src/javascript/templating/engine.ts +7 -2
  70. package/src/javascript/type-mapping.ts +19 -3
  71. package/src/print.ts +23 -8
  72. package/src/rpc/java-rpc-client.ts +3 -0
  73. package/src/rpc/queue.ts +37 -3
  74. package/src/rpc/request/get-object.ts +24 -0
  75. package/src/rpc/request/parse.ts +4 -1
  76. package/src/rpc/request/print.ts +12 -8
  77. package/src/rpc/rewrite-rpc.ts +16 -5
  78. package/src/rpc/server.ts +18 -6
  79. package/src/test/java-rpc.ts +3 -0
@@ -21,7 +21,7 @@ import {PrintOutputCapture, TreePrinters} from "../print";
21
21
  import {Cursor, isTree, Tree} from "../tree";
22
22
  import {Comment, emptySpace, J, Statement, TextComment, TrailingComma, TypedTree} from "../java";
23
23
  import {findMarker, Marker, Markers} from "../markers";
24
- import {DelegatedYield, FunctionDeclaration, Generator, NonNullAssertion, Optional} from "./markers";
24
+ import {Computed, DelegatedYield, FunctionDeclaration, Generator, NonNullAssertion, Optional} from "./markers";
25
25
 
26
26
  export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
27
27
 
@@ -140,10 +140,7 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
140
140
  override async visitJsxAttribute(attribute: JSX.Attribute, p: PrintOutputCapture): Promise<J | undefined> {
141
141
  await this.beforeSyntax(attribute, p);
142
142
  await this.visit(attribute.key, p);
143
- if (attribute.value) {
144
- p.append("=");
145
- await this.visit(attribute.value.element, p);
146
- }
143
+ await this.visitLeftPaddedLocal("=", attribute.value, p);
147
144
  await this.afterSyntax(attribute, p);
148
145
  return attribute;
149
146
  }
@@ -308,6 +305,10 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
308
305
  p.append("catch");
309
306
  if (aCatch.parameter.tree.element.variables.length > 0) {
310
307
  await this.visit(aCatch.parameter, p);
308
+ } else {
309
+ this.beforeSyntaxMarkers(aCatch.parameter.markers, p);
310
+ await this.markersOnly(aCatch.parameter.tree.element, p);
311
+ await this.afterSyntax(aCatch.parameter, p);
311
312
  }
312
313
  await this.visit(aCatch.body, p);
313
314
  await this.afterSyntax(aCatch, p);
@@ -662,15 +663,7 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
662
663
  if (functionType.constructorType.element) {
663
664
  await this.visitLeftPaddedLocal("new", functionType.constructorType, p);
664
665
  }
665
- const typeParameters = functionType.typeParameters;
666
- if (typeParameters) {
667
- await this.visitNodes(typeParameters.annotations, p);
668
- await this.visitSpace(typeParameters.prefix, p);
669
- await this.visitMarkers(typeParameters.markers, p);
670
- p.append("<");
671
- await this.visitRightPaddedLocal(typeParameters.typeParameters, ",", p);
672
- p.append(">");
673
- }
666
+ await this.printTypeParameters(functionType.typeParameters, p);
674
667
 
675
668
  await this.visitContainerLocal("(", functionType.parameters, ",", ")", p);
676
669
  await this.visitLeftPaddedLocal("=>", functionType.returnType, p);
@@ -679,9 +672,9 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
679
672
  return functionType;
680
673
  }
681
674
 
682
- override async visitClassDeclaration(classDecl: J.ClassDeclaration, p: PrintOutputCapture): Promise<J | undefined> {
675
+ override async visitClassDeclarationKind(classKind: J.ClassDeclaration.Kind, p: PrintOutputCapture): Promise<J | undefined> {
683
676
  let kind = "";
684
- switch (classDecl.classKind.type) {
677
+ switch (classKind.type) {
685
678
  case J.ClassDeclaration.Kind.Type.Class:
686
679
  kind = "class";
687
680
  break;
@@ -699,15 +692,21 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
699
692
  break;
700
693
  }
701
694
 
695
+ await this.visitNodes(classKind.annotations, p);
696
+ await this.beforeSyntax(classKind, p);
697
+ p.append(kind);
698
+ await this.afterSyntax(classKind, p);
699
+ return classKind;
700
+ }
701
+
702
+ override async visitClassDeclaration(classDecl: J.ClassDeclaration, p: PrintOutputCapture): Promise<J | undefined> {
702
703
  await this.beforeSyntax(classDecl, p);
703
704
  await this.visitSpace(emptySpace, p);
704
705
  await this.visitNodes(classDecl.leadingAnnotations, p);
705
706
  for (const m of classDecl.modifiers) {
706
707
  await this.visitModifier(m, p);
707
708
  }
708
- await this.visitNodes(classDecl.classKind.annotations, p);
709
- await this.visitSpace(classDecl.classKind.prefix, p);
710
- p.append(kind);
709
+ await this.visitClassDeclarationKind(classDecl.classKind, p);
711
710
  await this.visit(classDecl.name, p);
712
711
  classDecl.typeParameters && await this.visitContainerLocal("<", classDecl.typeParameters, ",", ">", p);
713
712
  classDecl.primaryConstructor && await this.visitContainerLocal("(", classDecl.primaryConstructor, ",", ")", p);
@@ -727,6 +726,7 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
727
726
  for (const m of method.modifiers) {
728
727
  await this.visitModifier(m, p);
729
728
  }
729
+ await this.visitNodes(method.nameAnnotations, p);
730
730
 
731
731
  let m;
732
732
  if ((m = findMarker<FunctionDeclaration>(method, JS.Markers.FunctionDeclaration))) {
@@ -742,15 +742,7 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
742
742
 
743
743
  await this.visit(method.name, p);
744
744
 
745
- const typeParameters = method.typeParameters;
746
- if (typeParameters) {
747
- await this.visitNodes(typeParameters.annotations, p);
748
- await this.visitSpace(typeParameters.prefix, p);
749
- await this.visitMarkers(typeParameters.markers, p);
750
- p.append("<");
751
- await this.visitRightPaddedLocal(typeParameters.typeParameters, ",", p);
752
- p.append(">");
753
- }
745
+ await this.printTypeParameters(method.typeParameters, p);
754
746
 
755
747
  await this.visitContainerLocal("(", method.parameters, ",", ")", p);
756
748
 
@@ -779,15 +771,7 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
779
771
 
780
772
  await this.visit(method.name, p);
781
773
 
782
- const typeParameters = method.typeParameters;
783
- if (typeParameters) {
784
- await this.visitNodes(typeParameters.annotations, p);
785
- await this.visitSpace(typeParameters.prefix, p);
786
- await this.visitMarkers(typeParameters.markers, p);
787
- p.append("<");
788
- await this.visitRightPaddedLocal(typeParameters.typeParameters, ",", p);
789
- p.append(">");
790
- }
774
+ await this.printTypeParameters(method.typeParameters, p);
791
775
 
792
776
  await this.visitContainerLocal("(", method.parameters, ",", ")", p);
793
777
  if (method.returnTypeExpression) {
@@ -839,12 +823,16 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
839
823
  if (!(constraintType.element.kind === J.Kind.Empty)) {
840
824
  p.append("extends");
841
825
  await this.visitRightPadded(constraintType, p);
826
+ } else {
827
+ await this.markersOnly(constraintType.element, p);
842
828
  }
843
829
 
844
830
  const defaultType = bounds.elements[1];
845
831
  if (!(defaultType.element.kind === J.Kind.Empty)) {
846
832
  p.append("=");
847
833
  await this.visitRightPadded(defaultType, p);
834
+ } else {
835
+ await this.markersOnly(defaultType.element, p);
848
836
  }
849
837
  }
850
838
 
@@ -859,26 +847,21 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
859
847
  await this.visitModifier(m, p);
860
848
  }
861
849
 
862
- const typeParameters = arrowFunction.typeParameters;
863
- if (typeParameters) {
864
- await this.visitNodes(typeParameters.annotations, p);
865
- await this.visitSpace(typeParameters.prefix, p);
866
- await this.visitMarkers(typeParameters.markers, p);
867
- p.append("<");
868
- await this.visitRightPaddedLocal(typeParameters.typeParameters, ",", p);
869
- p.append(">");
870
- }
850
+ await this.printTypeParameters(arrowFunction.typeParameters, p);
871
851
 
872
852
  const lambda = arrowFunction.lambda;
853
+ this.beforeSyntaxMarkers(lambda.markers, p);
873
854
 
874
855
  if (lambda.parameters.parenthesized) {
875
- await this.visitSpace(lambda.parameters.prefix, p);
856
+ await this.beforeSyntax(lambda.parameters, p);
876
857
  p.append("(");
877
858
  await this.visitRightPaddedLocal(lambda.parameters.parameters, ",", p);
878
859
  p.append(")");
879
860
  } else {
861
+ this.beforeSyntaxMarkers(lambda.parameters.markers, p);
880
862
  await this.visitRightPaddedLocal(lambda.parameters.parameters, ",", p);
881
863
  }
864
+ await this.afterSyntax(lambda.parameters, p);
882
865
 
883
866
  if (arrowFunction.returnTypeExpression) {
884
867
  await this.visit(arrowFunction.returnTypeExpression, p);
@@ -887,6 +870,7 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
887
870
  await this.visitSpace(lambda.arrow, p);
888
871
  p.append("=>");
889
872
  await this.visit(lambda.body, p);
873
+ await this.afterSyntax(lambda, p);
890
874
 
891
875
  await this.afterSyntax(arrowFunction, p);
892
876
  return arrowFunction;
@@ -934,15 +918,7 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
934
918
 
935
919
  await this.visitLeftPaddedLocal("type", typeDeclaration.name, p);
936
920
 
937
- const typeParameters = typeDeclaration.typeParameters;
938
- if (typeParameters) {
939
- await this.visitNodes(typeParameters.annotations, p);
940
- await this.visitSpace(typeParameters.prefix, p);
941
- await this.visitMarkers(typeParameters.markers, p);
942
- p.append("<");
943
- await this.visitRightPaddedLocal(typeParameters.typeParameters, ",", p);
944
- p.append(">");
945
- }
921
+ await this.printTypeParameters(typeDeclaration.typeParameters, p);
946
922
 
947
923
  await this.visitLeftPaddedLocal("=", typeDeclaration.initializer, p);
948
924
 
@@ -985,11 +961,11 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
985
961
  }
986
962
 
987
963
  override async visitExportDeclaration(ed: JS.ExportDeclaration, p: PrintOutputCapture): Promise<J | undefined> {
988
- await this.beforeSyntax(ed, p);
989
- p.append("export");
990
964
  for (const it of ed.modifiers) {
991
965
  await this.visitModifier(it, p);
992
966
  }
967
+ await this.beforeSyntax(ed, p);
968
+ p.append("export");
993
969
 
994
970
  if (ed.typeOnly.element) {
995
971
  await this.visitLeftPaddedLocal("type", ed.typeOnly, p);
@@ -1520,16 +1496,22 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
1520
1496
 
1521
1497
  override async visitEnumValue(enum_: J.EnumValue, p: PrintOutputCapture): Promise<J | undefined> {
1522
1498
  await this.beforeSyntax(enum_, p);
1499
+ const computed = findMarker<Computed>(enum_.name, JS.Markers.Computed);
1500
+ computed && p.append("[");
1523
1501
  await this.visit(enum_.name, p);
1502
+ if (computed) {
1503
+ await this.visitSpace(computed.suffix, p);
1504
+ p.append("]");
1505
+ }
1524
1506
 
1525
1507
  const initializer = enum_.initializer;
1526
1508
  if (initializer) {
1527
- await this.visitSpace(initializer.prefix, p);
1509
+ await this.beforeSyntax(initializer, p);
1528
1510
  p.append("=");
1529
1511
  // There can be only one argument
1530
1512
  const expression = initializer.arguments.elements[0];
1531
1513
  await this.visitRightPadded(expression, p);
1532
- return enum_;
1514
+ await this.afterSyntax(initializer, p);
1533
1515
  }
1534
1516
 
1535
1517
  await this.afterSyntax(enum_, p);
@@ -1717,13 +1699,14 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
1717
1699
  await this.beforeSyntax(forLoop, p);
1718
1700
  p.append("for");
1719
1701
  const ctrl = forLoop.control;
1720
- await this.visitSpace(ctrl.prefix, p);
1702
+ await this.beforeSyntax(ctrl, p);
1721
1703
  p.append('(');
1722
1704
  await this.visitRightPaddedLocal(ctrl.init, ",", p);
1723
1705
  p.append(';');
1724
1706
  ctrl.condition && await this.visitRightPaddedLocalSingle(ctrl.condition, ";", p);
1725
1707
  await this.visitRightPaddedLocal(ctrl.update, ",", p);
1726
1708
  p.append(')');
1709
+ await this.afterSyntax(ctrl, p);
1727
1710
  await this.visitStatementLocal(forLoop.body, p);
1728
1711
  await this.afterSyntax(forLoop, p);
1729
1712
  return forLoop;
@@ -1737,14 +1720,17 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
1737
1720
  p.append("await");
1738
1721
  }
1739
1722
 
1723
+ this.beforeSyntaxMarkers(loop.loop.markers, p);
1740
1724
  const control = loop.loop.control;
1741
- await this.visitSpace(control.prefix, p);
1725
+ await this.beforeSyntax(control, p);
1742
1726
  p.append('(');
1743
1727
  await this.visitRightPadded(control.variable, p);
1744
1728
  p.append("of");
1745
1729
  await this.visitRightPadded(control.iterable, p);
1746
1730
  p.append(')');
1731
+ await this.afterSyntax(control, p);
1747
1732
  await this.visitRightPadded(loop.loop.body, p);
1733
+ await this.afterSyntax(loop.loop, p);
1748
1734
  await this.afterSyntax(loop, p);
1749
1735
  return loop;
1750
1736
  }
@@ -1754,12 +1740,13 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
1754
1740
  p.append("for");
1755
1741
 
1756
1742
  const control = loop.control;
1757
- await this.visitSpace(control.prefix, p);
1743
+ await this.beforeSyntax(control, p);
1758
1744
  p.append('(');
1759
1745
  await this.visitRightPadded(control.variable, p);
1760
1746
  p.append("in");
1761
1747
  await this.visitRightPadded(control.iterable, p);
1762
1748
  p.append(')');
1749
+ await this.afterSyntax(control, p);
1763
1750
  await this.visitRightPadded(loop.body, p);
1764
1751
  await this.afterSyntax(loop, p);
1765
1752
  return loop;
@@ -1769,8 +1756,8 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
1769
1756
 
1770
1757
  private async visitStatements(statements: J.RightPadded<Statement>[], p: PrintOutputCapture) {
1771
1758
  const objectLiteral =
1772
- this.getParentCursor(0)?.value.kind === J.Kind.Block &&
1773
- this.getParentCursor(1)?.value.kind === J.Kind.NewClass;
1759
+ this.cursor.value.kind === J.Kind.Block &&
1760
+ this.parentTree()?.kind === J.Kind.NewClass;
1774
1761
 
1775
1762
  for (let i = 0; i < statements.length; i++) {
1776
1763
  const paddedStat = statements[i];
@@ -1789,13 +1776,73 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
1789
1776
  }
1790
1777
  }
1791
1778
 
1792
- private getParentCursor(levels: number): Cursor | undefined {
1793
- let cursor: Cursor | undefined = this.cursor;
1794
- for (let i = 0; i < levels && cursor; i++) {
1795
- cursor = cursor.parent;
1779
+ // A cursor handed in by a caller holds the padding between a tree and the tree enclosing it.
1780
+ private parentTree(): Tree | undefined {
1781
+ return this.cursor.parentTree()?.value;
1782
+ }
1783
+
1784
+ override async visitArrayAccess(arrayAccess: J.ArrayAccess, p: PrintOutputCapture): Promise<J | undefined> {
1785
+ await this.beforeSyntax(arrayAccess, p);
1786
+ await this.visit(arrayAccess.indexed, p);
1787
+ await this.visit(arrayAccess.dimension, p);
1788
+ await this.afterSyntax(arrayAccess, p);
1789
+ return arrayAccess;
1790
+ }
1791
+
1792
+ override async visitTypeCast(typeCast: J.TypeCast, p: PrintOutputCapture): Promise<J | undefined> {
1793
+ await this.beforeSyntax(typeCast, p);
1794
+ await this.visit(typeCast.class, p);
1795
+ await this.visit(typeCast.expression, p);
1796
+ await this.afterSyntax(typeCast, p);
1797
+ return typeCast;
1798
+ }
1799
+
1800
+ override async visitParenthesizedTypeTree(parTypeTree: J.ParenthesizedTypeTree, p: PrintOutputCapture): Promise<J | undefined> {
1801
+ await this.beforeSyntax(parTypeTree, p);
1802
+ await this.visitNodes(parTypeTree.annotations, p);
1803
+ await this.visit(parTypeTree.parenthesizedType, p);
1804
+ await this.afterSyntax(parTypeTree, p);
1805
+ return parTypeTree;
1806
+ }
1807
+
1808
+ override async visitEmpty(empty: J.Empty, p: PrintOutputCapture): Promise<J | undefined> {
1809
+ await this.beforeSyntax(empty, p);
1810
+ await this.afterSyntax(empty, p);
1811
+ return empty;
1812
+ }
1813
+
1814
+ override async visitUnknown(unknown: J.Unknown, p: PrintOutputCapture): Promise<J | undefined> {
1815
+ await this.beforeSyntax(unknown, p);
1816
+ await this.visit(unknown.source, p);
1817
+ await this.afterSyntax(unknown, p);
1818
+ return unknown;
1819
+ }
1820
+
1821
+ private async printTypeParameters(typeParameters: J.TypeParameters | undefined, p: PrintOutputCapture) {
1822
+ if (typeParameters) {
1823
+ await this.visitNodes(typeParameters.annotations, p);
1824
+ await this.beforeSyntaxExt(typeParameters.prefix, typeParameters.markers, p);
1825
+ p.append("<");
1826
+ await this.visitRightPaddedLocal(typeParameters.typeParameters, ",", p);
1827
+ p.append(">");
1828
+ await this.afterSyntaxMarkers(typeParameters.markers, p);
1796
1829
  }
1830
+ }
1797
1831
 
1798
- return cursor;
1832
+ // A tree that stands for something left out of the source is still printed where a recipe marked it.
1833
+ private async markersOnly(j: J, p: PrintOutputCapture) {
1834
+ this.beforeSyntaxMarkers(j.markers, p);
1835
+ await this.afterSyntax(j, p);
1836
+ }
1837
+
1838
+ // For a tree printed as part of another, whose prefix is not printed.
1839
+ private beforeSyntaxMarkers(markers: Markers, p: PrintOutputCapture) {
1840
+ for (const marker of markers.markers) {
1841
+ p.append(p.markerPrinter.beforePrefix(marker, new Cursor(marker, this.cursor), this.JAVA_SCRIPT_MARKER_WRAPPER));
1842
+ }
1843
+ for (const marker of markers.markers) {
1844
+ p.append(p.markerPrinter.beforeSyntax(marker, new Cursor(marker, this.cursor), this.JAVA_SCRIPT_MARKER_WRAPPER));
1845
+ }
1799
1846
  }
1800
1847
 
1801
1848
  protected async afterSyntax(j: J, p: PrintOutputCapture) {
@@ -1940,10 +1987,10 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
1940
1987
  }
1941
1988
  if (marker.kind === JS.Markers.Optional) {
1942
1989
  await this.visitSpace((marker as Optional).prefix, p);
1943
- if (this.cursor.parent?.value?.kind !== J.Kind.MethodInvocation &&
1944
- this.cursor.parent?.value?.kind !== JS.Kind.FunctionCall) {
1990
+ const parent = this.parentTree()?.kind;
1991
+ if (parent !== J.Kind.MethodInvocation && parent !== JS.Kind.FunctionCall) {
1945
1992
  p.append("?");
1946
- if (this.cursor.parent?.value?.kind === J.Kind.ArrayAccess) {
1993
+ if (parent === J.Kind.ArrayAccess) {
1947
1994
  p.append(".");
1948
1995
  }
1949
1996
  }
@@ -1954,7 +2001,7 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
1954
2001
 
1955
2002
  private printComment(comment: Comment, cursor: Cursor, p: PrintOutputCapture): void {
1956
2003
  for (const marker of comment.markers.markers) {
1957
- p.append(p.markerPrinter.beforeSyntax(marker, new Cursor(this, cursor), this.JAVA_SCRIPT_MARKER_WRAPPER));
2004
+ p.append(p.markerPrinter.beforeSyntax(marker, new Cursor(comment, cursor), this.JAVA_SCRIPT_MARKER_WRAPPER));
1958
2005
  }
1959
2006
 
1960
2007
  if (comment.kind === J.Kind.TextComment) {
@@ -1963,7 +2010,7 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
1963
2010
  }
1964
2011
 
1965
2012
  for (const marker of comment.markers.markers) {
1966
- p.append(p.markerPrinter.afterSyntax(marker, new Cursor(this, cursor), this.JAVA_SCRIPT_MARKER_WRAPPER));
2013
+ p.append(p.markerPrinter.afterSyntax(marker, new Cursor(comment, cursor), this.JAVA_SCRIPT_MARKER_WRAPPER));
1967
2014
  }
1968
2015
  }
1969
2016
 
@@ -1978,7 +2025,7 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
1978
2025
  override async visitControlParentheses<T extends J>(controlParens: J.ControlParentheses<T>, p: PrintOutputCapture): Promise<J | undefined> {
1979
2026
  await this.beforeSyntax(controlParens, p);
1980
2027
 
1981
- if (this.getParentCursor(1)?.value.kind === J.Kind.TypeCast) {
2028
+ if (this.parentTree()?.kind === J.Kind.TypeCast) {
1982
2029
  p.append('<');
1983
2030
  await this.visitRightPaddedLocalSingle(controlParens.tree, ">", p);
1984
2031
  } else {
@@ -845,9 +845,14 @@ export class TemplateApplier {
845
845
  return {...result, id: resultToUse.id};
846
846
  }
847
847
 
848
- // Apply auto-formatting to the result
848
+ // A recipe can apply a template to a child while its cursor still points at the
849
+ // owning node (for example, a JSX attribute's literal value). Keep that owner
850
+ // in the formatting path; dropping it loses the attribute's line indentation.
851
+ const owner = this.cursor?.value;
852
+ const parent = isTree(owner) && owner.id !== originalTree.id &&
853
+ (await treeIds(owner as J)).has(originalTree.id) ? this.cursor : this.cursor?.parent;
849
854
  const formatted =
850
- await maybeAutoFormat(originalTree, result, null, undefined, this.cursor?.parent);
855
+ await maybeAutoFormat(originalTree, result, null, undefined, parent);
851
856
 
852
857
  // Restore the original ID
853
858
  return {...formatted, id: resultToUse.id};
@@ -910,6 +910,22 @@ export class JavaScriptTypeMapping {
910
910
  return method;
911
911
  }
912
912
 
913
+ // A method is declared by one class, which an object literal that spreads a union, for one, is not.
914
+ private declaringType(type: ts.Type): Type.FullyQualified {
915
+ const mapped = this.getType(type);
916
+ switch (mapped.kind) {
917
+ case Type.Kind.Class:
918
+ case Type.Kind.Annotation:
919
+ case Type.Kind.ShallowClass:
920
+ case Type.Kind.Parameterized:
921
+ return mapped as Type.FullyQualified;
922
+ case Type.Kind.Primitive:
923
+ return this.wrapperType(mapped as Type.Primitive);
924
+ default:
925
+ return Type.unknownType as Type.FullyQualified;
926
+ }
927
+ }
928
+
913
929
  private wrapperType(declaringType: (Type.FullyQualified & Type.Primitive) | Type.FullyQualified) {
914
930
  if (declaringType === Type.Primitive.String && this.stringWrapperType) {
915
931
  return this.getType(this.stringWrapperType) as Type.FullyQualified;
@@ -1184,7 +1200,7 @@ export class JavaScriptTypeMapping {
1184
1200
  const parent = (symbol as any).parent;
1185
1201
  if (parent) {
1186
1202
  const parentType = this.checker.getDeclaredTypeOfSymbol(parent);
1187
- declaringType = this.getType(parentType) as Type.FullyQualified;
1203
+ declaringType = this.declaringType(parentType);
1188
1204
  } else {
1189
1205
  declaringType = Type.unknownType as Type.FullyQualified;
1190
1206
  }
@@ -1220,7 +1236,7 @@ export class JavaScriptTypeMapping {
1220
1236
  const parent = node.parent;
1221
1237
  if (ts.isClassDeclaration(parent) || ts.isInterfaceDeclaration(parent) || ts.isObjectLiteralExpression(parent)) {
1222
1238
  const parentType = this.checker.getTypeAtLocation(parent);
1223
- declaringType = this.getType(parentType) as Type.FullyQualified;
1239
+ declaringType = this.declaringType(parentType);
1224
1240
  } else {
1225
1241
  declaringType = Type.unknownType as Type.FullyQualified;
1226
1242
  }
@@ -1243,7 +1259,7 @@ export class JavaScriptTypeMapping {
1243
1259
  const parent = node.parent;
1244
1260
  if (ts.isClassDeclaration(parent) || ts.isClassExpression(parent)) {
1245
1261
  const parentType = this.checker.getTypeAtLocation(parent);
1246
- declaringType = this.getType(parentType) as Type.FullyQualified;
1262
+ declaringType = this.declaringType(parentType);
1247
1263
  } else {
1248
1264
  declaringType = Type.unknownType as Type.FullyQualified;
1249
1265
  }
package/src/print.ts CHANGED
@@ -35,11 +35,7 @@ export namespace MarkerPrinter {
35
35
  let searchResult = marker as SearchResult;
36
36
  return commentWrapper(searchResult.description == null ? "" : "(" + searchResult.description + ")");
37
37
  } else if (marker.kind.startsWith("org.openrewrite.marker.Markup$")) {
38
- const markup = marker as Markup;
39
- const content = markup.detail
40
- ? `(${markup.message}: ${markup.detail})`
41
- : `(${markup.message})`;
42
- return commentWrapper(content);
38
+ return commentWrapper(`(${(marker as Markup).message})`);
43
39
  }
44
40
  return "";
45
41
  },
@@ -51,6 +47,24 @@ export namespace MarkerPrinter {
51
47
  },
52
48
  }
53
49
 
50
+ /**
51
+ * As {@link DEFAULT}, but a {@link Markup} that has a detail prints it rather than its message.
52
+ */
53
+ export const VERBOSE: MarkerPrinter = {
54
+ beforeSyntax(marker: Marker, cursor: Cursor, commentWrapper: CommentWrapper): string {
55
+ if (marker.kind.startsWith("org.openrewrite.marker.Markup$")) {
56
+ return commentWrapper(`(${(marker as Markup).detail ?? (marker as Markup).message})`);
57
+ }
58
+ return DEFAULT.beforeSyntax(marker, cursor, commentWrapper);
59
+ },
60
+ beforePrefix(): string {
61
+ return "";
62
+ },
63
+ afterSyntax(): string {
64
+ return "";
65
+ },
66
+ }
67
+
54
68
  export const SEARCH_MARKERS_ONLY: MarkerPrinter = {
55
69
  beforeSyntax(marker: Marker, _cursor: Cursor, commentWrapper: CommentWrapper): string {
56
70
  if (marker.kind == MarkersKind.SearchResult) {
@@ -124,8 +138,9 @@ interface TreePrinter {
124
138
  * @param tree Helps to determine what kind of language we are dealing with when
125
139
  * printing a subtree whose LST type is shared between multiple languages in a language family.
126
140
  * @param out Accumulates printing output.
141
+ * @param cursor What encloses `tree`, when it is not a source file.
127
142
  */
128
- print(tree: Tree, out?: PrintOutputCapture): Promise<string>;
143
+ print(tree: Tree, out?: PrintOutputCapture, cursor?: Cursor): Promise<string>;
129
144
  }
130
145
 
131
146
  export class TreePrinters {
@@ -134,9 +149,9 @@ export class TreePrinters {
134
149
 
135
150
  static register(kind: string, printer: () => TreeVisitor<any, PrintOutputCapture>): void {
136
151
  this._registry.set(kind, {
137
- async print(tree: Tree, out?: PrintOutputCapture): Promise<string> {
152
+ async print(tree: Tree, out?: PrintOutputCapture, cursor?: Cursor): Promise<string> {
138
153
  const p = out || new PrintOutputCapture();
139
- await printer().visit(tree, p);
154
+ await printer().visit(tree, p, cursor);
140
155
  return p.out;
141
156
  }
142
157
  })
@@ -38,6 +38,8 @@ export interface JavaRpcOptions {
38
38
  * only. Does NOT configure the Java side — for that, use {@link marketplaceCsv}.
39
39
  */
40
40
  marketplace?: RecipeMarketplace;
41
+ /** How many messages the TS-side {@link RewriteRpc} sends per page of an object. */
42
+ batchSize?: number;
41
43
  }
42
44
 
43
45
  /**
@@ -116,6 +118,7 @@ export class JavaRpcTestServer {
116
118
  const rewriteRpc = new RewriteRpc(connection, {
117
119
  marketplace: opts.marketplace,
118
120
  logger: opts.logger,
121
+ batchSize: opts.batchSize,
119
122
  });
120
123
 
121
124
  // Hand back control once we know either (a) the JVM is up and the connection is
package/src/rpc/queue.ts CHANGED
@@ -182,6 +182,13 @@ export class RpcSendQueue {
182
182
 
183
183
  send<T>(after: T | undefined, before: T | undefined, onChange?: (() => Promise<any>)): Promise<void> {
184
184
  return saveTrace(this.trace, async () => {
185
+ // The peer has a single absent value, and an ADD that carries nothing is not one it can decode.
186
+ if (after === null) {
187
+ after = undefined;
188
+ }
189
+ if (before === null) {
190
+ before = undefined;
191
+ }
185
192
  if (before === after) {
186
193
  this.put({state: RpcObjectState.NO_CHANGE});
187
194
  } else if (before === undefined || (after !== undefined && this.typesAreDifferent(after, before))) {
@@ -372,10 +379,20 @@ export class StringInternTable {
372
379
  }
373
380
  }
374
381
 
382
+ // Java's serializer names the class and numbers the object inside the value; the kind already says the first.
383
+ function withoutSerializerKeys(value: any): any {
384
+ if (value === null || typeof value !== "object") {
385
+ return value;
386
+ }
387
+ const {"@c": _class, "@ref": _ref, ...fields} = value;
388
+ return fields;
389
+ }
390
+
375
391
  export class RpcReceiveQueue {
376
392
  private batch: RpcObjectData[] = [];
377
393
  private batchIndex = 0;
378
394
  private sinceYield = 0;
395
+ private recorded: number[] = [];
379
396
 
380
397
  constructor(private readonly refs: Map<number, any>,
381
398
  private readonly sourceFileType: string | undefined,
@@ -385,6 +402,23 @@ export class RpcReceiveQueue {
385
402
  private readonly internedStrings: StringInternTable = new StringInternTable()) {
386
403
  }
387
404
 
405
+ private record(ref: number, value: any): void {
406
+ this.refs.set(ref, value);
407
+ this.recorded.push(ref);
408
+ }
409
+
410
+ /**
411
+ * Drops the refs this transfer defined, for when it could not be read to its end and the
412
+ * sender is about to forget them too.
413
+ * @internal
414
+ */
415
+ forgetRefs(): void {
416
+ for (const ref of this.recorded) {
417
+ this.refs.delete(ref);
418
+ }
419
+ this.recorded = [];
420
+ }
421
+
388
422
  /**
389
423
  * Returns a value rather than a promise for all but the message that refills the
390
424
  * batch or yields, so the common path costs neither a promise nor an async frame.
@@ -479,7 +513,7 @@ export class RpcReceiveQueue {
479
513
  // For an object like JavaType that we will mutate in place rather than using
480
514
  // immutable updates because of its cyclic nature, the before instance will ultimately
481
515
  // be the same as the after instance below.
482
- this.refs.set(ref, before);
516
+ this.record(ref, before);
483
517
  }
484
518
  }
485
519
  // Intentional fall-through...
@@ -492,7 +526,7 @@ export class RpcReceiveQueue {
492
526
  after = await codec.rpcReceive(before, this);
493
527
  } else if (message.value !== undefined) {
494
528
  after = message.valueType ?
495
- {kind: this.internedStrings.internType(message.valueType), ...message.value} :
529
+ {kind: this.internedStrings.internType(message.valueType), ...withoutSerializerKeys(message.value)} :
496
530
  typeof message.value === "string" ? this.internedStrings.internValue(message.value) : message.value;
497
531
  } else if (message.state === RpcObjectState.ADD && message.valueType) {
498
532
  throw new Error(
@@ -504,7 +538,7 @@ export class RpcReceiveQueue {
504
538
  after = before;
505
539
  }
506
540
  if (ref !== undefined) {
507
- this.refs.set(ref, after);
541
+ this.record(ref, after);
508
542
  }
509
543
  return after;
510
544
  default: