From df2d13c7277e7f6455784c82b48f3b9da0985f64 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 5 Oct 2026 22:29:02 +0200 Subject: [PATCH] Blink parity: closure/method empty-body, array-named method, docblock-removal indent; gate laravel to 4% Three blink fixes that close the largest laravel/framework parity gaps: - SingleLineEmptyBody now collapses empty closure bodies too, not just class and named-function bodies (function () {} stays single-line). - ArraySyntax no longer rewrites a method named array() to [] - a name after function is skipped, like method/constant uses. - NoEmptyPhpdoc removes an emptied docblock's trailing whitespace outright when the preceding whitespace already carries the newline and indent, instead of leaving a dangling indent that doubled the next line's indentation. laravel/framework parity 92.80% -> 96.06% (diff 7.20% -> 3.94%); gate lowered from 7.3% to 4%. rector-src 1:1 gate stays at 0 diffs and mautic stays at 0.088%. --- .github/workflows/blink_parity_laravel.yaml | 2 +- blink/internal/fixer/rules/array_notation.go | 5 +++-- blink/internal/fixer/rules/percs.go | 6 +++--- blink/internal/fixer/rules/phpdoc_batch.go | 7 ++++++- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.github/workflows/blink_parity_laravel.yaml b/.github/workflows/blink_parity_laravel.yaml index 545844d6ad..94ef0679b1 100644 --- a/.github/workflows/blink_parity_laravel.yaml +++ b/.github/workflows/blink_parity_laravel.yaml @@ -95,7 +95,7 @@ jobs: - name: Compare the two trees run: | # ratchet gate: fail once the differing share crosses this; lower it as parity improves - MAX_DIFF_PERCENT=7.3 + MAX_DIFF_PERCENT=4 total=0 differ=0 differing_files="" diff --git a/blink/internal/fixer/rules/array_notation.go b/blink/internal/fixer/rules/array_notation.go index fcf22786bc..363cf39fce 100644 --- a/blink/internal/fixer/rules/array_notation.go +++ b/blink/internal/fixer/rules/array_notation.go @@ -10,7 +10,8 @@ import ( ) // convertLongArray rewrites a long "name(...)" construct to "[...]", where name -// is "array" or "list". Method/constant uses (after -> ?-> ::) are skipped. +// is "array" or "list". Method/constant uses (after -> ?-> ::) and a method +// declared with that name (after "function") are skipped. func convertLongArray(s *tokens.Stream, name string) bool { changed := false for i := 0; i < s.Len(); i++ { @@ -23,7 +24,7 @@ func convertLongArray(s *tokens.Stream, name string) bool { } if prev, ok := prevSignificant(s, i); ok { switch prev.Value { - case "->", "?->", "::": + case "->", "?->", "::", "function": continue } } diff --git a/blink/internal/fixer/rules/percs.go b/blink/internal/fixer/rules/percs.go index 9439f56014..9a6523e615 100644 --- a/blink/internal/fixer/rules/percs.go +++ b/blink/internal/fixer/rules/percs.go @@ -139,8 +139,8 @@ func isStaticRef(v string) bool { // PHP-CS-Fixer: https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/blob/master/src/Fixer/Basic/SingleLineEmptyBodyFixer.php // -// SingleLineEmptyBody collapses an empty class or function body to "{}" on the -// declaration line ("function f()\n{\n}" -> "function f() {}"). +// SingleLineEmptyBody collapses an empty class, function or closure body to "{}" +// on the declaration line ("function f()\n{\n}" -> "function f() {}"). type SingleLineEmptyBody struct{} func (SingleLineEmptyBody) Name() string { @@ -158,7 +158,7 @@ func (SingleLineEmptyBody) Fix(s *tokens.Stream) bool { continue } switch kind, _ := classifyBrace(s, i); kind { - case braceClassLike, braceFunctionDecl: + case braceClassLike, braceFunctionDecl, braceClosure: default: continue } diff --git a/blink/internal/fixer/rules/phpdoc_batch.go b/blink/internal/fixer/rules/phpdoc_batch.go index cefc17d546..b0780e5cc8 100644 --- a/blink/internal/fixer/rules/phpdoc_batch.go +++ b/blink/internal/fixer/rules/phpdoc_batch.go @@ -37,7 +37,12 @@ func (NoEmptyPhpdoc) Fix(s *tokens.Stream) bool { changed = true // Drop one newline of the following whitespace, like removing a blank line. if i < s.Len() && s.At(i).Kind == token.Whitespace && strings.HasPrefix(s.At(i).Value, "\n") { - if v := s.At(i).Value[1:]; v == "" { + // The preceding whitespace already carries the newline + indent for the + // next line, so remove the docblock's trailing whitespace outright; + // de-newlining it would leave a dangling indent that doubles up. + if i > 0 && s.At(i-1).Kind == token.Whitespace && hasNewline(s.At(i-1).Value) { + s.RemoveAt(i) + } else if v := s.At(i).Value[1:]; v == "" { s.RemoveAt(i) } else { s.SetValue(i, v)