Skip to content

Commit

Permalink
Added Normalize Formatter (#214)
Browse files Browse the repository at this point in the history
Co-authored-by: Andrii Rodionov <andriih@moderne.io>
  • Loading branch information
arodionov and Andrii Rodionov authored Mar 10, 2025
1 parent 9a81022 commit b4fec60
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 10 deletions.
7 changes: 0 additions & 7 deletions openrewrite/src/javascript/format/blankLines.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,8 @@ export class BlankLinesFormatVisitor extends JavaScriptVisitor<InMemoryExecution
}

function adjustedLinesForTree(tree: J.J, minLines: number, maxLines: number): J.J {

if (tree instanceof JS.ScopedVariableDeclarations && tree.padding.scope) {
const prefix = tree.padding.scope.before;
return tree.padding.withScope(tree.padding.scope.withBefore(adjustedLinesForSpace(prefix, minLines, maxLines)));
} else {
const prefix = tree.prefix;
return tree.withPrefix(adjustedLinesForSpace(prefix, minLines, maxLines));
}

}

function adjustedLinesForSpace(prefix: Space, minLines: number, maxLines: number): Space {
Expand Down
72 changes: 72 additions & 0 deletions openrewrite/src/javascript/format/normalizeSpaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import * as J from '../../java';
import * as JS from '..';
import {JavaScriptVisitor} from "..";
import {Cursor, InMemoryExecutionContext} from "../../core";
import {Space, TextComment} from '../../java';

export class NormalizeFormatVisitor extends JavaScriptVisitor<InMemoryExecutionContext> {

constructor() {
super();
this.cursor = new Cursor(null, Cursor.ROOT_VALUE);
}

visitScopedVariableDeclarations(scopedVariableDeclarations: JS.ScopedVariableDeclarations, p: InMemoryExecutionContext): J.J | null {
let vd = super.visitScopedVariableDeclarations(scopedVariableDeclarations, p) as JS.ScopedVariableDeclarations;

if (vd.padding.scope) {
vd = concatenatePrefix(vd, vd.padding.scope.before);
if (vd.padding.scope) {
vd = vd.padding.withScope(vd.padding.scope.withBefore(Space.EMPTY));
}
}

return vd;
}

}

function concatenatePrefix<J2 extends J.J>(j: J2, prefix: Space): J2 {
const shift = commonMargin(null, j.prefix.whitespace ?? "");

const comments = [
...j.prefix.comments,
...prefix.comments.map((comment) => {
let c = comment;

if (shift === "") {
return c;
}

if (c instanceof TextComment) {
const textComment = c as TextComment;
c = textComment.withText(textComment.text.replace("\n", "\n" + shift));
}

if (c.suffix.includes("\n")) {
c = c.withSuffix(c.suffix.replace("\n", "\n" + shift));
}

return c;
})
];

return j.withPrefix(
j.prefix.withWhitespace((j.prefix.whitespace ?? "") + (prefix.whitespace ?? ""))
.withComments(comments)
) as J2;
}


function commonMargin(s1: string | null, s2: string): string {
if (s1 === null) {
const s = s2.toString();
return s.substring(s.lastIndexOf('\n') + 1);
}
for (let i = 0; i < s1.length && i < s2.length; i++) {
if (s1.charAt(i) !== s2.charAt(i) || !/\s/.test(s1.charAt(i))) {
return s1.substring(0, i);
}
}
return s2.length < s1.length ? s2 : s1;
}
19 changes: 16 additions & 3 deletions openrewrite/test/javascript/format/blankLines.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
typeScript
} from '../testHarness';
import {BlankLinesFormatVisitor} from "../../../dist/src/javascript/format/blankLines";
import {NormalizeFormatVisitor} from "../../../dist/src/javascript/format/normalizeSpaces";
import {fromVisitor, RecipeSpec} from "../recipeHarness";
import {IntelliJ} from "../../../dist/src/javascript/style";

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

test('blank lines after import and variables', () => {
rewriteRunWithRecipe(
new RecipeSpec().withRecipe(fromVisitor(new BlankLinesFormatVisitor(IntelliJ.TypeScript.blankLines()))),
new RecipeSpec()
.withRecipes(
fromVisitor(new NormalizeFormatVisitor()),
fromVisitor(new BlankLinesFormatVisitor(IntelliJ.TypeScript.blankLines()))
),
//language=typescript
typeScript(`
import {Component} from 'React'
Expand All @@ -50,7 +55,11 @@ let printed = print("sourceFile");`,

test('blank lines exists after import and variables', () => {
rewriteRunWithRecipe(
new RecipeSpec().withRecipe(fromVisitor(new BlankLinesFormatVisitor(IntelliJ.TypeScript.blankLines()))),
new RecipeSpec()
.withRecipes(
fromVisitor(new NormalizeFormatVisitor()),
fromVisitor(new BlankLinesFormatVisitor(IntelliJ.TypeScript.blankLines()))
),
//language=typescript
typeScript(`
import {Component} from 'React'
Expand All @@ -70,7 +79,11 @@ let printed = print("sourceFile");`,

test('blank lines exists after import and variables large maximum', () => {
rewriteRunWithRecipe(
new RecipeSpec().withRecipe(fromVisitor(new BlankLinesFormatVisitor(IntelliJ.TypeScript.blankLines()))),
new RecipeSpec()
.withRecipes(
fromVisitor(new NormalizeFormatVisitor()),
fromVisitor(new BlankLinesFormatVisitor(IntelliJ.TypeScript.blankLines()))
),
//language=typescript
typeScript(`
import {Component} from 'React'
Expand Down
18 changes: 18 additions & 0 deletions openrewrite/test/javascript/recipeHarness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,24 @@ export class RecipeSpec {
withRecipe(recipe: Recipe): RecipeSpec {
return recipe === this._recipe ? this : new RecipeSpec(recipe);
}

withRecipes(...recipes: Recipe[]): RecipeSpec {
return new RecipeSpec(new CompositeRecipe(recipes));
}

}

export class CompositeRecipe extends Recipe {
readonly recipes: Iterable<Recipe>;

constructor(recipes: Iterable<Recipe>) {
super();
this.recipes = recipes;
}

override getRecipeList(): Recipe[] {
return Array.from(this.recipes);
}
}

export class AdHocRecipe extends Recipe {
Expand Down

0 comments on commit b4fec60

Please # to comment.