lint/pkg/php/refactor.go
Snider af5c792da8 feat(lint): add pkg/detect + pkg/php — project detection and PHP QA toolchain
Add project type detection (pkg/detect) and complete PHP quality assurance
package (pkg/php) with formatter, analyser, audit, security, refactor,
mutation testing, test runner, pipeline stages, and QA runner that builds
process.RunSpec for orchestrated execution.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 13:13:30 +00:00

104 lines
2.1 KiB
Go

package php
import (
"context"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
)
// RectorOptions configures Rector code refactoring.
type RectorOptions struct {
Dir string
Fix bool // Apply changes (default is dry-run)
Diff bool // Show detailed diff
ClearCache bool // Clear cache before running
Output io.Writer
}
// DetectRector checks if Rector is available in the project.
func DetectRector(dir string) bool {
// Check for rector.php config
rectorConfig := filepath.Join(dir, "rector.php")
if fileExists(rectorConfig) {
return true
}
// Check for vendor binary
rectorBin := filepath.Join(dir, "vendor", "bin", "rector")
if fileExists(rectorBin) {
return true
}
return false
}
// RunRector runs Rector for automated code refactoring.
func RunRector(ctx context.Context, opts RectorOptions) error {
if opts.Dir == "" {
cwd, err := os.Getwd()
if err != nil {
return fmt.Errorf("get working directory: %w", err)
}
opts.Dir = cwd
}
if opts.Output == nil {
opts.Output = os.Stdout
}
// Build command
vendorBin := filepath.Join(opts.Dir, "vendor", "bin", "rector")
cmdName := "rector"
if fileExists(vendorBin) {
cmdName = vendorBin
}
args := []string{"process"}
if !opts.Fix {
args = append(args, "--dry-run")
}
if opts.Diff {
args = append(args, "--output-format", "diff")
}
if opts.ClearCache {
args = append(args, "--clear-cache")
}
cmd := exec.CommandContext(ctx, cmdName, args...)
cmd.Dir = opts.Dir
cmd.Stdout = opts.Output
cmd.Stderr = opts.Output
return cmd.Run()
}
// buildRectorCommand builds the command for running Rector (exported for testing).
func buildRectorCommand(opts RectorOptions) (string, []string) {
vendorBin := filepath.Join(opts.Dir, "vendor", "bin", "rector")
cmdName := "rector"
if fileExists(vendorBin) {
cmdName = vendorBin
}
args := []string{"process"}
if !opts.Fix {
args = append(args, "--dry-run")
}
if opts.Diff {
args = append(args, "--output-format", "diff")
}
if opts.ClearCache {
args = append(args, "--clear-cache")
}
return cmdName, args
}