๐Ÿš€ Grammar-Aware Code Formatter: Structure through separation (supports Go, JavaScript, TypeScript, JSX, and TSX)
go formatter code-formatter javascript typescript jsx tsx

fix(adapter): Suppress blank lines before continuation keywords (else/catch/finally)

fuwn.net b15244a3 f1dfe6b1

verified
+75 -66
+29 -24
adapter_ecmascript.go
··· 97 97 continue 98 98 } 99 99 100 - statementType, isScoped := classifyEcmaScriptStatement(trimmedContent) 100 + statementType, isScoped, isContinuation := classifyEcmaScriptStatement(trimmedContent) 101 101 102 102 if statementType != "" { 103 103 event.HasASTInfo = true 104 104 event.StatementType = statementType 105 105 event.IsScoped = isScoped 106 + event.IsContinuation = isContinuation 106 107 event.IsTopLevel = ecmaScriptLineIsTopLevel(currentLine) 107 108 event.IsStartLine = true 108 109 } else { ··· 117 118 return source, events, nil 118 119 } 119 120 120 - func classifyEcmaScriptStatement(trimmedLine string) (string, bool) { 121 + func classifyEcmaScriptStatement(trimmedLine string) (string, bool, bool) { 121 122 classified := trimmedLine 122 123 123 124 if strings.HasPrefix(classified, "export default ") { ··· 136 137 137 138 switch { 138 139 case ecmaScriptStatementHasPrefix(classified, "function"): 139 - return "function", true 140 + return "function", true, false 140 141 case ecmaScriptStatementHasPrefix(classified, "class"): 141 - return "class", true 142 + return "class", true, false 142 143 case ecmaScriptStatementHasPrefix(classified, "if"): 143 - return "if", true 144 + return "if", true, false 144 145 case ecmaScriptStatementHasPrefix(classified, "else"): 145 - return "if", true 146 + return "if", true, true 146 147 case ecmaScriptStatementHasPrefix(classified, "for"): 147 - return "for", true 148 + return "for", true, false 148 149 case ecmaScriptStatementHasPrefix(classified, "while"): 149 - return "while", true 150 + return "while", true, false 150 151 case ecmaScriptStatementHasPrefix(classified, "do"): 151 - return "do", true 152 + return "do", true, false 152 153 case ecmaScriptStatementHasPrefix(classified, "switch"): 153 - return "switch", true 154 + return "switch", true, false 154 155 case ecmaScriptStatementHasPrefix(classified, "try"): 155 - return "try", true 156 + return "try", true, false 157 + case ecmaScriptStatementHasPrefix(classified, "catch"): 158 + return "try", true, true 159 + case ecmaScriptStatementHasPrefix(classified, "finally"): 160 + return "try", true, true 156 161 case ecmaScriptStatementHasPrefix(classified, "interface"): 157 - return "interface", true 162 + return "interface", true, false 158 163 case ecmaScriptStatementHasPrefix(classified, "enum"): 159 - return "enum", true 164 + return "enum", true, false 160 165 case ecmaScriptStatementHasPrefix(classified, "namespace"): 161 - return "namespace", true 166 + return "namespace", true, false 162 167 case ecmaScriptStatementHasPrefix(classified, "const"): 163 - return "const", false 168 + return "const", false, false 164 169 case ecmaScriptStatementHasPrefix(classified, "let"): 165 - return "let", false 170 + return "let", false, false 166 171 case ecmaScriptStatementHasPrefix(classified, "var"): 167 - return "var", false 172 + return "var", false, false 168 173 case ecmaScriptStatementHasPrefix(classified, "import"): 169 - return "import", false 174 + return "import", false, false 170 175 case ecmaScriptStatementHasPrefix(classified, "type"): 171 - return "type", false 176 + return "type", false, false 172 177 case ecmaScriptStatementHasPrefix(classified, "return"): 173 - return "return", false 178 + return "return", false, false 174 179 case ecmaScriptStatementHasPrefix(classified, "throw"): 175 - return "throw", false 180 + return "throw", false, false 176 181 case ecmaScriptStatementHasPrefix(classified, "await"): 177 - return "await", false 182 + return "await", false, false 178 183 case ecmaScriptStatementHasPrefix(classified, "yield"): 179 - return "yield", false 184 + return "yield", false, false 180 185 } 181 186 182 - return "", false 187 + return "", false, false 183 188 } 184 189 185 190 func ecmaScriptStatementHasPrefix(line string, keyword string) bool {
+44 -41
adapter_ecmascript_test.go
··· 411 411 412 412 func TestClassifyEcmaScriptStatement(t *testing.T) { 413 413 cases := []struct { 414 - input string 415 - expectedType string 416 - expectedScope bool 414 + input string 415 + expectedType string 416 + expectedScope bool 417 + expectedContinuation bool 417 418 }{ 418 - {"function foo() {", "function", true}, 419 - {"async function foo() {", "function", true}, 420 - {"export function foo() {", "function", true}, 421 - {"export default function() {", "function", true}, 422 - {"class Foo {", "class", true}, 423 - {"export class Foo {", "class", true}, 424 - {"if (x) {", "if", true}, 425 - {"else if (y) {", "if", true}, 426 - {"else {", "if", true}, 427 - {"for (const x of items) {", "for", true}, 428 - {"while (true) {", "while", true}, 429 - {"do {", "do", true}, 430 - {"switch (x) {", "switch", true}, 431 - {"try {", "try", true}, 432 - {"interface Foo {", "interface", true}, 433 - {"enum Direction {", "enum", true}, 434 - {"namespace Foo {", "namespace", true}, 435 - {"const x = 1;", "const", false}, 436 - {"let x = 1;", "let", false}, 437 - {"var x = 1;", "var", false}, 438 - {"import { foo } from 'bar';", "import", false}, 439 - {"type Foo = string;", "type", false}, 440 - {"return x;", "return", false}, 441 - {"return;", "return", false}, 442 - {"throw new Error();", "throw", false}, 443 - {"await fetch(url);", "await", false}, 444 - {"yield value;", "yield", false}, 445 - {"export const x = 1;", "const", false}, 446 - {"export default class Foo {", "class", true}, 447 - {"declare const x: number;", "const", false}, 448 - {"declare function foo(): void;", "function", true}, 449 - {"foo();", "", false}, 450 - {"x = 1;", "", false}, 451 - {"", "", false}, 419 + {"function foo() {", "function", true, false}, 420 + {"async function foo() {", "function", true, false}, 421 + {"export function foo() {", "function", true, false}, 422 + {"export default function() {", "function", true, false}, 423 + {"class Foo {", "class", true, false}, 424 + {"export class Foo {", "class", true, false}, 425 + {"if (x) {", "if", true, false}, 426 + {"else if (y) {", "if", true, true}, 427 + {"else {", "if", true, true}, 428 + {"for (const x of items) {", "for", true, false}, 429 + {"while (true) {", "while", true, false}, 430 + {"do {", "do", true, false}, 431 + {"switch (x) {", "switch", true, false}, 432 + {"try {", "try", true, false}, 433 + {"catch (e) {", "try", true, true}, 434 + {"finally {", "try", true, true}, 435 + {"interface Foo {", "interface", true, false}, 436 + {"enum Direction {", "enum", true, false}, 437 + {"namespace Foo {", "namespace", true, false}, 438 + {"const x = 1;", "const", false, false}, 439 + {"let x = 1;", "let", false, false}, 440 + {"var x = 1;", "var", false, false}, 441 + {"import { foo } from 'bar';", "import", false, false}, 442 + {"type Foo = string;", "type", false, false}, 443 + {"return x;", "return", false, false}, 444 + {"return;", "return", false, false}, 445 + {"throw new Error();", "throw", false, false}, 446 + {"await fetch(url);", "await", false, false}, 447 + {"yield value;", "yield", false, false}, 448 + {"export const x = 1;", "const", false, false}, 449 + {"export default class Foo {", "class", true, false}, 450 + {"declare const x: number;", "const", false, false}, 451 + {"declare function foo(): void;", "function", true, false}, 452 + {"foo();", "", false, false}, 453 + {"x = 1;", "", false, false}, 454 + {"", "", false, false}, 452 455 } 453 456 454 457 for _, testCase := range cases { 455 - statementType, isScoped := classifyEcmaScriptStatement(testCase.input) 458 + statementType, isScoped, isContinuation := classifyEcmaScriptStatement(testCase.input) 456 459 457 - if statementType != testCase.expectedType || isScoped != testCase.expectedScope { 458 - t.Errorf("classifyEcmaScriptStatement(%q) = (%q, %v), want (%q, %v)", 459 - testCase.input, statementType, isScoped, testCase.expectedType, testCase.expectedScope) 460 + if statementType != testCase.expectedType || isScoped != testCase.expectedScope || isContinuation != testCase.expectedContinuation { 461 + t.Errorf("classifyEcmaScriptStatement(%q) = (%q, %v, %v), want (%q, %v, %v)", 462 + testCase.input, statementType, isScoped, isContinuation, testCase.expectedType, testCase.expectedScope, testCase.expectedContinuation) 460 463 } 461 464 } 462 465 }
+1 -1
engine/engine.go
··· 49 49 currentIsTopLevel := event.HasASTInfo && event.IsTopLevel 50 50 currentIsScoped := event.HasASTInfo && event.IsScoped 51 51 52 - if hasWrittenContent && !previousWasOpenBrace && !event.IsClosingBrace && !event.IsCaseLabel { 52 + if hasWrittenContent && !previousWasOpenBrace && !event.IsClosingBrace && !event.IsCaseLabel && !event.IsContinuation { 53 53 if currentIsTopLevel && previousWasTopLevel && currentStatementType != previousStatementType { 54 54 if !(e.CommentMode == CommentsFollow && previousWasComment) { 55 55 needsBlankLine = true
+1
engine/event.go
··· 13 13 IsClosingBrace bool 14 14 IsOpeningBrace bool 15 15 IsCaseLabel bool 16 + IsContinuation bool 16 17 IsCommentOnly bool 17 18 IsBlank bool 18 19 InRawString bool