diff --git a/openrewrite/src/javascript/format/blankLines.ts b/openrewrite/src/javascript/format/blankLines.ts index 36517dd..be8bf96 100644 --- a/openrewrite/src/javascript/format/blankLines.ts +++ b/openrewrite/src/javascript/format/blankLines.ts @@ -94,15 +94,8 @@ export class BlankLinesFormatVisitor extends JavaScriptVisitor { + + 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(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; +} diff --git a/openrewrite/test/javascript/format/blankLines.test.ts b/openrewrite/test/javascript/format/blankLines.test.ts index a2860a5..240fd1b 100644 --- a/openrewrite/test/javascript/format/blankLines.test.ts +++ b/openrewrite/test/javascript/format/blankLines.test.ts @@ -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"; @@ -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' @@ -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' @@ -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' diff --git a/openrewrite/test/javascript/recipeHarness.ts b/openrewrite/test/javascript/recipeHarness.ts index ece3100..4d37aee 100644 --- a/openrewrite/test/javascript/recipeHarness.ts +++ b/openrewrite/test/javascript/recipeHarness.ts @@ -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; + + constructor(recipes: Iterable) { + super(); + this.recipes = recipes; + } + + override getRecipeList(): Recipe[] { + return Array.from(this.recipes); + } } export class AdHocRecipe extends Recipe {