Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/blink_parity_mautic.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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=0.15
MAX_DIFF_PERCENT=0.1
total=0
differ=0
differing_files=""
Expand Down
23 changes: 20 additions & 3 deletions blink/internal/fixer/rules/gen3_func.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,23 @@ func fnEnsureSingleSpaceBefore(s *tokens.Stream, i int) bool {

// fnGlueAfter removes a single-line whitespace token immediately after i, gluing
// the token at i to the following significant token. A newline is left intact.
// fnIsArrowFn reports whether the "fn" keyword at i opens an arrow function - its
// parameter "(" follows directly or after a by-reference "&".
func fnIsArrowFn(s *tokens.Stream, i int) bool {
n := nextSignificantIndex(s, i)
if n < 0 || s.At(n).Kind != token.Punct {
return false
}
if s.At(n).Value == "(" {
return true
}
if s.At(n).Value == "&" {
nn := nextSignificantIndex(s, n)
return nn >= 0 && s.At(nn).Kind == token.Punct && s.At(nn).Value == "("
}
return false
}

func fnGlueAfter(s *tokens.Stream, i int) bool {
if i+1 < s.Len() && s.At(i+1).Kind == token.Whitespace && !hasNewline(s.At(i+1).Value) {
s.RemoveAt(i + 1)
Expand Down Expand Up @@ -134,9 +151,9 @@ func (f FunctionDeclaration) Fix(s *tokens.Stream) bool {
changed = true
}
case "fn":
// arrow function: spacing between "fn" and "(" (closure_fn_spacing)
if n := nextSignificantIndex(s, i); n >= 0 &&
s.At(n).Kind == token.Punct && s.At(n).Value == "(" {
// arrow function: spacing after "fn" (closure_fn_spacing). The "("
// follows directly, or after a by-reference "&" ("fn &() => ...").
if fnIsArrowFn(s, i) {
if f.closureFnSpacingNone {
if fnGlueAfter(s, i) {
changed = true
Expand Down
12 changes: 12 additions & 0 deletions blink/internal/fixer/rules/gen3_func_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@ func TestFunctionDeclarationClosureFnSpacing(t *testing.T) {
if want := "<?php $f = fn() => 1;"; !changed || got != want {
t.Fatalf("closure_fn_spacing=none: changed=%v got=%q want=%q", changed, got, want)
}

// a by-reference arrow function ("fn &() => ...") also glues the space after fn
got, changed = apply(t, cfg, "<?php $f = fn &() => $x;")
if want := "<?php $f = fn&() => $x;"; !changed || got != want {
t.Fatalf("by-ref fn: changed=%v got=%q want=%q", changed, got, want)
}

// closure_fn_spacing=one keeps a single space for the by-reference form
one := FunctionDeclaration{}.WithConfig(map[string]any{"closure_fn_spacing": "one"})
if _, changed := apply(t, one, "<?php $f = fn &() => $x;"); changed {
t.Fatal("closure_fn_spacing=one must keep the single space in fn &()")
}
}

func TestFunctionDeclarationTrailingCommaSingleLine(t *testing.T) {
Expand Down
Loading