@openrewrite/rewrite 8.62.3 → 8.62.5

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 (170) hide show
  1. package/dist/execution.d.ts.map +1 -1
  2. package/dist/execution.js.map +1 -1
  3. package/dist/java/rpc.d.ts +1 -0
  4. package/dist/java/rpc.d.ts.map +1 -1
  5. package/dist/java/rpc.js +81 -0
  6. package/dist/java/rpc.js.map +1 -1
  7. package/dist/java/tree.d.ts +12 -6
  8. package/dist/java/tree.d.ts.map +1 -1
  9. package/dist/java/tree.js +12 -92
  10. package/dist/java/tree.js.map +1 -1
  11. package/dist/java/type.d.ts +2 -0
  12. package/dist/java/type.d.ts.map +1 -1
  13. package/dist/java/type.js +12 -0
  14. package/dist/java/type.js.map +1 -1
  15. package/dist/java/visitor.d.ts +12 -4
  16. package/dist/java/visitor.d.ts.map +1 -1
  17. package/dist/java/visitor.js +23 -1
  18. package/dist/java/visitor.js.map +1 -1
  19. package/dist/javascript/format.d.ts +2 -2
  20. package/dist/javascript/format.d.ts.map +1 -1
  21. package/dist/javascript/format.js.map +1 -1
  22. package/dist/javascript/index.d.ts +3 -0
  23. package/dist/javascript/index.d.ts.map +1 -1
  24. package/dist/javascript/index.js +3 -0
  25. package/dist/javascript/index.js.map +1 -1
  26. package/dist/javascript/method-matcher.d.ts +16 -0
  27. package/dist/javascript/method-matcher.d.ts.map +1 -0
  28. package/dist/javascript/method-matcher.js +222 -0
  29. package/dist/javascript/method-matcher.js.map +1 -0
  30. package/dist/javascript/parser.d.ts +1 -1
  31. package/dist/javascript/parser.d.ts.map +1 -1
  32. package/dist/javascript/parser.js +27 -5
  33. package/dist/javascript/parser.js.map +1 -1
  34. package/dist/javascript/preconditions.d.ts +6 -0
  35. package/dist/javascript/preconditions.d.ts.map +1 -0
  36. package/dist/javascript/preconditions.js +58 -0
  37. package/dist/javascript/preconditions.js.map +1 -0
  38. package/dist/javascript/print.d.ts +2 -2
  39. package/dist/javascript/print.d.ts.map +1 -1
  40. package/dist/javascript/print.js.map +1 -1
  41. package/dist/javascript/remove-import.d.ts +56 -0
  42. package/dist/javascript/remove-import.d.ts.map +1 -0
  43. package/dist/javascript/remove-import.js +715 -0
  44. package/dist/javascript/remove-import.js.map +1 -0
  45. package/dist/javascript/rpc.js +3 -18
  46. package/dist/javascript/rpc.js.map +1 -1
  47. package/dist/javascript/search/index.d.ts +3 -0
  48. package/dist/javascript/search/index.d.ts.map +1 -0
  49. package/dist/javascript/search/index.js +19 -0
  50. package/dist/javascript/search/index.js.map +1 -0
  51. package/dist/javascript/search/uses-method.d.ts +8 -0
  52. package/dist/javascript/search/uses-method.d.ts.map +1 -0
  53. package/dist/javascript/search/uses-method.js +35 -0
  54. package/dist/javascript/search/uses-method.js.map +1 -0
  55. package/dist/javascript/search/uses-type.d.ts +8 -0
  56. package/dist/javascript/search/uses-type.d.ts.map +1 -0
  57. package/dist/javascript/search/uses-type.js +71 -0
  58. package/dist/javascript/search/uses-type.js.map +1 -0
  59. package/dist/javascript/templating.d.ts +1 -1
  60. package/dist/javascript/templating.d.ts.map +1 -1
  61. package/dist/javascript/templating.js +1 -1
  62. package/dist/javascript/templating.js.map +1 -1
  63. package/dist/javascript/tree.d.ts +3 -3
  64. package/dist/javascript/tree.d.ts.map +1 -1
  65. package/dist/javascript/tree.js +28 -0
  66. package/dist/javascript/tree.js.map +1 -1
  67. package/dist/javascript/type-mapping.d.ts +7 -18
  68. package/dist/javascript/type-mapping.d.ts.map +1 -1
  69. package/dist/javascript/type-mapping.js +290 -203
  70. package/dist/javascript/type-mapping.js.map +1 -1
  71. package/dist/javascript/visitor.d.ts +1 -1
  72. package/dist/javascript/visitor.d.ts.map +1 -1
  73. package/dist/javascript/visitor.js +1 -1
  74. package/dist/javascript/visitor.js.map +1 -1
  75. package/dist/json/print.js.map +1 -1
  76. package/dist/json/rpc.js +46 -17
  77. package/dist/json/rpc.js.map +1 -1
  78. package/dist/json/visitor.d.ts +2 -2
  79. package/dist/json/visitor.d.ts.map +1 -1
  80. package/dist/json/visitor.js.map +1 -1
  81. package/dist/print.d.ts +1 -0
  82. package/dist/print.d.ts.map +1 -1
  83. package/dist/print.js +6 -0
  84. package/dist/print.js.map +1 -1
  85. package/dist/rpc/queue.d.ts +15 -6
  86. package/dist/rpc/queue.d.ts.map +1 -1
  87. package/dist/rpc/queue.js +37 -13
  88. package/dist/rpc/queue.js.map +1 -1
  89. package/dist/rpc/request/generate.d.ts +4 -0
  90. package/dist/rpc/request/generate.d.ts.map +1 -1
  91. package/dist/rpc/request/generate.js +9 -4
  92. package/dist/rpc/request/generate.js.map +1 -1
  93. package/dist/rpc/request/get-object.d.ts +2 -2
  94. package/dist/rpc/request/get-object.d.ts.map +1 -1
  95. package/dist/rpc/request/get-object.js +4 -12
  96. package/dist/rpc/request/get-object.js.map +1 -1
  97. package/dist/rpc/request/parse.d.ts.map +1 -1
  98. package/dist/rpc/request/parse.js.map +1 -1
  99. package/dist/rpc/request/print.d.ts +1 -1
  100. package/dist/rpc/request/print.d.ts.map +1 -1
  101. package/dist/rpc/request/print.js +1 -1
  102. package/dist/rpc/request/print.js.map +1 -1
  103. package/dist/rpc/request/visit.d.ts +3 -2
  104. package/dist/rpc/request/visit.d.ts.map +1 -1
  105. package/dist/rpc/request/visit.js +5 -4
  106. package/dist/rpc/request/visit.js.map +1 -1
  107. package/dist/rpc/rewrite-rpc.d.ts +4 -4
  108. package/dist/rpc/rewrite-rpc.d.ts.map +1 -1
  109. package/dist/rpc/rewrite-rpc.js +16 -17
  110. package/dist/rpc/rewrite-rpc.js.map +1 -1
  111. package/dist/search/index.d.ts +2 -0
  112. package/dist/search/index.d.ts.map +1 -0
  113. package/dist/search/index.js +18 -0
  114. package/dist/search/index.js.map +1 -0
  115. package/dist/search/is-source-file.d.ts +8 -0
  116. package/dist/search/is-source-file.d.ts.map +1 -0
  117. package/dist/search/is-source-file.js +70 -0
  118. package/dist/search/is-source-file.js.map +1 -0
  119. package/dist/test/rewrite-test.d.ts.map +1 -1
  120. package/dist/test/rewrite-test.js +3 -0
  121. package/dist/test/rewrite-test.js.map +1 -1
  122. package/dist/text/rpc.js +37 -40
  123. package/dist/text/rpc.js.map +1 -1
  124. package/dist/util.d.ts +1 -0
  125. package/dist/util.d.ts.map +1 -1
  126. package/dist/util.js +13 -0
  127. package/dist/util.js.map +1 -1
  128. package/dist/version.txt +1 -1
  129. package/dist/visitor.d.ts +1 -1
  130. package/dist/visitor.d.ts.map +1 -1
  131. package/dist/visitor.js +3 -2
  132. package/dist/visitor.js.map +1 -1
  133. package/package.json +3 -1
  134. package/src/execution.ts +0 -2
  135. package/src/java/rpc.ts +68 -0
  136. package/src/java/tree.ts +20 -76
  137. package/src/java/type.ts +14 -0
  138. package/src/java/visitor.ts +32 -12
  139. package/src/javascript/format.ts +2 -2
  140. package/src/javascript/index.ts +4 -0
  141. package/src/javascript/method-matcher.ts +250 -0
  142. package/src/javascript/parser.ts +20 -6
  143. package/src/javascript/preconditions.ts +40 -0
  144. package/src/javascript/print.ts +3 -3
  145. package/src/javascript/remove-import.ts +780 -0
  146. package/src/javascript/rpc.ts +6 -19
  147. package/src/javascript/search/index.ts +2 -0
  148. package/src/javascript/search/uses-method.ts +21 -0
  149. package/src/javascript/search/uses-type.ts +27 -0
  150. package/src/javascript/templating.ts +4 -3
  151. package/src/javascript/tree.ts +47 -3
  152. package/src/javascript/type-mapping.ts +320 -214
  153. package/src/javascript/visitor.ts +126 -126
  154. package/src/json/print.ts +1 -1
  155. package/src/json/rpc.ts +40 -19
  156. package/src/json/visitor.ts +2 -2
  157. package/src/print.ts +9 -3
  158. package/src/rpc/queue.ts +36 -12
  159. package/src/rpc/request/generate.ts +18 -6
  160. package/src/rpc/request/get-object.ts +6 -13
  161. package/src/rpc/request/parse.ts +1 -1
  162. package/src/rpc/request/print.ts +2 -2
  163. package/src/rpc/request/visit.ts +6 -5
  164. package/src/rpc/rewrite-rpc.ts +22 -21
  165. package/src/search/index.ts +1 -0
  166. package/src/search/is-source-file.ts +26 -0
  167. package/src/test/rewrite-test.ts +5 -2
  168. package/src/text/rpc.ts +33 -37
  169. package/src/util.ts +19 -4
  170. package/src/visitor.ts +3 -3
package/src/java/rpc.ts CHANGED
@@ -20,6 +20,7 @@ import {produceAsync} from "../visitor";
20
20
  import {createDraft, Draft, finishDraft, WritableDraft} from "immer";
21
21
  import {isTree} from "../tree";
22
22
  import {Type} from "./type";
23
+ import Space = J.Space;
23
24
 
24
25
  export class JavaSender extends JavaVisitor<RpcSendQueue> {
25
26
 
@@ -1382,3 +1383,70 @@ export class JavaReceiver extends JavaVisitor<RpcReceiveQueue> {
1382
1383
  return undefined;
1383
1384
  }
1384
1385
  }
1386
+
1387
+ export function registerJLanguageCodecs(sourceFileType: string,
1388
+ receiver: JavaVisitor<RpcReceiveQueue>,
1389
+ sender: JavaVisitor<RpcSendQueue>,
1390
+ extendedKinds?: any) {
1391
+ const kinds = new Set([
1392
+ ...Object.values(J.Kind),
1393
+ ...(extendedKinds ? Object.values(extendedKinds) : [])
1394
+ ]);
1395
+
1396
+ // Register codec for all Java AST node types
1397
+ for (const kind of kinds) {
1398
+ if (kind === J.Kind.Space) {
1399
+ RpcCodecs.registerCodec(kind, {
1400
+ async rpcReceive(before: J.Space, q: RpcReceiveQueue): Promise<J.Space> {
1401
+ return (await receiver.visitSpace(before, q))!;
1402
+ },
1403
+
1404
+ async rpcSend(after: J.Space, q: RpcSendQueue): Promise<void> {
1405
+ await sender.visitSpace(after, q);
1406
+ }
1407
+ }, sourceFileType);
1408
+ } else if (kind === J.Kind.RightPadded) {
1409
+ RpcCodecs.registerCodec(kind, {
1410
+ async rpcReceive<T extends J | boolean>(before: J.RightPadded<T>, q: RpcReceiveQueue): Promise<J.RightPadded<T>> {
1411
+ return (await receiver.visitRightPadded(before, q))!;
1412
+ },
1413
+
1414
+ async rpcSend<T extends J | boolean>(after: J.RightPadded<T>, q: RpcSendQueue): Promise<void> {
1415
+ await sender.visitRightPadded(after, q);
1416
+ }
1417
+ }, sourceFileType);
1418
+ } else if (kind === J.Kind.LeftPadded) {
1419
+ RpcCodecs.registerCodec(kind, {
1420
+ async rpcReceive<T extends J | Space | number | string | boolean>(before: J.LeftPadded<T>, q: RpcReceiveQueue): Promise<J.LeftPadded<T>> {
1421
+ return (await receiver.visitLeftPadded(before, q))!;
1422
+ },
1423
+
1424
+ async rpcSend<T extends J | Space | number | string | boolean>(after: J.LeftPadded<T>, q: RpcSendQueue): Promise<void> {
1425
+ await sender.visitLeftPadded(after, q);
1426
+ }
1427
+ }, sourceFileType);
1428
+ } else if (kind === J.Kind.Container) {
1429
+ RpcCodecs.registerCodec(kind, {
1430
+ async rpcReceive<T extends J>(before: J.Container<T>, q: RpcReceiveQueue): Promise<J.Container<T>> {
1431
+ return (await receiver.visitContainer(before, q))!;
1432
+ },
1433
+
1434
+ async rpcSend<T extends J>(after: J.Container<T>, q: RpcSendQueue): Promise<void> {
1435
+ await sender.visitContainer(after, q);
1436
+ }
1437
+ }, sourceFileType);
1438
+ } else {
1439
+ RpcCodecs.registerCodec(kind as string, {
1440
+ async rpcReceive(before: J, q: RpcReceiveQueue): Promise<J> {
1441
+ return (await receiver.visit(before, q))!;
1442
+ },
1443
+
1444
+ async rpcSend(after: J, q: RpcSendQueue): Promise<void> {
1445
+ await sender.visit(after, q);
1446
+ }
1447
+ }, sourceFileType);
1448
+ }
1449
+ }
1450
+ }
1451
+
1452
+ registerJLanguageCodecs(J.Kind.CompilationUnit, new JavaReceiver(), new JavaSender());
package/src/java/tree.ts CHANGED
@@ -17,19 +17,32 @@
17
17
  */
18
18
 
19
19
  import {emptyMarkers, Markers} from "../markers";
20
- import {SourceFile, Tree, TreeKind} from "../tree";
20
+ import {SourceFile, Tree} from "../tree";
21
21
  import {Type} from "./type";
22
- import {RpcCodec, RpcCodecs, RpcReceiveQueue, RpcSendQueue} from "../rpc";
23
- import {JavaReceiver, JavaSender} from "./rpc";
24
- import Space = J.Space;
25
22
 
26
23
  export interface J extends Tree {
27
24
  readonly prefix: J.Space;
28
25
  }
29
26
 
27
+ export namespace J {
28
+ export function isMethodCall(e?: Expression): e is MethodCall {
29
+ return e?.kind === J.Kind.NewClass ||
30
+ e?.kind === J.Kind.MethodInvocation ||
31
+ e?.kind === J.Kind.MemberReference;
32
+ }
33
+
34
+ export function hasType<T extends J>(tree: T): tree is T & { type: Type } {
35
+ return tree && 'type' in tree && tree.type != null;
36
+ }
37
+ }
38
+
30
39
  export interface Expression extends J {
31
40
  }
32
41
 
42
+ export interface MethodCall extends Expression {
43
+ readonly methodType?: Type.Method;
44
+ }
45
+
33
46
  export interface TypedTree extends J {
34
47
  }
35
48
 
@@ -461,13 +474,12 @@ export namespace J {
461
474
  readonly codePoint: string;
462
475
  }
463
476
 
464
- export interface MemberReference extends J, Expression {
477
+ export interface MemberReference extends J, MethodCall {
465
478
  readonly kind: typeof Kind.MemberReference;
466
479
  readonly containing: RightPadded<Expression>;
467
480
  readonly typeParameters?: Container<Expression>;
468
481
  readonly reference: LeftPadded<Identifier>;
469
482
  readonly type?: Type;
470
- readonly methodType?: Type.Method;
471
483
  readonly variableType?: Type.Variable;
472
484
  }
473
485
 
@@ -486,13 +498,12 @@ export namespace J {
486
498
  readonly methodType?: Type.Method;
487
499
  }
488
500
 
489
- export interface MethodInvocation extends J, TypedTree, Expression {
501
+ export interface MethodInvocation extends J, TypedTree, MethodCall {
490
502
  readonly kind: typeof Kind.MethodInvocation;
491
503
  readonly select?: RightPadded<Expression>;
492
504
  readonly typeParameters?: Container<Expression>;
493
505
  readonly name: Identifier;
494
506
  readonly arguments: Container<Expression>;
495
- readonly methodType?: Type.Method;
496
507
  }
497
508
 
498
509
  export interface Modifier extends J {
@@ -539,7 +550,7 @@ export namespace J {
539
550
  readonly type?: Type;
540
551
  }
541
552
 
542
- export interface NewClass extends J, TypedTree, Expression {
553
+ export interface NewClass extends J, TypedTree, MethodCall {
543
554
  readonly kind: typeof Kind.NewClass;
544
555
  readonly enclosing?: RightPadded<Expression>;
545
556
  readonly new: Space;
@@ -817,12 +828,6 @@ export interface DocComment extends Comment {
817
828
  // TODO implement me!
818
829
  }
819
830
 
820
- const javaKindValues = new Set(Object.values(J.Kind));
821
-
822
- export function isJava(tree: any): tree is J {
823
- return javaKindValues.has(tree["kind"]);
824
- }
825
-
826
831
  export function isLiteral(tree: any): tree is J.Literal {
827
832
  return tree["kind"] === J.Kind.Literal;
828
833
  }
@@ -874,64 +879,3 @@ export namespace TypedTree {
874
879
  registerTypeGetter(J.Kind.Wildcard, () => Type.unknownType);
875
880
  registerTypeGetter(J.Kind.Unknown, () => Type.unknownType);
876
881
  }
877
-
878
- const javaReceiver = new JavaReceiver();
879
- const javaSender = new JavaSender();
880
-
881
- const javaCodec: RpcCodec<J> = {
882
- async rpcReceive(before: J, q: RpcReceiveQueue): Promise<J> {
883
- return (await javaReceiver.visit(before, q))!;
884
- },
885
-
886
- async rpcSend(after: J, q: RpcSendQueue): Promise<void> {
887
- await javaSender.visit(after, q);
888
- }
889
- }
890
-
891
- // Register codec for all Java AST node types
892
- Object.values(J.Kind).forEach(kind => {
893
- if (kind === J.Kind.Space) {
894
- RpcCodecs.registerCodec(kind, {
895
- async rpcReceive(before: J.Space, q: RpcReceiveQueue): Promise<J.Space> {
896
- return (await javaReceiver.visitSpace(before, q))!;
897
- },
898
-
899
- async rpcSend(after: J.Space, q: RpcSendQueue): Promise<void> {
900
- await javaSender.visitSpace(after, q);
901
- }
902
- }
903
- );
904
- } else if (kind === J.Kind.RightPadded) {
905
- RpcCodecs.registerCodec(kind, {
906
- async rpcReceive<T extends J | boolean>(before: J.RightPadded<T>, q: RpcReceiveQueue): Promise<J.RightPadded<T>> {
907
- return (await javaReceiver.visitRightPadded(before, q))!;
908
- },
909
-
910
- async rpcSend<T extends J | boolean>(after: J.RightPadded<T>, q: RpcSendQueue): Promise<void> {
911
- await javaSender.visitRightPadded(after, q);
912
- }
913
- })
914
- } else if (kind === J.Kind.LeftPadded) {
915
- RpcCodecs.registerCodec(kind, {
916
- async rpcReceive<T extends J | Space | number | string | boolean>(before: J.LeftPadded<T>, q: RpcReceiveQueue): Promise<J.LeftPadded<T>> {
917
- return (await javaReceiver.visitLeftPadded(before, q))!;
918
- },
919
-
920
- async rpcSend<T extends J | Space | number | string | boolean>(after: J.LeftPadded<T>, q: RpcSendQueue): Promise<void> {
921
- await javaSender.visitLeftPadded(after, q);
922
- }
923
- })
924
- } else if (kind === J.Kind.Container) {
925
- RpcCodecs.registerCodec(kind, {
926
- async rpcReceive<T extends J>(before: J.Container<T>, q: RpcReceiveQueue): Promise<J.Container<T>> {
927
- return (await javaReceiver.visitContainer(before, q))!;
928
- },
929
-
930
- async rpcSend<T extends J>(after: J.Container<T>, q: RpcSendQueue): Promise<void> {
931
- await javaSender.visitContainer(after, q);
932
- }
933
- })
934
- } else {
935
- RpcCodecs.registerCodec(kind, javaCodec);
936
- }
937
- });
package/src/java/type.ts CHANGED
@@ -237,6 +237,10 @@ export namespace Type {
237
237
  return type?.kind === Type.Kind.Class;
238
238
  }
239
239
 
240
+ export function isMethod(type?: Type): type is Type.Method {
241
+ return type?.kind === Type.Kind.Method;
242
+ }
243
+
240
244
  export function isArray(type?: Type): type is Type.Array {
241
245
  return type?.kind === Type.Kind.Array;
242
246
  }
@@ -245,6 +249,16 @@ export namespace Type {
245
249
  return type?.kind === Type.Kind.Parameterized;
246
250
  }
247
251
 
252
+ export function isFullyQualified(type?: Type): type is Type.FullyQualified {
253
+ return type != null && (
254
+ type.kind === Type.Kind.Class ||
255
+ type.kind === Type.Kind.Annotation ||
256
+ type.kind === Type.Kind.Parameterized ||
257
+ type.kind === Type.Kind.Array ||
258
+ type.kind === Type.Kind.ShallowClass
259
+ );
260
+ }
261
+
248
262
  export interface FullyQualified extends Type {
249
263
  }
250
264
 
@@ -16,17 +16,33 @@
16
16
  import {Cursor, isTree, SourceFile} from "../tree";
17
17
  import {mapAsync} from "../util";
18
18
  import {produceAsync, TreeVisitor, ValidImmerRecipeReturnType} from "../visitor";
19
- import {
20
- Expression,
21
- isJava,
22
- isSpace,
23
- J,
24
- NameTree,
25
- Statement, TypedTree, TypeTree
26
- } from "./tree";
19
+ import {Expression, isSpace, J, NameTree, Statement, TypedTree, TypeTree} from "./tree";
27
20
  import {createDraft, Draft, finishDraft} from "immer";
28
21
  import {Type} from "./type";
29
22
 
23
+ const javaKindValues = new Set(Object.values(J.Kind));
24
+
25
+ const extendedJavaKinds = new Map<string, <P>(visitor: JavaVisitor<P>) => JavaVisitor<P>>();
26
+
27
+ /**
28
+ * Register additional kind values for interfaces that extend J.
29
+ * This allows isJava to recognize implementations of those interfaces.
30
+ * @param kinds - Array of kind values to register
31
+ * @param adapter - Adapter function to transform a JavaVisitor to, for example, a JavaScriptVisitor
32
+ */
33
+ export function registerJavaExtensionKinds(
34
+ kinds: readonly string[],
35
+ adapter: <P>(visitor: JavaVisitor<P>) => JavaVisitor<P>
36
+ ): void {
37
+ for (const kind of kinds) {
38
+ extendedJavaKinds.set(kind, adapter);
39
+ }
40
+ }
41
+
42
+ export function isJava(tree: any): tree is J {
43
+ return javaKindValues.has(tree["kind"]) || extendedJavaKinds.has(tree["kind"]);
44
+ }
45
+
30
46
  export class JavaVisitor<P> extends TreeVisitor<J, P> {
31
47
  // protected javadocVisitor: any | null = null;
32
48
 
@@ -45,7 +61,7 @@ export class JavaVisitor<P> extends TreeVisitor<J, P> {
45
61
  }
46
62
 
47
63
  // noinspection JSUnusedLocalSymbols
48
- protected async visitSpace(space: J.Space, p: P): Promise<J.Space> {
64
+ public async visitSpace(space: J.Space, p: P): Promise<J.Space> {
49
65
  return space;
50
66
  }
51
67
 
@@ -995,7 +1011,7 @@ export class JavaVisitor<P> extends TreeVisitor<J, P> {
995
1011
  return right ? this.visitRightPadded(right, p) : undefined;
996
1012
  }
997
1013
 
998
- protected async visitRightPadded<T extends J | boolean>(right: J.RightPadded<T>, p: P): Promise<J.RightPadded<T>> {
1014
+ public async visitRightPadded<T extends J | boolean>(right: J.RightPadded<T>, p: P): Promise<J.RightPadded<T>> {
999
1015
  return produceAsync<J.RightPadded<T>>(right, async draft => {
1000
1016
  this.cursor = new Cursor(right, this.cursor);
1001
1017
  if (isTree(right.element)) {
@@ -1011,7 +1027,7 @@ export class JavaVisitor<P> extends TreeVisitor<J, P> {
1011
1027
  return left ? this.visitLeftPadded(left, p) : undefined;
1012
1028
  }
1013
1029
 
1014
- protected async visitLeftPadded<T extends J | J.Space | number | string | boolean>(left: J.LeftPadded<T>, p: P): Promise<J.LeftPadded<T>> {
1030
+ public async visitLeftPadded<T extends J | J.Space | number | string | boolean>(left: J.LeftPadded<T>, p: P): Promise<J.LeftPadded<T>> {
1015
1031
  return produceAsync<J.LeftPadded<T>>(left, async draft => {
1016
1032
  this.cursor = new Cursor(left, this.cursor);
1017
1033
  draft.before = await this.visitSpace(left.before, p);
@@ -1029,7 +1045,7 @@ export class JavaVisitor<P> extends TreeVisitor<J, P> {
1029
1045
  return container ? this.visitContainer(container, p) : undefined;
1030
1046
  }
1031
1047
 
1032
- protected async visitContainer<T extends J>(container: J.Container<T>, p: P): Promise<J.Container<T>> {
1048
+ public async visitContainer<T extends J>(container: J.Container<T>, p: P): Promise<J.Container<T>> {
1033
1049
  return produceAsync<J.Container<T>>(container, async draft => {
1034
1050
  this.cursor = new Cursor(container, this.cursor);
1035
1051
  draft.before = await this.visitSpace(container.before, p);
@@ -1200,6 +1216,10 @@ export class JavaVisitor<P> extends TreeVisitor<J, P> {
1200
1216
  case J.Kind.Yield:
1201
1217
  return this.visitYield(t as J.Yield, p);
1202
1218
  default:
1219
+ const adapter = extendedJavaKinds.get(t.kind)
1220
+ if (adapter) {
1221
+ return adapter(this).visit(t, p);
1222
+ }
1203
1223
  return Promise.resolve(t);
1204
1224
  }
1205
1225
  }
@@ -159,7 +159,7 @@ export class SpacesVisitor<P> extends JavaScriptVisitor<P> {
159
159
  }) as J.ClassDeclaration;
160
160
  }
161
161
 
162
- protected async visitContainer<T extends J>(container: J.Container<T>, p: P): Promise<J.Container<T>> {
162
+ public async visitContainer<T extends J>(container: J.Container<T>, p: P): Promise<J.Container<T>> {
163
163
  const ret = await super.visitContainer(container, p) as J.Container<T>;
164
164
  return produce(ret, draft => {
165
165
  if (draft.elements.length > 1) {
@@ -1088,7 +1088,7 @@ export class TabsAndIndentsVisitor<P> extends JavaScriptVisitor<P> {
1088
1088
  });
1089
1089
  }
1090
1090
 
1091
- protected async visitLeftPadded<T extends J | J.Space | number | string | boolean>(left: J.LeftPadded<T>, p: P): Promise<J.LeftPadded<T>> {
1091
+ public async visitLeftPadded<T extends J | J.Space | number | string | boolean>(left: J.LeftPadded<T>, p: P): Promise<J.LeftPadded<T>> {
1092
1092
  const ret = await super.visitLeftPadded(left, p);
1093
1093
  if (ret == undefined) {
1094
1094
  return ret;
@@ -19,7 +19,11 @@ export * from "./assertions";
19
19
  export * from "./parser";
20
20
  export * from "./style";
21
21
  export * from "./markers";
22
+ export * from "./preconditions";
22
23
  export * from "./templating";
24
+ export * from "./method-matcher";
25
+
26
+ export * from "./remove-import";
23
27
 
24
28
  import "./print";
25
29
  import "./rpc";
@@ -0,0 +1,250 @@
1
+ import {Type} from "../java";
2
+ import FullyQualified = Type.FullyQualified;
3
+
4
+ export class MethodMatcher {
5
+ private readonly packagePattern: string;
6
+ private readonly typePattern: string;
7
+ private readonly methodPattern: string;
8
+ private readonly argumentPatterns: string[];
9
+
10
+ constructor(pattern: string) {
11
+ // Find the last space before the method spec (which contains parentheses)
12
+ const firstParenIndex = pattern.indexOf('(');
13
+ if (firstParenIndex === -1) {
14
+ throw new Error(`Invalid pattern format: ${pattern} - missing method arguments`);
15
+ }
16
+
17
+ // Find the last space before the opening parenthesis
18
+ const lastSpaceBeforeParen = pattern.lastIndexOf(' ', firstParenIndex);
19
+ if (lastSpaceBeforeParen === -1) {
20
+ throw new Error(`Invalid pattern format: ${pattern}`);
21
+ }
22
+
23
+ const typeSpec = pattern.substring(0, lastSpaceBeforeParen).trim();
24
+ const methodSpec = pattern.substring(lastSpaceBeforeParen + 1).trim();
25
+
26
+ // Parse type specification (package.Type or just Type)
27
+ // Special case: *..* pattern (any package, any type)
28
+ if (typeSpec === '*..*') {
29
+ this.packagePattern = '*..';
30
+ this.typePattern = '*';
31
+ } else {
32
+ const lastDotIndex = typeSpec.lastIndexOf('.');
33
+ if (lastDotIndex === -1) {
34
+ this.packagePattern = '*';
35
+ this.typePattern = typeSpec;
36
+ } else {
37
+ // Check if we're splitting a *.. pattern incorrectly
38
+ const potentialPackage = typeSpec.substring(0, lastDotIndex);
39
+ if (potentialPackage.endsWith('*..')) {
40
+ // Don't split *.. pattern - it should stay together
41
+ this.packagePattern = potentialPackage;
42
+ this.typePattern = typeSpec.substring(lastDotIndex + 1);
43
+ } else {
44
+ this.packagePattern = potentialPackage;
45
+ this.typePattern = typeSpec.substring(lastDotIndex + 1);
46
+ }
47
+ }
48
+ }
49
+
50
+ // Parse method specification methodName(args)
51
+ const methodParenIndex = methodSpec.indexOf('(');
52
+ if (methodParenIndex === -1 || !methodSpec.endsWith(')')) {
53
+ throw new Error(`Invalid method specification: ${methodSpec}`);
54
+ }
55
+
56
+ this.methodPattern = methodSpec.substring(0, methodParenIndex);
57
+ const argsString = methodSpec.substring(methodParenIndex + 1, methodSpec.length - 1);
58
+
59
+ // Parse arguments
60
+ if (argsString.trim() === '..') {
61
+ this.argumentPatterns = ['..'];
62
+ } else if (argsString.trim() === '') {
63
+ this.argumentPatterns = [];
64
+ } else {
65
+ this.argumentPatterns = argsString.split(',').map(arg => arg.trim());
66
+ }
67
+ }
68
+
69
+ matches(method?: Type.Method): boolean {
70
+ if (!method) {
71
+ return false;
72
+ }
73
+
74
+ // Extract fully qualified name from declaringType
75
+ const fullyQualifiedName = FullyQualified.getFullyQualifiedName(method.declaringType);
76
+
77
+ // Split fully qualified name into package and type
78
+ const lastDotIndex = fullyQualifiedName.lastIndexOf('.');
79
+ const packageName = lastDotIndex === -1 ? '' : fullyQualifiedName.substring(0, lastDotIndex);
80
+ const typeName = lastDotIndex === -1 ? fullyQualifiedName : fullyQualifiedName.substring(lastDotIndex + 1);
81
+
82
+ // Match package
83
+ if (!this.matchesPackage(packageName)) {
84
+ return false;
85
+ }
86
+
87
+ // Match type (normalize primitives for matching)
88
+ const normalizedTypePattern = this.normalizePrimitiveType(this.typePattern);
89
+ const normalizedTypeName = this.normalizePrimitiveType(typeName);
90
+ if (!this.matchesPattern(normalizedTypePattern, normalizedTypeName)) {
91
+ return false;
92
+ }
93
+
94
+ // Match method name
95
+ if (!this.matchesPattern(this.methodPattern, method.name)) {
96
+ return false;
97
+ }
98
+
99
+ // Match arguments - convert Type[] to string representations
100
+ const argStrings = method.parameterTypes.map(type => this.typeToString(type));
101
+ return this.matchesArguments(argStrings);
102
+ }
103
+
104
+ private typeToString(type: Type): string {
105
+ switch (type.kind) {
106
+ case Type.Kind.Primitive:
107
+ return (type as Type.Primitive).keyword;
108
+ case Type.Kind.Class:
109
+ return (type as Type.Class).fullyQualifiedName;
110
+ case Type.Kind.Parameterized:
111
+ return FullyQualified.getFullyQualifiedName((type as Type.Parameterized).type);
112
+ case Type.Kind.Array:
113
+ const arrayType = type as Type.Array;
114
+ return this.typeToString(arrayType.elemType) + '[]';
115
+ case Type.Kind.GenericTypeVariable:
116
+ return (type as Type.GenericTypeVariable).name;
117
+ default:
118
+ return 'unknown';
119
+ }
120
+ }
121
+
122
+ private matchesPackage(packageName?: string): boolean {
123
+ const pkg = packageName || '';
124
+
125
+ // Handle *..* pattern (any package including nested)
126
+ if (this.packagePattern === '*..') {
127
+ return true;
128
+ }
129
+
130
+ // Handle * pattern (no package or any single-level package)
131
+ if (this.packagePattern === '*') {
132
+ return true;
133
+ }
134
+
135
+ // Handle lib.* pattern (lib and any subpackage)
136
+ if (this.packagePattern.endsWith('.*')) {
137
+ const prefix = this.packagePattern.slice(0, -2);
138
+ return pkg === prefix || pkg.startsWith(prefix + '.');
139
+ }
140
+
141
+ // Exact match
142
+ return pkg === this.packagePattern;
143
+ }
144
+
145
+ private matchesPattern(pattern: string, value: string): boolean {
146
+ if (pattern === '*') {
147
+ return true;
148
+ }
149
+
150
+ // Handle patterns with wildcards
151
+ if (pattern.includes('*')) {
152
+ // Convert pattern to regex
153
+ const regexPattern = pattern
154
+ .replace(/[.+?^${}()|[\]\\]/g, '\\$&') // Escape special chars except *
155
+ .replace(/\*/g, '.*'); // Replace * with .*
156
+ const regex = new RegExp(`^${regexPattern}$`);
157
+ return regex.test(value);
158
+ }
159
+
160
+ return pattern === value;
161
+ }
162
+
163
+ private matchesArguments(args: string[]): boolean {
164
+ // Handle .. pattern (any arguments)
165
+ if (this.argumentPatterns.length === 1 && this.argumentPatterns[0] === '..') {
166
+ return true;
167
+ }
168
+
169
+ // Handle patterns with .. in arguments
170
+ let patternIndex = 0;
171
+ let argIndex = 0;
172
+
173
+ while (patternIndex < this.argumentPatterns.length && argIndex < args.length) {
174
+ const pattern = this.argumentPatterns[patternIndex];
175
+
176
+ if (pattern === '..') {
177
+ // If .. is the last pattern, it matches all remaining args
178
+ if (patternIndex === this.argumentPatterns.length - 1) {
179
+ return true;
180
+ }
181
+
182
+ // Otherwise, try to match the next pattern with remaining args
183
+ const nextPattern = this.argumentPatterns[patternIndex + 1];
184
+ let matched = false;
185
+ for (let i = argIndex; i < args.length; i++) {
186
+ if (this.matchesArgumentPattern(nextPattern, args[i])) {
187
+ argIndex = i + 1;
188
+ patternIndex += 2;
189
+ matched = true;
190
+ break;
191
+ }
192
+ }
193
+ if (!matched) {
194
+ return false;
195
+ }
196
+ } else {
197
+ if (!this.matchesArgumentPattern(pattern, args[argIndex])) {
198
+ return false;
199
+ }
200
+ patternIndex++;
201
+ argIndex++;
202
+ }
203
+ }
204
+
205
+ // Check if all patterns and arguments are consumed
206
+ if (patternIndex < this.argumentPatterns.length) {
207
+ // Allow trailing .. to match zero arguments
208
+ return patternIndex === this.argumentPatterns.length - 1 &&
209
+ this.argumentPatterns[patternIndex] === '..';
210
+ }
211
+
212
+ return argIndex === args.length;
213
+ }
214
+
215
+ private matchesArgumentPattern(pattern: string, arg: string): boolean {
216
+ // Handle type patterns like lib.Array
217
+ if (pattern.includes('.')) {
218
+ // Also check if the pattern is a TypeScript primitive class (lib.Number, lib.String, lib.Boolean)
219
+ const normalizedPattern = this.normalizePrimitiveType(pattern);
220
+ const normalizedArg = this.normalizePrimitiveType(arg);
221
+ return normalizedPattern === normalizedArg;
222
+ }
223
+
224
+ // Normalize TypeScript primitive names to match both primitive and class representations
225
+ const normalizedPattern = this.normalizePrimitiveType(pattern);
226
+ const normalizedArg = this.normalizePrimitiveType(arg);
227
+
228
+ return normalizedPattern === normalizedArg;
229
+ }
230
+
231
+ private normalizePrimitiveType(type: string): string {
232
+ switch (type) {
233
+ case 'number':
234
+ case 'Number':
235
+ case 'lib.Number':
236
+ case 'double':
237
+ return 'Number';
238
+ case 'string':
239
+ case 'String':
240
+ case 'lib.String':
241
+ return 'String';
242
+ case 'boolean':
243
+ case 'Boolean':
244
+ case 'lib.Boolean':
245
+ return 'Boolean';
246
+ default:
247
+ return type;
248
+ }
249
+ }
250
+ }