Skip to content
This repository was archived by the owner on May 12, 2025. It is now read-only.

Commit b4fec60

Browse files
arodionovAndrii Rodionov
andauthored
Added Normalize Formatter (#214)
Co-authored-by: Andrii Rodionov <andriih@moderne.io>
1 parent 9a81022 commit b4fec60

File tree

4 files changed

+106
-10
lines changed

4 files changed

+106
-10
lines changed

openrewrite/src/javascript/format/blankLines.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,8 @@ export class BlankLinesFormatVisitor extends JavaScriptVisitor<InMemoryExecution
9494
}
9595

9696
function adjustedLinesForTree(tree: J.J, minLines: number, maxLines: number): J.J {
97-
98-
if (tree instanceof JS.ScopedVariableDeclarations && tree.padding.scope) {
99-
const prefix = tree.padding.scope.before;
100-
return tree.padding.withScope(tree.padding.scope.withBefore(adjustedLinesForSpace(prefix, minLines, maxLines)));
101-
} else {
10297
const prefix = tree.prefix;
10398
return tree.withPrefix(adjustedLinesForSpace(prefix, minLines, maxLines));
104-
}
105-
10699
}
107100

108101
function adjustedLinesForSpace(prefix: Space, minLines: number, maxLines: number): Space {
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import * as J from '../../java';
2+
import * as JS from '..';
3+
import {JavaScriptVisitor} from "..";
4+
import {Cursor, InMemoryExecutionContext} from "../../core";
5+
import {Space, TextComment} from '../../java';
6+
7+
export class NormalizeFormatVisitor extends JavaScriptVisitor<InMemoryExecutionContext> {
8+
9+
constructor() {
10+
super();
11+
this.cursor = new Cursor(null, Cursor.ROOT_VALUE);
12+
}
13+
14+
visitScopedVariableDeclarations(scopedVariableDeclarations: JS.ScopedVariableDeclarations, p: InMemoryExecutionContext): J.J | null {
15+
let vd = super.visitScopedVariableDeclarations(scopedVariableDeclarations, p) as JS.ScopedVariableDeclarations;
16+
17+
if (vd.padding.scope) {
18+
vd = concatenatePrefix(vd, vd.padding.scope.before);
19+
if (vd.padding.scope) {
20+
vd = vd.padding.withScope(vd.padding.scope.withBefore(Space.EMPTY));
21+
}
22+
}
23+
24+
return vd;
25+
}
26+
27+
}
28+
29+
function concatenatePrefix<J2 extends J.J>(j: J2, prefix: Space): J2 {
30+
const shift = commonMargin(null, j.prefix.whitespace ?? "");
31+
32+
const comments = [
33+
...j.prefix.comments,
34+
...prefix.comments.map((comment) => {
35+
let c = comment;
36+
37+
if (shift === "") {
38+
return c;
39+
}
40+
41+
if (c instanceof TextComment) {
42+
const textComment = c as TextComment;
43+
c = textComment.withText(textComment.text.replace("\n", "\n" + shift));
44+
}
45+
46+
if (c.suffix.includes("\n")) {
47+
c = c.withSuffix(c.suffix.replace("\n", "\n" + shift));
48+
}
49+
50+
return c;
51+
})
52+
];
53+
54+
return j.withPrefix(
55+
j.prefix.withWhitespace((j.prefix.whitespace ?? "") + (prefix.whitespace ?? ""))
56+
.withComments(comments)
57+
) as J2;
58+
}
59+
60+
61+
function commonMargin(s1: string | null, s2: string): string {
62+
if (s1 === null) {
63+
const s = s2.toString();
64+
return s.substring(s.lastIndexOf('\n') + 1);
65+
}
66+
for (let i = 0; i < s1.length && i < s2.length; i++) {
67+
if (s1.charAt(i) !== s2.charAt(i) || !/\s/.test(s1.charAt(i))) {
68+
return s1.substring(0, i);
69+
}
70+
}
71+
return s2.length < s1.length ? s2 : s1;
72+
}

openrewrite/test/javascript/format/blankLines.test.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
typeScript
77
} from '../testHarness';
88
import {BlankLinesFormatVisitor} from "../../../dist/src/javascript/format/blankLines";
9+
import {NormalizeFormatVisitor} from "../../../dist/src/javascript/format/normalizeSpaces";
910
import {fromVisitor, RecipeSpec} from "../recipeHarness";
1011
import {IntelliJ} from "../../../dist/src/javascript/style";
1112

@@ -29,7 +30,11 @@ let printed = print("sourceFile");`,
2930

3031
test('blank lines after import and variables', () => {
3132
rewriteRunWithRecipe(
32-
new RecipeSpec().withRecipe(fromVisitor(new BlankLinesFormatVisitor(IntelliJ.TypeScript.blankLines()))),
33+
new RecipeSpec()
34+
.withRecipes(
35+
fromVisitor(new NormalizeFormatVisitor()),
36+
fromVisitor(new BlankLinesFormatVisitor(IntelliJ.TypeScript.blankLines()))
37+
),
3338
//language=typescript
3439
typeScript(`
3540
import {Component} from 'React'
@@ -50,7 +55,11 @@ let printed = print("sourceFile");`,
5055

5156
test('blank lines exists after import and variables', () => {
5257
rewriteRunWithRecipe(
53-
new RecipeSpec().withRecipe(fromVisitor(new BlankLinesFormatVisitor(IntelliJ.TypeScript.blankLines()))),
58+
new RecipeSpec()
59+
.withRecipes(
60+
fromVisitor(new NormalizeFormatVisitor()),
61+
fromVisitor(new BlankLinesFormatVisitor(IntelliJ.TypeScript.blankLines()))
62+
),
5463
//language=typescript
5564
typeScript(`
5665
import {Component} from 'React'
@@ -70,7 +79,11 @@ let printed = print("sourceFile");`,
7079

7180
test('blank lines exists after import and variables large maximum', () => {
7281
rewriteRunWithRecipe(
73-
new RecipeSpec().withRecipe(fromVisitor(new BlankLinesFormatVisitor(IntelliJ.TypeScript.blankLines()))),
82+
new RecipeSpec()
83+
.withRecipes(
84+
fromVisitor(new NormalizeFormatVisitor()),
85+
fromVisitor(new BlankLinesFormatVisitor(IntelliJ.TypeScript.blankLines()))
86+
),
7487
//language=typescript
7588
typeScript(`
7689
import {Component} from 'React'

openrewrite/test/javascript/recipeHarness.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,24 @@ export class RecipeSpec {
1818
withRecipe(recipe: Recipe): RecipeSpec {
1919
return recipe === this._recipe ? this : new RecipeSpec(recipe);
2020
}
21+
22+
withRecipes(...recipes: Recipe[]): RecipeSpec {
23+
return new RecipeSpec(new CompositeRecipe(recipes));
24+
}
25+
26+
}
27+
28+
export class CompositeRecipe extends Recipe {
29+
readonly recipes: Iterable<Recipe>;
30+
31+
constructor(recipes: Iterable<Recipe>) {
32+
super();
33+
this.recipes = recipes;
34+
}
35+
36+
override getRecipeList(): Recipe[] {
37+
return Array.from(this.recipes);
38+
}
2139
}
2240

2341
export class AdHocRecipe extends Recipe {

0 commit comments

Comments
 (0)