@openrewrite/rewrite 8.53.0 → 8.53.1

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 (48) hide show
  1. package/dist/src/java/visitor.d.ts.map +1 -1
  2. package/dist/src/java/visitor.js +10 -0
  3. package/dist/src/java/visitor.js.map +1 -1
  4. package/dist/src/javascript/assertions.d.ts +2 -0
  5. package/dist/src/javascript/assertions.d.ts.map +1 -1
  6. package/dist/src/javascript/assertions.js +20 -0
  7. package/dist/src/javascript/assertions.js.map +1 -1
  8. package/dist/src/javascript/format.d.ts +62 -44
  9. package/dist/src/javascript/format.d.ts.map +1 -1
  10. package/dist/src/javascript/format.js +244 -12
  11. package/dist/src/javascript/format.js.map +1 -1
  12. package/dist/src/javascript/parser.d.ts +11 -15
  13. package/dist/src/javascript/parser.d.ts.map +1 -1
  14. package/dist/src/javascript/parser.js +136 -56
  15. package/dist/src/javascript/parser.js.map +1 -1
  16. package/dist/src/javascript/print.d.ts +7 -3
  17. package/dist/src/javascript/print.d.ts.map +1 -1
  18. package/dist/src/javascript/print.js +93 -35
  19. package/dist/src/javascript/print.js.map +1 -1
  20. package/dist/src/javascript/rpc.js +83 -0
  21. package/dist/src/javascript/rpc.js.map +1 -1
  22. package/dist/src/javascript/style.d.ts +19 -6
  23. package/dist/src/javascript/style.d.ts.map +1 -1
  24. package/dist/src/javascript/style.js +31 -4
  25. package/dist/src/javascript/style.js.map +1 -1
  26. package/dist/src/javascript/tree.d.ts +48 -4
  27. package/dist/src/javascript/tree.d.ts.map +1 -1
  28. package/dist/src/javascript/tree.js +1 -1
  29. package/dist/src/javascript/tree.js.map +1 -1
  30. package/dist/src/javascript/visitor.d.ts +6 -1
  31. package/dist/src/javascript/visitor.d.ts.map +1 -1
  32. package/dist/src/javascript/visitor.js +59 -0
  33. package/dist/src/javascript/visitor.js.map +1 -1
  34. package/dist/src/tree.d.ts +1 -0
  35. package/dist/src/tree.d.ts.map +1 -1
  36. package/dist/src/tree.js +4 -0
  37. package/dist/src/tree.js.map +1 -1
  38. package/package.json +1 -1
  39. package/src/java/visitor.ts +12 -0
  40. package/src/javascript/assertions.ts +20 -0
  41. package/src/javascript/format.ts +254 -71
  42. package/src/javascript/parser.ts +195 -76
  43. package/src/javascript/print.ts +90 -39
  44. package/src/javascript/rpc.ts +78 -1
  45. package/src/javascript/style.ts +47 -9
  46. package/src/javascript/tree.ts +75 -4
  47. package/src/javascript/visitor.ts +56 -1
  48. package/src/tree.ts +5 -0
@@ -14,37 +14,51 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  import {JS} from "./tree";
17
- import {ExecutionContext} from "../execution";
18
17
  import {JavaScriptVisitor} from "./visitor";
19
- import {Comment, J, JavaType, Statement} from "../java";
18
+ import {Comment, J, Statement} from "../java";
20
19
  import {Draft, produce} from "immer";
21
20
  import {Cursor, isTree, Tree} from "../tree";
22
- import {SpacesStyle, styleFromSourceFile, StyleKind, WrappingAndBracesStyle, BlankLinesStyle} from "./style";
21
+ import {
22
+ BlankLinesStyle,
23
+ SpacesStyle,
24
+ styleFromSourceFile,
25
+ StyleKind,
26
+ TabsAndIndentsStyle,
27
+ WrappingAndBracesStyle
28
+ } from "./style";
23
29
  import {produceAsync} from "../visitor";
24
30
 
25
- export class AutoformatVisitor extends JavaScriptVisitor<ExecutionContext> {
26
- async visit<R extends J>(tree: Tree, p: ExecutionContext, cursor?: Cursor): Promise<R | undefined> {
31
+ export class AutoformatVisitor<P> extends JavaScriptVisitor<P> {
32
+ async visit<R extends J>(tree: Tree, p: P, cursor?: Cursor): Promise<R | undefined> {
27
33
  const spacesStyle = styleFromSourceFile(StyleKind.SpacesStyle, tree) as SpacesStyle;
28
34
  const wrappingAndBracesStyle = styleFromSourceFile(StyleKind.WrappingAndBracesStyle, tree) as WrappingAndBracesStyle;
29
35
  const blankLinesStyle = styleFromSourceFile(StyleKind.BlankLinesStyle, tree) as BlankLinesStyle;
36
+ const tabsAndIndentsStyle = styleFromSourceFile(StyleKind.TabsAndIndentsStyle, tree) as TabsAndIndentsStyle;
30
37
  let t: R | undefined = tree as R;
31
38
  // TODO possibly cursor.fork
32
39
 
33
- // TODO enable them once we have the indenting visitor
34
- // t = t && await new MinimumViableSpacingVisitor().visit(t, p, cursor);
35
- // t = t && await new BlankLinesVisitor(blankLinesStyle).visit(t, p, cursor);
40
+ t = t && await new MinimumViableSpacingVisitor().visit(t, p, cursor);
41
+ t = t && await new BlankLinesVisitor(blankLinesStyle).visit(t, p, cursor);
36
42
  t = t && await new WrappingAndBracesVisitor(wrappingAndBracesStyle).visit(t, p, cursor);
37
43
  t = t && await new SpacesVisitor(spacesStyle).visit(t, p, cursor);
44
+ t = t && await new TabsAndIndentsVisitor(tabsAndIndentsStyle).visit(t, p, cursor);
38
45
  return t;
39
46
  }
40
47
  }
41
48
 
42
- export class SpacesVisitor extends JavaScriptVisitor<ExecutionContext> {
49
+ export class SpacesVisitor<P> extends JavaScriptVisitor<P> {
43
50
  constructor(private style: SpacesStyle) {
44
51
  super();
45
52
  }
46
53
 
47
- protected async visitArrayAccess(arrayAccess: J.ArrayAccess, p: ExecutionContext): Promise<J | undefined> {
54
+ protected async visitAlias(alias: JS.Alias, p: P): Promise<J | undefined> {
55
+ const ret = await super.visitAlias(alias, p) as JS.Alias;
56
+ return produce(ret, draft => {
57
+ draft.propertyName.after.whitespace = " ";
58
+ });
59
+ }
60
+
61
+ protected async visitArrayAccess(arrayAccess: J.ArrayAccess, p: P): Promise<J | undefined> {
48
62
  const ret = await super.visitArrayAccess(arrayAccess, p) as J.ArrayAccess;
49
63
  return produce(ret, draft => {
50
64
  draft.dimension.index.element.prefix.whitespace = this.style.within.arrayBrackets ? " " : "";
@@ -52,7 +66,7 @@ export class SpacesVisitor extends JavaScriptVisitor<ExecutionContext> {
52
66
  });
53
67
  }
54
68
 
55
- protected async visitBinary(binary: J.Binary, p: ExecutionContext): Promise<J | undefined> {
69
+ protected async visitBinary(binary: J.Binary, p: P): Promise<J | undefined> {
56
70
  const ret = await super.visitBinary(binary, p) as J.Binary;
57
71
  let property = false;
58
72
  switch (ret.operator.element.valueOf()) {
@@ -99,7 +113,16 @@ export class SpacesVisitor extends JavaScriptVisitor<ExecutionContext> {
99
113
  }) as J.Binary;
100
114
  }
101
115
 
102
- protected async visitClassDeclaration(classDecl: J.ClassDeclaration, p: ExecutionContext): Promise<J | undefined> {
116
+ protected async visitCase(aCase: J.Case, p: P): Promise<J | undefined> {
117
+ const ret = await super.visitCase(aCase, p) as J.Case;
118
+ return ret && produce(ret, draft => {
119
+ if (draft.caseLabels.elements[0].element.kind != J.Kind.Identifier || (draft.caseLabels.elements[0].element as J.Identifier).simpleName != "default") {
120
+ draft.caseLabels.before.whitespace = " ";
121
+ }
122
+ });
123
+ }
124
+
125
+ protected async visitClassDeclaration(classDecl: J.ClassDeclaration, p: P): Promise<J | undefined> {
103
126
  const ret = await super.visitClassDeclaration(classDecl, p) as J.ClassDeclaration;
104
127
  // TODO
105
128
  // if (c.leadingAnnotations.length > 1) {
@@ -111,11 +134,47 @@ export class SpacesVisitor extends JavaScriptVisitor<ExecutionContext> {
111
134
 
112
135
  return produce(ret, draft => {
113
136
  draft.body.prefix.whitespace = this.style.beforeLeftBrace.catchLeftBrace ? " " : "";
114
- // TODO if (classDecl.body.statements.length === 0) {
137
+
138
+ if (draft.extends) {
139
+ draft.extends.before.whitespace = " ";
140
+ draft.extends.element.prefix.whitespace = " ";
141
+ }
115
142
  }) as J.ClassDeclaration;
116
143
  }
117
144
 
118
- protected async visitForLoop(forLoop: J.ForLoop, p: ExecutionContext): Promise<J | undefined> {
145
+ protected async visitContainer<T extends J>(container: J.Container<T>, p: P): Promise<J.Container<T>> {
146
+ const ret = await super.visitContainer(container, p) as J.Container<T>;
147
+ return produce(ret, draft => {
148
+ if (draft.elements.length > 1) {
149
+ for (let i = 1; i < draft.elements.length; i++) {
150
+ draft.elements[i].element.prefix.whitespace = this.style.other.afterComma ? " " : "";
151
+ }
152
+ }
153
+ });
154
+ }
155
+
156
+ protected async visitExportDeclaration(exportDeclaration: JS.ExportDeclaration, p: P): Promise<J | undefined> {
157
+ const ret = await super.visitExportDeclaration(exportDeclaration, p) as JS.ExportDeclaration;
158
+ return produce(ret, draft => {
159
+ if (draft.exportClause) {
160
+ draft.exportClause.prefix.whitespace = " ";
161
+ if (draft.exportClause.kind == JS.Kind.NamedExports) {
162
+ const ne = (draft.exportClause as Draft<JS.NamedExports>);
163
+ if (ne.elements.elements.length > 0) {
164
+ ne.elements.elements[0].element.prefix.whitespace = this.style.within.es6ImportExportBraces ? " " : "";
165
+ ne.elements.elements[ne.elements.elements.length - 1].after.whitespace = this.style.within.es6ImportExportBraces ? " " : "";
166
+ }
167
+ }
168
+ }
169
+ draft.typeOnly.before.whitespace = draft.typeOnly.element ? " " : "";
170
+ if (draft.moduleSpecifier) {
171
+ draft.moduleSpecifier.before.whitespace = " ";
172
+ draft.moduleSpecifier.element.prefix.whitespace = " ";
173
+ }
174
+ })
175
+ }
176
+
177
+ protected async visitForLoop(forLoop: J.ForLoop, p: P): Promise<J | undefined> {
119
178
  const ret = await super.visitForLoop(forLoop, p) as J.ForLoop;
120
179
  return produceAsync(ret, async draft => {
121
180
  draft.control.prefix.whitespace = this.style.beforeParentheses.forParentheses ? " " : "";
@@ -144,7 +203,7 @@ export class SpacesVisitor extends JavaScriptVisitor<ExecutionContext> {
144
203
  });
145
204
  }
146
205
 
147
- protected async visitIf(iff: J.If, p: ExecutionContext): Promise<J | undefined> {
206
+ protected async visitIf(iff: J.If, p: P): Promise<J | undefined> {
148
207
  const ret = await super.visitIf(iff, p) as J.If;
149
208
  return produceAsync(ret, async draft => {
150
209
  draft.ifCondition = await this.spaceBefore(draft.ifCondition, this.style.beforeParentheses.ifParentheses);
@@ -153,7 +212,31 @@ export class SpacesVisitor extends JavaScriptVisitor<ExecutionContext> {
153
212
  });
154
213
  }
155
214
 
156
- protected async visitMethodDeclaration(methodDecl: J.MethodDeclaration, p: ExecutionContext): Promise<J | undefined> {
215
+ protected async visitImportDeclaration(jsImport: JS.Import, p: P): Promise<J | undefined> {
216
+ const ret = await super.visitImportDeclaration(jsImport, p) as JS.Import;
217
+ return produce(ret, draft => {
218
+ if (draft.importClause) {
219
+ draft.importClause.prefix.whitespace = draft.importClause.namedBindings && !draft.importClause.typeOnly ? "" : " ";
220
+ if (draft.importClause.name) {
221
+ draft.importClause.name.after.whitespace = "";
222
+ }
223
+ if (draft.importClause.namedBindings) {
224
+ draft.importClause.namedBindings.prefix.whitespace = " ";
225
+ if (draft.importClause.namedBindings.kind == JS.Kind.NamedImports) {
226
+ const ni = draft.importClause.namedBindings as Draft<JS.NamedImports>;
227
+ ni.elements.elements[0].element.prefix.whitespace = this.style.within.es6ImportExportBraces ? " " : "";
228
+ ni.elements.elements[ni.elements.elements.length - 1].after.whitespace = this.style.within.es6ImportExportBraces ? " " : "";
229
+ }
230
+ }
231
+ }
232
+ if (draft.moduleSpecifier) {
233
+ draft.moduleSpecifier.before.whitespace = " ";
234
+ draft.moduleSpecifier.element.prefix.whitespace = draft.importClause ? " " : "";
235
+ }
236
+ })
237
+ }
238
+
239
+ protected async visitMethodDeclaration(methodDecl: J.MethodDeclaration, p: P): Promise<J | undefined> {
157
240
  const ret = await super.visitMethodDeclaration(methodDecl, p) as J.MethodDeclaration;
158
241
  return produceAsync(ret, async draft => {
159
242
  draft.body = ret.body && await this.spaceBefore(ret.body, this.style.beforeLeftBrace.functionLeftBrace);
@@ -179,7 +262,7 @@ export class SpacesVisitor extends JavaScriptVisitor<ExecutionContext> {
179
262
  });
180
263
  }
181
264
 
182
- protected async visitMethodInvocation(methodInv: J.MethodInvocation, p: ExecutionContext): Promise<J | undefined> {
265
+ protected async visitMethodInvocation(methodInv: J.MethodInvocation, p: P): Promise<J | undefined> {
183
266
  const ret = await super.visitMethodInvocation(methodInv, p) as J.MethodInvocation;
184
267
  return produceAsync(ret, async draft => {
185
268
  if (draft.select) {
@@ -204,7 +287,7 @@ export class SpacesVisitor extends JavaScriptVisitor<ExecutionContext> {
204
287
  });
205
288
  }
206
289
 
207
- protected async visitRightPadded<T extends J | boolean>(right: J.RightPadded<T>, p: ExecutionContext): Promise<J.RightPadded<T>> {
290
+ protected async visitRightPadded<T extends J | boolean>(right: J.RightPadded<T>, p: P): Promise<J.RightPadded<T>> {
208
291
  const ret = await super.visitRightPadded(right, p);
209
292
  if (isTree(ret.element)) {
210
293
  switch (ret.element.kind) {
@@ -217,7 +300,7 @@ export class SpacesVisitor extends JavaScriptVisitor<ExecutionContext> {
217
300
  return ret;
218
301
  }
219
302
 
220
- protected async visitSwitch(switchNode: J.Switch, p: ExecutionContext): Promise<J | undefined> {
303
+ protected async visitSwitch(switchNode: J.Switch, p: P): Promise<J | undefined> {
221
304
  const ret = await super.visitSwitch(switchNode, p) as J.Switch;
222
305
  return produceAsync(ret, async draft => {
223
306
  draft.selector = await this.spaceBefore(draft.selector, this.style.beforeParentheses.switchParentheses);
@@ -235,7 +318,7 @@ export class SpacesVisitor extends JavaScriptVisitor<ExecutionContext> {
235
318
  });
236
319
  }
237
320
 
238
- protected async visitTernary(ternary: J.Ternary, p: ExecutionContext): Promise<J | undefined> {
321
+ protected async visitTernary(ternary: J.Ternary, p: P): Promise<J | undefined> {
239
322
  const ret = await super.visitTernary(ternary, p) as J.Ternary;
240
323
  return produceAsync(ret, async draft => {
241
324
  draft.truePart = await this.spaceBeforeLeftPaddedElement(draft.truePart, this.style.ternaryOperator.beforeQuestionMark, this.style.ternaryOperator.afterQuestionMark);
@@ -243,7 +326,7 @@ export class SpacesVisitor extends JavaScriptVisitor<ExecutionContext> {
243
326
  });
244
327
  }
245
328
 
246
- protected async visitTry(try_: J.Try, p: ExecutionContext): Promise<J | undefined> {
329
+ protected async visitTry(try_: J.Try, p: P): Promise<J | undefined> {
247
330
  const ret = await super.visitTry(try_, p) as J.Try;
248
331
  return produceAsync(ret, async draft => {
249
332
  draft.body.prefix.whitespace = this.style.beforeLeftBrace.tryLeftBrace ? " " : "";
@@ -259,7 +342,19 @@ export class SpacesVisitor extends JavaScriptVisitor<ExecutionContext> {
259
342
  });
260
343
  }
261
344
 
262
- protected async visitTypeInfo(typeInfo: JS.TypeInfo, p: ExecutionContext): Promise<J | undefined> {
345
+ protected async visitTypeDeclaration(typeDeclaration: JS.TypeDeclaration, p: P): Promise<J | undefined> {
346
+ const ret = await super.visitTypeDeclaration(typeDeclaration, p) as JS.TypeDeclaration;
347
+ return produce(ret, draft => {
348
+ if (draft.modifiers.length > 0) {
349
+ draft.name.before.whitespace = " ";
350
+ }
351
+ draft.name.element.prefix.whitespace = " ";
352
+ draft.initializer.before.whitespace = this.style.aroundOperators.assignment ? " " : "";
353
+ draft.initializer.element.prefix.whitespace = this.style.aroundOperators.assignment ? " " : "";
354
+ });
355
+ }
356
+
357
+ protected async visitTypeInfo(typeInfo: JS.TypeInfo, p: P): Promise<J | undefined> {
263
358
  const ret = await super.visitTypeInfo(typeInfo, p) as JS.TypeInfo;
264
359
  return produceAsync(ret, async draft => {
265
360
  draft.prefix.whitespace = this.style.other.beforeTypeReferenceColon ? " " : "";
@@ -267,7 +362,7 @@ export class SpacesVisitor extends JavaScriptVisitor<ExecutionContext> {
267
362
  });
268
363
  }
269
364
 
270
- protected async visitUnary(unary: J.Unary, p: ExecutionContext): Promise<J | undefined> {
365
+ protected async visitUnary(unary: J.Unary, p: P): Promise<J | undefined> {
271
366
  const ret = await super.visitUnary(unary, p) as J.Unary;
272
367
  return produce(ret, draft => {
273
368
  const spacing = this.style.aroundOperators.unary;
@@ -289,7 +384,7 @@ export class SpacesVisitor extends JavaScriptVisitor<ExecutionContext> {
289
384
  }
290
385
  });
291
386
  }
292
- protected async visitVariable(variable: J.VariableDeclarations.NamedVariable, p: ExecutionContext): Promise<J | undefined> {
387
+ protected async visitVariable(variable: J.VariableDeclarations.NamedVariable, p: P): Promise<J | undefined> {
293
388
  const ret = await super.visitVariable(variable, p) as J.VariableDeclarations.NamedVariable;
294
389
  return produceAsync(ret, async draft => {
295
390
  if (draft.initializer) {
@@ -298,7 +393,7 @@ export class SpacesVisitor extends JavaScriptVisitor<ExecutionContext> {
298
393
  });
299
394
  }
300
395
 
301
- protected async visitWhileLoop(whileLoop: J.WhileLoop, p: ExecutionContext): Promise<J | undefined> {
396
+ protected async visitWhileLoop(whileLoop: J.WhileLoop, p: P): Promise<J | undefined> {
302
397
  const ret = await super.visitWhileLoop(whileLoop, p) as J.WhileLoop;
303
398
  return produceAsync(ret, async draft => {
304
399
  draft.body = await this.spaceAfterRightPadded(await this.spaceBeforeRightPaddedElement(ret.body, this.style.beforeLeftBrace.whileLeftBrace), false);
@@ -408,12 +503,12 @@ export class SpacesVisitor extends JavaScriptVisitor<ExecutionContext> {
408
503
  }
409
504
  }
410
505
 
411
- export class WrappingAndBracesVisitor extends JavaScriptVisitor<ExecutionContext> {
506
+ export class WrappingAndBracesVisitor<P> extends JavaScriptVisitor<P> {
412
507
  constructor(private readonly style: WrappingAndBracesStyle) {
413
508
  super();
414
509
  }
415
510
 
416
- public async visitStatement(statement: Statement, p: ExecutionContext): Promise<Statement> {
511
+ public async visitStatement(statement: Statement, p: P): Promise<Statement> {
417
512
  const j = await super.visitStatement(statement, p) as Statement;
418
513
  // TODO is it needed?
419
514
  // const parent = this.cursor.parent?.value;
@@ -427,7 +522,7 @@ export class WrappingAndBracesVisitor extends JavaScriptVisitor<ExecutionContext
427
522
  return j;
428
523
  }
429
524
 
430
- protected async visitVariableDeclarations(multiVariable: J.VariableDeclarations, p: ExecutionContext): Promise<J.VariableDeclarations> {
525
+ protected async visitVariableDeclarations(multiVariable: J.VariableDeclarations, p: P): Promise<J.VariableDeclarations> {
431
526
  const v = await super.visitVariableDeclarations(multiVariable, p) as J.VariableDeclarations;
432
527
  const parent = this.cursor.parent?.value;
433
528
  if (parent?.kind === J.Kind.Block) {
@@ -445,7 +540,7 @@ export class WrappingAndBracesVisitor extends JavaScriptVisitor<ExecutionContext
445
540
  return v;
446
541
  }
447
542
 
448
- protected async visitMethodDeclaration(method: J.MethodDeclaration, p: ExecutionContext): Promise<J.MethodDeclaration> {
543
+ protected async visitMethodDeclaration(method: J.MethodDeclaration, p: P): Promise<J.MethodDeclaration> {
449
544
  const m = await super.visitMethodDeclaration(method, p) as J.MethodDeclaration;
450
545
  return produce(m, draft => {
451
546
  draft.leadingAnnotations = this.withNewlines(draft.leadingAnnotations);
@@ -463,7 +558,7 @@ export class WrappingAndBracesVisitor extends JavaScriptVisitor<ExecutionContext
463
558
  });
464
559
  }
465
560
 
466
- protected async visitElse(elsePart: J.If.Else, p: ExecutionContext): Promise<J.If.Else> {
561
+ protected async visitElse(elsePart: J.If.Else, p: P): Promise<J.If.Else> {
467
562
  const e = await super.visitElse(elsePart, p) as J.If.Else;
468
563
  const hasBody = e.body.element.kind === J.Kind.Block || e.body.element.kind === J.Kind.If;
469
564
 
@@ -480,7 +575,7 @@ export class WrappingAndBracesVisitor extends JavaScriptVisitor<ExecutionContext
480
575
  });
481
576
  }
482
577
 
483
- protected async visitClassDeclaration(classDecl: J.ClassDeclaration, p: ExecutionContext): Promise<J.ClassDeclaration> {
578
+ protected async visitClassDeclaration(classDecl: J.ClassDeclaration, p: P): Promise<J.ClassDeclaration> {
484
579
  const j = await super.visitClassDeclaration(classDecl, p) as J.ClassDeclaration;
485
580
  return produce(j, draft => {
486
581
  draft.leadingAnnotations = this.withNewlines(draft.leadingAnnotations);
@@ -497,7 +592,7 @@ export class WrappingAndBracesVisitor extends JavaScriptVisitor<ExecutionContext
497
592
  });
498
593
  }
499
594
 
500
- protected async visitBlock(block: J.Block, p: ExecutionContext): Promise<J.Block> {
595
+ protected async visitBlock(block: J.Block, p: P): Promise<J.Block> {
501
596
  const b = await super.visitBlock(block, p) as J.Block;
502
597
  return produce(b, draft => {
503
598
  if (!draft.end.whitespace.includes("\n") && (draft.statements.length == 0 || !draft.statements[draft.statements.length - 1].after.whitespace.includes("\n"))) {
@@ -506,7 +601,7 @@ export class WrappingAndBracesVisitor extends JavaScriptVisitor<ExecutionContext
506
601
  });
507
602
  }
508
603
 
509
- protected async visitSwitch(aSwitch: J.Switch, p: ExecutionContext): Promise<J | undefined> {
604
+ protected async visitSwitch(aSwitch: J.Switch, p: P): Promise<J | undefined> {
510
605
  return super.visitSwitch(aSwitch, p);
511
606
  }
512
607
 
@@ -553,12 +648,12 @@ export class WrappingAndBracesVisitor extends JavaScriptVisitor<ExecutionContext
553
648
  }
554
649
 
555
650
 
556
- export class MinimumViableSpacingVisitor extends JavaScriptVisitor<ExecutionContext> {
651
+ export class MinimumViableSpacingVisitor<P> extends JavaScriptVisitor<P> {
557
652
  constructor() {
558
653
  super();
559
654
  }
560
655
 
561
- override async visitSpace(space: J.Space, p: ExecutionContext): Promise<J.Space> {
656
+ override async visitSpace(space: J.Space, p: P): Promise<J.Space> {
562
657
  // Note - for some reason the original MinimumViableSpacingVisitor.java doesn't have it
563
658
  // and only has the logic in MinimumViableSpacingTest.defaults
564
659
  const ret = await super.visitSpace(space, p) as J.Space;
@@ -567,7 +662,7 @@ export class MinimumViableSpacingVisitor extends JavaScriptVisitor<ExecutionCont
567
662
  });
568
663
  }
569
664
 
570
- protected async visitClassDeclaration(classDecl: J.ClassDeclaration, p: ExecutionContext): Promise<J | undefined> {
665
+ protected async visitClassDeclaration(classDecl: J.ClassDeclaration, p: P): Promise<J | undefined> {
571
666
  let c = await super.visitClassDeclaration(classDecl, p) as J.ClassDeclaration;
572
667
  let first = c.leadingAnnotations.length === 0;
573
668
 
@@ -623,7 +718,7 @@ export class MinimumViableSpacingVisitor extends JavaScriptVisitor<ExecutionCont
623
718
  return c;
624
719
  }
625
720
 
626
- protected async visitMethodDeclaration(method: J.MethodDeclaration, p: ExecutionContext): Promise<J | undefined> {
721
+ protected async visitMethodDeclaration(method: J.MethodDeclaration, p: P): Promise<J | undefined> {
627
722
  let m = await super.visitMethodDeclaration(method, p) as J.MethodDeclaration;
628
723
  let first = m.leadingAnnotations.length === 0;
629
724
 
@@ -677,7 +772,7 @@ export class MinimumViableSpacingVisitor extends JavaScriptVisitor<ExecutionCont
677
772
  return m;
678
773
  }
679
774
 
680
- protected async visitNewClass(newClass: J.NewClass, p: ExecutionContext): Promise<J | undefined> {
775
+ protected async visitNewClass(newClass: J.NewClass, p: P): Promise<J | undefined> {
681
776
  const ret = await super.visitNewClass(newClass, p) as J.NewClass;
682
777
  return produce(ret, draft => {
683
778
  if (draft.class != undefined) {
@@ -686,7 +781,7 @@ export class MinimumViableSpacingVisitor extends JavaScriptVisitor<ExecutionCont
686
781
  });
687
782
  }
688
783
 
689
- protected async visitReturn(returnNode: J.Return, p: ExecutionContext): Promise<J | undefined> {
784
+ protected async visitReturn(returnNode: J.Return, p: P): Promise<J | undefined> {
690
785
  const r = await super.visitReturn(returnNode, p) as J.Return;
691
786
  if (r.expression && r.expression.prefix.whitespace === "" &&
692
787
  !r.markers.markers.find(m => m.id === "org.openrewrite.java.marker.ImplicitReturn")) {
@@ -697,14 +792,31 @@ export class MinimumViableSpacingVisitor extends JavaScriptVisitor<ExecutionCont
697
792
  return r;
698
793
  }
699
794
 
700
- protected async visitScopedVariableDeclarations(scopedVariableDeclarations: JS.ScopedVariableDeclarations, p: ExecutionContext): Promise<J | undefined> {
795
+ protected async visitScopedVariableDeclarations(scopedVariableDeclarations: JS.ScopedVariableDeclarations, p: P): Promise<J | undefined> {
701
796
  const ret = await super.visitScopedVariableDeclarations(scopedVariableDeclarations, p) as JS.ScopedVariableDeclarations;
702
797
  return ret.scope && produce(ret, draft => {
703
798
  draft.variables[0].element.prefix.whitespace = " ";
704
799
  });
705
800
  }
706
801
 
707
- protected async visitVariableDeclarations(v: J.VariableDeclarations, p: ExecutionContext): Promise<J | undefined> {
802
+ protected async visitThrow(thrown: J.Throw, p: P): Promise<J | undefined> {
803
+ const ret = await super.visitThrow(thrown, p) as J.Throw;
804
+ return ret && produce(ret, draft => {
805
+ draft.exception.prefix.whitespace = " ";
806
+ });
807
+ }
808
+
809
+ protected async visitTypeDeclaration(typeDeclaration: JS.TypeDeclaration, p: P): Promise<J | undefined> {
810
+ const ret = await super.visitTypeDeclaration(typeDeclaration, p) as JS.TypeDeclaration;
811
+ return produce(ret, draft => {
812
+ if (draft.modifiers.length > 0) {
813
+ draft.name.before.whitespace = " ";
814
+ }
815
+ draft.name.element.prefix.whitespace = " ";
816
+ });
817
+ }
818
+
819
+ protected async visitVariableDeclarations(v: J.VariableDeclarations, p: P): Promise<J | undefined> {
708
820
  let ret = await super.visitVariableDeclarations(v, p) as J.VariableDeclarations;
709
821
  let first = ret.leadingAnnotations.length === 0;
710
822
 
@@ -728,7 +840,7 @@ export class MinimumViableSpacingVisitor extends JavaScriptVisitor<ExecutionCont
728
840
  }
729
841
 
730
842
 
731
- protected async visitCase(caseNode: J.Case, p: ExecutionContext): Promise<J | undefined> {
843
+ protected async visitCase(caseNode: J.Case, p: P): Promise<J | undefined> {
732
844
  const c = await super.visitCase(caseNode, p) as J.Case;
733
845
 
734
846
  if (c.guard && c.caseLabels.elements.length > 0 && c.caseLabels.elements[c.caseLabels.elements.length - 1].after.whitespace === "") {
@@ -742,12 +854,12 @@ export class MinimumViableSpacingVisitor extends JavaScriptVisitor<ExecutionCont
742
854
  }
743
855
  }
744
856
 
745
- export class BlankLinesVisitor extends JavaScriptVisitor<ExecutionContext> {
857
+ export class BlankLinesVisitor<P> extends JavaScriptVisitor<P> {
746
858
  constructor(private readonly style: BlankLinesStyle) {
747
859
  super();
748
860
  }
749
861
 
750
- override async visit<R extends J>(tree: Tree, p: ExecutionContext, cursor?: Cursor): Promise<R | undefined> {
862
+ override async visit<R extends J>(tree: Tree, p: P, cursor?: Cursor): Promise<R | undefined> {
751
863
  if (tree.kind === JS.Kind.CompilationUnit) {
752
864
  const cu = produce(tree as JS.CompilationUnit, draft => {
753
865
  if (draft.prefix.comments.length == 0) {
@@ -756,11 +868,15 @@ export class BlankLinesVisitor extends JavaScriptVisitor<ExecutionContext> {
756
868
  });
757
869
  return super.visit(cu, p, cursor);
758
870
  }
759
-
871
+ if (tree.kind === J.Kind.MethodDeclaration) {
872
+ tree = produce(tree as J.MethodDeclaration, draft => {
873
+ this.ensurePrefixHasNewLine(draft);
874
+ });
875
+ }
760
876
  return super.visit(tree, p, cursor);
761
877
  }
762
878
 
763
- protected async visitClassDeclaration(classDecl: J.ClassDeclaration, p: ExecutionContext): Promise<J.ClassDeclaration> {
879
+ protected async visitClassDeclaration(classDecl: J.ClassDeclaration, p: P): Promise<J.ClassDeclaration> {
764
880
  let ret = await super.visitClassDeclaration(classDecl, p) as J.ClassDeclaration;
765
881
  if (!ret.body) return ret;
766
882
  return produce(ret, draft => {
@@ -799,28 +915,7 @@ export class BlankLinesVisitor extends JavaScriptVisitor<ExecutionContext> {
799
915
  });
800
916
  }
801
917
 
802
- protected async visitMethodDeclaration(method: J.MethodDeclaration, p: ExecutionContext): Promise<J.MethodDeclaration> {
803
- let j = await super.visitMethodDeclaration(method, p) as J.MethodDeclaration;
804
- if (!j.body) return j;
805
-
806
- // TODO check if it's relevant to TS/JS
807
- // j = produce(j, draft => {
808
- // if (draft.body!.statements.length === 0) {
809
- //
810
- // let end = this.minimumLines(draft.body!.end.whitespace, this.style.minimum.beforeMethodBody);
811
- // if (!end.whitespace.includes("\n") && this.style.minimum.beforeMethodBody > 0) {
812
- // end = { ...end, whitespace: "\n".repeat(this.style.minimum.beforeMethodBody) };
813
- // }
814
- // draft.body!.end = end;
815
- // } else {
816
- // draft.body!.statements[0] = this.minimumLines(draft.body!.statements[0], this.style.minimum.beforeMethodBody);
817
- // }
818
- // });
819
-
820
- return j;
821
- }
822
-
823
- override async visitStatement(statement: Statement, p: ExecutionContext): Promise<Statement> {
918
+ override async visitStatement(statement: Statement, p: P): Promise<Statement> {
824
919
  const ret = await super.visitStatement(statement, p) as Statement;
825
920
  const parent = this.cursor.parent?.value;
826
921
  const grandparent = this.cursor.parent?.parent?.value;
@@ -849,25 +944,32 @@ export class BlankLinesVisitor extends JavaScriptVisitor<ExecutionContext> {
849
944
  }
850
945
  this.keepMaximumBlankLines(draft, this.style.keepMaximum.inCode);
851
946
  }
947
+ } else if (parent?.kind === J.Kind.Block ||
948
+ (parent?.kind === JS.Kind.CompilationUnit && (parent! as JS.CompilationUnit).statements[0].element.id != draft.id) ||
949
+ (parent?.kind === J.Kind.Case)) {
950
+ this.ensurePrefixHasNewLine(draft);
852
951
  }
853
952
  });
854
953
  }
855
954
 
856
- protected async visitBlock(block: J.Block, p: ExecutionContext): Promise<J.Block> {
955
+ protected async visitBlock(block: J.Block, p: P): Promise<J.Block> {
857
956
  const b = await super.visitBlock(block, p) as J.Block;
858
957
  return produce(b, draft => {
958
+ if (!draft.end.whitespace.includes("\n")) {
959
+ draft.end.whitespace = draft.end.whitespace + "\n";
960
+ }
859
961
  // TODO check if it's relevant to TS/JS
860
962
  // draft.end = this.keepMaximumLines(draft.end, this.style.keepMaximum.beforeEndOfBlock);
861
963
  });
862
964
  }
863
965
 
864
- protected async visitEnumValue(enumValue: J.EnumValue, p: ExecutionContext): Promise<J.EnumValue> {
966
+ protected async visitEnumValue(enumValue: J.EnumValue, p: P): Promise<J.EnumValue> {
865
967
  const e = await super.visitEnumValue(enumValue, p) as J.EnumValue;
866
968
  this.keepMaximumBlankLines(e, this.style.keepMaximum.inCode);
867
969
  return e;
868
970
  }
869
971
  // TODO check if it's relevant to TS/JS
870
- // protected async visitNewClass(newClass: J.NewClass, p: ExecutionContext): Promise<J.NewClass> {
972
+ // protected async visitNewClass(newClass: J.NewClass, p: P): Promise<J.NewClass> {
871
973
  // const j = await super.visitNewClass(newClass, p) as J.NewClass;
872
974
  // if (!j.body) return j;
873
975
  //
@@ -902,7 +1004,88 @@ export class BlankLinesVisitor extends JavaScriptVisitor<ExecutionContext> {
902
1004
  }
903
1005
  }
904
1006
 
1007
+ private ensurePrefixHasNewLine<T extends J>(node: Draft<J>) {
1008
+ if (node.prefix && !node.prefix.whitespace.includes("\n")) {
1009
+ node.prefix.whitespace = "\n" + node.prefix.whitespace;
1010
+ }
1011
+ }
1012
+
905
1013
  private static countNewlines(s: string): number {
906
1014
  return [...s].filter(c => c === "\n").length;
907
1015
  }
908
1016
  }
1017
+
1018
+ export class TabsAndIndentsVisitor<P> extends JavaScriptVisitor<P> {
1019
+ private readonly newline: string;
1020
+ private readonly singleIndent: string;
1021
+
1022
+ constructor(private readonly tabsAndIndentsStyle: TabsAndIndentsStyle) {
1023
+ super();
1024
+ this.newline = "\n"; // TODO this should be configurable and come from some style too
1025
+
1026
+ if (this.tabsAndIndentsStyle.useTabCharacter) {
1027
+ this.singleIndent = "\t";
1028
+ } else {
1029
+ this.singleIndent = " ".repeat(this.tabsAndIndentsStyle.indentSize);
1030
+ }
1031
+ }
1032
+
1033
+ protected async preVisit(tree: J, p: P): Promise<J | undefined> {
1034
+ const ret = await super.preVisit(tree, p);
1035
+ const indentShouldIncrease = tree.kind === J.Kind.Block || tree.kind === J.Kind.Case;
1036
+ if (indentShouldIncrease) {
1037
+ this.cursor.messages.set("indentToUse", this.currentIndent + this.singleIndent);
1038
+ }
1039
+ return ret;
1040
+ }
1041
+
1042
+ async visit<R extends J>(tree: Tree, p: P, parent?: Cursor): Promise<R | undefined> {
1043
+ let ret = await super.visit(tree, p, parent) as R;
1044
+ if (ret == undefined) {
1045
+ return ret;
1046
+ }
1047
+ const relativeIndent = this.currentIndent;
1048
+
1049
+ return produce(ret, draft => {
1050
+ if (draft.prefix == undefined) {
1051
+ draft.prefix = {kind: J.Kind.Space, comments: [], whitespace: ""};
1052
+ }
1053
+ if (draft.prefix.whitespace.includes("\n")) {
1054
+ draft.prefix.whitespace = this.combineIndent(draft.prefix.whitespace, relativeIndent);
1055
+ }
1056
+ if (draft.kind === J.Kind.Block) {
1057
+ const block = draft as Draft<J> as Draft<J.Block>;
1058
+ block.end.whitespace = this.newline + relativeIndent;
1059
+ }
1060
+ });
1061
+ }
1062
+
1063
+ protected async visitLeftPadded<T extends J | J.Space | number | string | boolean>(left: J.LeftPadded<T>, p: P): Promise<J.LeftPadded<T>> {
1064
+ const ret = await super.visitLeftPadded(left, p);
1065
+ if (ret == undefined) {
1066
+ return ret;
1067
+ }
1068
+ return produce(ret, draft => {
1069
+ if (draft.before.whitespace.includes("\n")) {
1070
+ draft.before.whitespace = this.combineIndent(draft.before.whitespace, this.currentIndent);
1071
+ }
1072
+ });
1073
+ }
1074
+
1075
+ private get currentIndent(): string {
1076
+ const indent = this.cursor.getNearestMessage("indentToUse");
1077
+ if (indent == undefined) {
1078
+ const enclosingWhitespace = this.cursor.firstEnclosing((x: any): x is J => x.prefix && x.prefix.whitespace.includes("\n"))?.prefix.whitespace;
1079
+ if (enclosingWhitespace) {
1080
+ return enclosingWhitespace.substring(enclosingWhitespace.lastIndexOf("\n") + 1);
1081
+ } else {
1082
+ return "";
1083
+ }
1084
+ }
1085
+ return indent;
1086
+ }
1087
+
1088
+ private combineIndent(oldWs: string, relativeIndent: string): string {
1089
+ return oldWs.substring(0, oldWs.lastIndexOf("\n") + 1) + relativeIndent;
1090
+ }
1091
+ }