diff --git a/pkg/lint/adapter.go b/pkg/lint/adapter.go index 589189f..276e281 100644 --- a/pkg/lint/adapter.go +++ b/pkg/lint/adapter.go @@ -80,6 +80,7 @@ func defaultAdapters() []Adapter { newCommandAdapter("yamllint", []string{"yamllint"}, []string{"yaml"}, "style", "", false, true, pathArgs("-f", "parsable"), parseTextDiagnostics), newCommandAdapter("jsonlint", []string{"jsonlint"}, []string{"json"}, "style", "", false, true, fileArgs(), parseTextDiagnostics), newCommandAdapter("markdownlint", []string{"markdownlint", "markdownlint-cli"}, []string{"markdown"}, "style", "", false, true, pathArgs("--json"), parseJSONDiagnostics), + newCommandAdapter("prettier", []string{"prettier"}, []string{"js"}, "style", "", false, true, pathArgs("--list-different"), parsePrettierDiagnostics), newCommandAdapter("gitleaks", []string{"gitleaks"}, []string{"*"}, "security", "lint.security", true, false, recursivePathArgs("detect", "--no-git", "--report-format", "json", "--source"), parseJSONDiagnostics), newCommandAdapter("trivy", []string{"trivy"}, []string{"*"}, "security", "lint.security", true, false, pathArgs("fs", "--format", "json"), parseJSONDiagnostics), newCommandAdapter("semgrep", []string{"semgrep"}, []string{"*"}, "security", "lint.security", true, false, pathArgs("--json"), parseJSONDiagnostics), @@ -598,6 +599,28 @@ func parseTextDiagnostics(tool string, category string, output string) []Finding return dedupeFindings(findings) } +func parsePrettierDiagnostics(tool string, category string, output string) []Finding { + var findings []Finding + + for line := range strings.SplitSeq(strings.TrimSpace(output), "\n") { + trimmed := strings.TrimSpace(line) + if trimmed == "" { + continue + } + + findings = append(findings, Finding{ + Tool: tool, + File: filepath.ToSlash(trimmed), + Severity: defaultSeverityForCategory(category), + Code: "prettier-format", + Message: "File is not formatted with Prettier", + Category: category, + }) + } + + return dedupeFindings(findings) +} + func parseTextDiagnosticLine(tool string, category string, line string) (Finding, bool) { segments := strings.Split(line, ":") if len(segments) < 3 { diff --git a/pkg/lint/service_test.go b/pkg/lint/service_test.go index 28476a6..19a5b76 100644 --- a/pkg/lint/service_test.go +++ b/pkg/lint/service_test.go @@ -90,6 +90,34 @@ func run2() { assert.False(t, report.Summary.Passed) } +func TestServiceRun_JS_PrettierFindings(t *testing.T) { + dir := t.TempDir() + require.NoError(t, os.WriteFile(filepath.Join(dir, "package.json"), []byte("{\n \"name\": \"example\"\n}\n"), 0o644)) + require.NoError(t, os.WriteFile(filepath.Join(dir, "index.js"), []byte("const value = 1;\n"), 0o644)) + + setupMockCmdExit(t, "prettier", "index.js\n", "", 1) + + svc := &Service{adapters: []Adapter{ + newCommandAdapter("prettier", []string{"prettier"}, []string{"js"}, "style", "", false, true, pathArgs("--list-different"), parsePrettierDiagnostics), + }} + report, err := svc.Run(context.Background(), RunInput{ + Path: dir, + FailOn: "warning", + }) + require.NoError(t, err) + + require.Len(t, report.Findings, 1) + require.Len(t, report.Tools, 1) + assert.Equal(t, "prettier", report.Findings[0].Tool) + assert.Equal(t, "index.js", report.Findings[0].File) + assert.Equal(t, "prettier-format", report.Findings[0].Code) + assert.Equal(t, "warning", report.Findings[0].Severity) + assert.False(t, report.Summary.Passed) + assert.Equal(t, "prettier", report.Tools[0].Name) + assert.Equal(t, "failed", report.Tools[0].Status) + assert.Equal(t, 1, report.Tools[0].Findings) +} + func runTestCommand(t *testing.T, dir string, name string, args ...string) { t.Helper()