Skip to content

Commit 2b7aa1d

Browse files
akoclaude
andcommitted
fix: mxcli check --format json/sarif now outputs structured results
Status messages ("Checking syntax:", "✓ Syntax OK", "Check passed!") were always printed as plain text regardless of --format, making --format json/sarif unusable for machine consumption. Parse errors were also plain text. Now: - json/sarif format suppresses all progress text - Parse errors are emitted as MDL-SYNTAX violations in the chosen format - A clean pass emits an empty violations envelope ({"violations":null,...}) - Text format is unchanged Fixes #134 (partial — check command; lint already worked) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 88f3648 commit 2b7aa1d

1 file changed

Lines changed: 49 additions & 22 deletions

File tree

cmd/mxcli/cmd_check.go

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ Examples:
4646
projectPath, _ := cmd.Flags().GetString("project")
4747
checkRefs, _ := cmd.Flags().GetBool("references")
4848
format := resolveFormat(cmd, "text")
49+
isStructured := format != "" && format != "text"
50+
51+
outputFormat := linter.OutputFormat(format)
52+
formatter := linter.GetFormatter(outputFormat, !isStructured)
4953

5054
// Read the file
5155
content, err := os.ReadFile(filePath)
@@ -55,24 +59,40 @@ Examples:
5559
}
5660

5761
// Parse the script
58-
fmt.Printf("Checking syntax: %s\n", filePath)
62+
if !isStructured {
63+
fmt.Printf("Checking syntax: %s\n", filePath)
64+
}
5965
prog, errs := visitor.Build(string(content))
6066
if len(errs) > 0 {
61-
fmt.Fprintf(os.Stderr, "Syntax errors found:\n")
62-
for _, err := range errs {
63-
fmt.Fprintf(os.Stderr, " - %v\n", err)
64-
}
65-
// Hint: if script contains IMPORT/QUERY with single $ but not $$, suggest dollar-quoting
66-
src := string(content)
67-
if (strings.Contains(src, "IMPORT") || strings.Contains(src, "import")) &&
68-
(strings.Contains(src, "QUERY") || strings.Contains(src, "query")) &&
69-
strings.Contains(src, "$") && !strings.Contains(src, "$$") {
70-
fmt.Fprintf(os.Stderr, "\nHint: SQL queries in IMPORT statements should use dollar-quoting ($$...$$) instead of single quotes.\n")
71-
fmt.Fprintf(os.Stderr, " Example: IMPORT FROM alias QUERY $$SELECT * FROM table$$ INTO Module.Entity MAP (...)\n")
67+
if isStructured {
68+
var parseViolations []linter.Violation
69+
for _, parseErr := range errs {
70+
parseViolations = append(parseViolations, linter.Violation{
71+
RuleID: "MDL-SYNTAX",
72+
Severity: linter.SeverityError,
73+
Message: parseErr.Error(),
74+
})
75+
}
76+
formatter.Format(parseViolations, os.Stderr)
77+
} else {
78+
fmt.Fprintf(os.Stderr, "Syntax errors found:\n")
79+
for _, err := range errs {
80+
fmt.Fprintf(os.Stderr, " - %v\n", err)
81+
}
82+
// Hint: if script contains IMPORT/QUERY with single $ but not $$, suggest dollar-quoting
83+
src := string(content)
84+
if (strings.Contains(src, "IMPORT") || strings.Contains(src, "import")) &&
85+
(strings.Contains(src, "QUERY") || strings.Contains(src, "query")) &&
86+
strings.Contains(src, "$") && !strings.Contains(src, "$$") {
87+
fmt.Fprintf(os.Stderr, "\nHint: SQL queries in IMPORT statements should use dollar-quoting ($$...$$) instead of single quotes.\n")
88+
fmt.Fprintf(os.Stderr, " Example: IMPORT FROM alias QUERY $$SELECT * FROM table$$ INTO Module.Entity MAP (...)\n")
89+
}
7290
}
7391
os.Exit(1)
7492
}
75-
fmt.Printf("✓ Syntax OK (%d statements)\n", len(prog.Statements))
93+
if !isStructured {
94+
fmt.Printf("✓ Syntax OK (%d statements)\n", len(prog.Statements))
95+
}
7696

7797
// Validate statements (doesn't require project connection)
7898
var violations []linter.Violation
@@ -98,14 +118,15 @@ Examples:
98118
}
99119
}
100120

101-
if len(violations) > 0 {
102-
// Use structured output
103-
outputFormat := linter.OutputFormat(format)
104-
formatter := linter.GetFormatter(outputFormat, format == "" || format == "text")
121+
if isStructured {
122+
// Always emit structured output (even when clean)
123+
formatter.Format(violations, os.Stderr)
124+
} else if len(violations) > 0 {
105125
fmt.Fprintln(os.Stderr)
106126
formatter.Format(violations, os.Stderr)
127+
}
107128

108-
// Exit with error if there are any error-severity violations
129+
if len(violations) > 0 {
109130
summary := linter.Summarize(violations)
110131
if summary.Errors > 0 {
111132
os.Exit(1)
@@ -119,8 +140,10 @@ Examples:
119140
os.Exit(1)
120141
}
121142

122-
fmt.Printf("\nValidating references against: %s\n", projectPath)
123-
fmt.Printf("(Note: References to objects created within the script are skipped)\n")
143+
if !isStructured {
144+
fmt.Printf("\nValidating references against: %s\n", projectPath)
145+
fmt.Printf("(Note: References to objects created within the script are skipped)\n")
146+
}
124147
exec, logger := newLoggedExecutor("check")
125148
defer logger.Close()
126149
defer exec.Close()
@@ -144,9 +167,13 @@ Examples:
144167
fmt.Fprintf(os.Stderr, "\n✗ %d reference error(s) found\n", len(validationErrors))
145168
os.Exit(1)
146169
}
147-
fmt.Printf("✓ All references valid\n")
170+
if !isStructured {
171+
fmt.Printf("✓ All references valid\n")
172+
}
148173
}
149174

150-
fmt.Println("\nCheck passed!")
175+
if !isStructured {
176+
fmt.Println("\nCheck passed!")
177+
}
151178
},
152179
}

0 commit comments

Comments
 (0)