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
8 changes: 4 additions & 4 deletions packages/go/driver/internal/app/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,22 +51,22 @@ func (a App) runPipeline(ctx context.Context, paths []string, opts formatOptions
pipeline := orchestrator.Pipeline{
Tools: orchestrator.Tools{
TS: func(ctx context.Context, scopes []string, output io.Writer) error {
support, err := tsruntime.Resolve(a.version)
assets, err := tsruntime.Resolve(a.version)

if err != nil {
return err
}

return support.RunPipeline(ctx, tsruntime.RunOptions{Scopes: scopes, Selection: selection, Stdout: output, Stderr: output})
return tsruntime.NewInvoker(assets).RunPipeline(ctx, tsruntime.Request{Scopes: scopes, Selection: selection, Stdout: output, Stderr: output})
},
Lint: func(ctx context.Context, scopes []string, output io.Writer) error {
support, err := tsruntime.Resolve(a.version)
assets, err := tsruntime.Resolve(a.version)

if err != nil {
return err
}

return support.RunLint(ctx, tsruntime.RunOptions{Scopes: scopes, Selection: selection, Fix: true, Stdout: output, Stderr: output})
return tsruntime.NewInvoker(assets).RunLint(ctx, tsruntime.Request{Scopes: scopes, Selection: selection, Fix: true, Stdout: output, Stderr: output})
},
Go: func(ctx context.Context, args []string, output io.Writer) int {
return cli.
Expand Down
8 changes: 4 additions & 4 deletions packages/go/driver/internal/app/ts.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@ import (
)

func (a App) runTS(ctx context.Context, paths []string) int {
support, err := tsruntime.Resolve(a.version)
assets, err := tsruntime.Resolve(a.version)

if err != nil {
return a.reportError(err)
}

return a.reportError(support.RunPipeline(ctx, tsruntime.RunOptions{Scopes: paths, Stdout: a.stdout, Stderr: a.stderr}))
return a.reportError(tsruntime.NewInvoker(assets).RunPipeline(ctx, tsruntime.Request{Scopes: paths, Stdout: a.stdout, Stderr: a.stderr}))
}

func (a App) runLint(ctx context.Context, paths []string) int {
support, err := tsruntime.Resolve(a.version)
assets, err := tsruntime.Resolve(a.version)

if err != nil {
return a.reportError(err)
}

return a.reportError(support.RunLint(ctx, tsruntime.RunOptions{Scopes: paths, Stdout: a.stdout, Stderr: a.stderr}))
return a.reportError(tsruntime.NewInvoker(assets).RunLint(ctx, tsruntime.Request{Scopes: paths, Stdout: a.stdout, Stderr: a.stderr}))
}
46 changes: 17 additions & 29 deletions packages/go/driver/internal/orchestrator/summarize.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,18 @@ import (
"fmt"
"regexp"
"strings"

"go.ollin.sh/fmtkit/driver/internal/sidecarproto"
)

// The summarizers distill a step's captured output into the aligned detail
// lines shown under its section header.
// lines shown under its section header. Lines the TS sidecar emits are parsed
// by sidecarproto; the Go-report scraping below stays here (G6 retires it).

var (
lintResultPattern = regexp.MustCompile(`Found [0-9]+ warning|[0-9]+ error`)
goFileSummaryPattern = regexp.MustCompile(`^ (Formatted|Checked) [0-9]+ file\(s\)\.$|^ No Go files found\.$`)
goVetSummaryPattern = regexp.MustCompile(`^ go vet \./\.\.\. passed\.$|^ Skipped automatic go vet `)
sourcesMissingPrefix = "[sources] path not found, skipping:"
blankLinesPrefix = "[blank-lines] processed "
fluentChainsPrefix = "[fluent-chains] processed "
oxfmtFinishedPrefix = "Finished in "
validateSyntaxPrefix = "[validate-syntax] checked "
lintNothingToLintLine = "[lint] no TS/Vue files to lint."
goResultPrefix = " Result: "
)
Expand All @@ -39,55 +37,45 @@ func lastWithPrefix(logLines []string, prefix string) string {
}

func summarizeTSFormat(log string, l *logger) {
logLines := lines(log)
summary := sidecarproto.ParsePipelineSummary(log)
missing := 0

for _, line := range logLines {
for _, line := range lines(log) {
if strings.HasPrefix(line, sourcesMissingPrefix) {
missing++
}
}

if line := lastWithPrefix(logLines, blankLinesPrefix); line != "" {
l.detail("blank-lines", strings.TrimPrefix(line, "[blank-lines] "))
if summary.BlankLines != "" {
l.detail("blank-lines", summary.BlankLines)
}

if missing > 0 {
l.detail("skipped", fmt.Sprintf("%d missing tracked file(s)", missing))
}

if line := lastWithPrefix(logLines, oxfmtFinishedPrefix); line != "" {
l.detail("oxfmt", line)
if summary.Oxfmt != "" {
l.detail("oxfmt", summary.Oxfmt)
}

if line := lastWithPrefix(logLines, fluentChainsPrefix); line != "" {
l.detail("fluent", strings.TrimPrefix(line, "[fluent-chains] "))
if summary.FluentChains != "" {
l.detail("fluent", summary.FluentChains)
}

if line := lastWithPrefix(logLines, validateSyntaxPrefix); line != "" {
l.detail("validated", strings.TrimPrefix(line, "[validate-syntax] "))
if summary.ValidateSyntax != "" {
l.detail("validated", summary.ValidateSyntax)
}
}

func summarizeTSLint(log string, l *logger) {
logLines := lines(log)

if lastWithPrefix(logLines, lintNothingToLintLine) != "" {
if lastWithPrefix(lines(log), lintNothingToLintLine) != "" {
l.detail("oxlint", strings.TrimPrefix(lintNothingToLintLine, "[lint] "))

return
}

var match string

for _, line := range logLines {
if lintResultPattern.MatchString(line) {
match = line
}
}

if match != "" {
l.detail("oxlint", match)
if result := sidecarproto.ParseLintSummary(log).Result; result != "" {
l.detail("oxlint", result)

return
}
Expand Down
83 changes: 83 additions & 0 deletions packages/go/driver/internal/sidecarproto/command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package sidecarproto

// The command types below build the exact argument vectors each sidecar mode
// expects. The bin resolution (which executable to spawn) is the caller's
// concern; these types own only the argv the sidecar itself parses.

// PipelineCommand describes a full-pipeline invocation. OxfmtBin is the
// already-resolved oxfmt executable the sidecar shells out to, and OxfmtConfig
// is the resolved config path, or "" to let oxfmt auto-discover.
type PipelineCommand struct {
OxfmtBin string
OxfmtConfig string
FormatFiles []string
SyntaxFiles []string
}

// OxlintCommand describes an oxlint invocation. ViaSidecar is set when the
// sidecar dispatches oxlint (and so must be told the mode); a direct OXLINT_BIN
// override clears it. Config is the resolved config path, or "" for
// auto-discovery.
type OxlintCommand struct {
ViaSidecar bool
Fix bool
Config string
Files []string
}

// MigrateCommand describes an `oxfmt --migrate=prettier` invocation. ViaSidecar
// is set when the sidecar dispatches oxfmt; a direct OXFMT_BIN override clears
// it.
type MigrateCommand struct {
ViaSidecar bool
}

// Argv returns the pipeline mode's argument vector.
func (c PipelineCommand) Argv() []string {
args := []string{ModePipeline}

args = append(args, "--oxfmt-bin", c.OxfmtBin)

if c.OxfmtConfig != "" {
args = append(args, "--oxfmt-config", c.OxfmtConfig)
}

args = append(args, "--format-files")
args = append(args, c.FormatFiles...)
args = append(args, "--syntax-files")
args = append(args, c.SyntaxFiles...)

return args
}

// Argv returns oxlint's argument vector.
func (c OxlintCommand) Argv() []string {
var args []string

if c.ViaSidecar {
args = append(args, ModeOxlint)
}

if c.Fix {
args = append(args, "--fix")
}

if c.Config != "" {
args = append(args, "--config", c.Config)
}

args = append(args, c.Files...)

return args
}

// Argv returns the migration argument vector.
func (c MigrateCommand) Argv() (args []string) {
if c.ViaSidecar {
args = append(args, ModeOxfmt)
}

args = append(args, "--migrate=prettier")

return args
}
135 changes: 135 additions & 0 deletions packages/go/driver/internal/sidecarproto/command_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package sidecarproto

import (
"reflect"
"testing"
)

func TestPipelineCommandArgv(t *testing.T) {
cmd := PipelineCommand{
OxfmtBin: "/tools/fmtkit-ts-sidecar",
OxfmtConfig: "/cfg/.oxfmtrc.json",
FormatFiles: []string{"/work/app.ts", "/work/types.ts"},
SyntaxFiles: []string{"/work/app.ts", "/work/decl.d.ts", "/work/types.ts"},
}

want := []string{
"pipeline",
"--oxfmt-bin", "/tools/fmtkit-ts-sidecar",
"--oxfmt-config", "/cfg/.oxfmtrc.json",
"--format-files",
"/work/app.ts", "/work/types.ts",
"--syntax-files",
"/work/app.ts", "/work/decl.d.ts", "/work/types.ts",
}

if got := cmd.Argv(); !reflect.DeepEqual(got, want) {
t.Fatalf("Argv() = %q, want %q", got, want)
}
}

func TestPipelineCommandArgvOmitsEmptyConfig(t *testing.T) {
cmd := PipelineCommand{
OxfmtBin: "/tools/fmtkit-ts-sidecar",
FormatFiles: []string{"/work/app.ts"},
SyntaxFiles: []string{"/work/app.ts"},
}

want := []string{
"pipeline",
"--oxfmt-bin", "/tools/fmtkit-ts-sidecar",
"--format-files",
"/work/app.ts",
"--syntax-files",
"/work/app.ts",
}

if got := cmd.Argv(); !reflect.DeepEqual(got, want) {
t.Fatalf("Argv() = %q, want %q", got, want)
}
}

func TestPipelineCommandArgvAlwaysCarriesFileSentinels(t *testing.T) {
// Even with no files, the --format-files/--syntax-files markers are present
// so the sidecar's parser sees empty lists rather than a missing section.
cmd := PipelineCommand{OxfmtBin: "sidecar"}

want := []string{
"pipeline",
"--oxfmt-bin", "sidecar",
"--format-files",
"--syntax-files",
}

if got := cmd.Argv(); !reflect.DeepEqual(got, want) {
t.Fatalf("Argv() = %q, want %q", got, want)
}
}

func TestOxlintCommandArgvViaSidecar(t *testing.T) {
cmd := OxlintCommand{
ViaSidecar: true,
Config: "/cfg/.oxlintrc.json",
Files: []string{"/work/app.ts"},
}

want := []string{
"oxlint",
"--config", "/cfg/.oxlintrc.json",
"/work/app.ts",
}

if got := cmd.Argv(); !reflect.DeepEqual(got, want) {
t.Fatalf("Argv() = %q, want %q", got, want)
}
}

func TestOxlintCommandArgvWithFix(t *testing.T) {
cmd := OxlintCommand{
ViaSidecar: true,
Fix: true,
Config: "/cfg/.oxlintrc.json",
Files: []string{"/work/app.ts"},
}

want := []string{
"oxlint",
"--fix",
"--config", "/cfg/.oxlintrc.json",
"/work/app.ts",
}

if got := cmd.Argv(); !reflect.DeepEqual(got, want) {
t.Fatalf("Argv() = %q, want %q", got, want)
}
}

func TestOxlintCommandArgvDirectBinOmitsMode(t *testing.T) {
// A direct OXLINT_BIN override runs oxlint without the sidecar's mode word.
cmd := OxlintCommand{
ViaSidecar: false,
Files: []string{"/work/app.ts"},
}

want := []string{"/work/app.ts"}

if got := cmd.Argv(); !reflect.DeepEqual(got, want) {
t.Fatalf("Argv() = %q, want %q", got, want)
}
}

func TestMigrateCommandArgvViaSidecar(t *testing.T) {
want := []string{"oxfmt", "--migrate=prettier"}

if got := (MigrateCommand{ViaSidecar: true}).Argv(); !reflect.DeepEqual(got, want) {
t.Fatalf("Argv() = %q, want %q", got, want)
}
}

func TestMigrateCommandArgvDirectBin(t *testing.T) {
want := []string{"--migrate=prettier"}

if got := (MigrateCommand{ViaSidecar: false}).Argv(); !reflect.DeepEqual(got, want) {
t.Fatalf("Argv() = %q, want %q", got, want)
}
}
Loading
Loading