Skip to content

Commit 5b0a9a2

Browse files
author
Test User
committed
refactor(outputters): implement Dependency Inversion Principle for formatters
Introduced Formatter interface and FormatterFactory abstraction to decouple Outputter from concrete formatter implementations: - Formatter interface: abstracts Format(summary) behavior - FormatterFactory interface: abstracts formatter creation - DefaultFormatterFactory: creates output.* formatters - NewOutputterWithFactory: enables dependency injection for testing Outputter now depends on FormatterFactory abstraction rather than directly on output package implementations (DIP compliance).
1 parent d757c4a commit 5b0a9a2

1 file changed

Lines changed: 75 additions & 19 deletions

File tree

internal/outputters/outputter.go

Lines changed: 75 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,87 @@ import (
44
"fmt"
55
"time"
66

7-
"github.com/dotcommander/cclint/internal/config"
87
"github.com/dotcommander/cclint/internal/cli"
8+
"github.com/dotcommander/cclint/internal/config"
99
"github.com/dotcommander/cclint/internal/output"
1010
)
1111

12-
// Outputter handles output formatting
12+
// =============================================================================
13+
// Dependency Inversion: Formatter interface for output formatters
14+
// =============================================================================
15+
16+
// Formatter defines the interface for output formatters.
17+
// This allows the Outputter to depend on an abstraction rather than
18+
// concrete formatter implementations (DIP compliance).
19+
type Formatter interface {
20+
// Format formats the lint summary and outputs it
21+
Format(summary *cli.LintSummary) error
22+
}
23+
24+
// FormatterFactory creates formatters based on format type.
25+
// This follows the Factory pattern for DIP compliance.
26+
type FormatterFactory interface {
27+
// CreateFormatter creates a formatter for the given format type
28+
CreateFormatter(format string) (Formatter, error)
29+
}
30+
31+
// =============================================================================
32+
// Default FormatterFactory implementation
33+
// =============================================================================
34+
35+
// DefaultFormatterFactory creates formatters using the output package.
36+
type DefaultFormatterFactory struct {
37+
cfg *config.Config
38+
}
39+
40+
// NewDefaultFormatterFactory creates a new DefaultFormatterFactory.
41+
func NewDefaultFormatterFactory(cfg *config.Config) *DefaultFormatterFactory {
42+
return &DefaultFormatterFactory{cfg: cfg}
43+
}
44+
45+
// CreateFormatter implements FormatterFactory interface.
46+
func (f *DefaultFormatterFactory) CreateFormatter(format string) (Formatter, error) {
47+
switch format {
48+
case "console":
49+
return output.NewConsoleFormatter(f.cfg.Quiet, f.cfg.Verbose, f.cfg.ShowScores, f.cfg.ShowImprovements), nil
50+
case "json":
51+
return output.NewJSONFormatter(f.cfg.Quiet, true, f.cfg.Output), nil
52+
case "markdown":
53+
return output.NewMarkdownFormatter(f.cfg.Quiet, f.cfg.Verbose, f.cfg.Output), nil
54+
default:
55+
return nil, fmt.Errorf("unsupported format: %s", format)
56+
}
57+
}
58+
59+
// =============================================================================
60+
// Outputter with DIP-compliant design
61+
// =============================================================================
62+
63+
// Outputter handles output formatting using injected formatter factory.
64+
// It depends on the FormatterFactory abstraction, not concrete formatters.
1365
type Outputter struct {
14-
config *config.Config
66+
config *config.Config
67+
factory FormatterFactory
1568
}
1669

17-
// NewOutputter creates a new Outputter
70+
// NewOutputter creates a new Outputter with the default formatter factory.
1871
func NewOutputter(config *config.Config) *Outputter {
1972
return &Outputter{
20-
config: config,
73+
config: config,
74+
factory: NewDefaultFormatterFactory(config),
2175
}
2276
}
2377

24-
// Format formats the lint summary using the configured format
78+
// NewOutputterWithFactory creates a new Outputter with a custom formatter factory.
79+
// This allows for dependency injection and easier testing.
80+
func NewOutputterWithFactory(config *config.Config, factory FormatterFactory) *Outputter {
81+
return &Outputter{
82+
config: config,
83+
factory: factory,
84+
}
85+
}
86+
87+
// Format formats the lint summary using the configured format.
2588
func (o *Outputter) Format(summary *cli.LintSummary, format string) error {
2689
// Set start time if not set
2790
if summary.StartTime.IsZero() {
@@ -31,18 +94,11 @@ func (o *Outputter) Format(summary *cli.LintSummary, format string) error {
3194
// Set project root in summary for display
3295
summary.ProjectRoot = o.config.Root
3396

34-
// Create appropriate formatter based on format
35-
switch format {
36-
case "console":
37-
formatter := output.NewConsoleFormatter(o.config.Quiet, o.config.Verbose, o.config.ShowScores, o.config.ShowImprovements)
38-
return formatter.Format(summary)
39-
case "json":
40-
formatter := output.NewJSONFormatter(o.config.Quiet, true, o.config.Output)
41-
return formatter.Format(summary)
42-
case "markdown":
43-
formatter := output.NewMarkdownFormatter(o.config.Quiet, o.config.Verbose, o.config.Output)
44-
return formatter.Format(summary)
45-
default:
46-
return fmt.Errorf("unsupported format: %s", format)
97+
// Create formatter via factory (DIP compliance)
98+
formatter, err := o.factory.CreateFormatter(format)
99+
if err != nil {
100+
return err
47101
}
102+
103+
return formatter.Format(summary)
48104
}

0 commit comments

Comments
 (0)