@@ -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 , "\n Hint: 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 , "\n Hint: 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 ("\n Validating 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 ("\n Validating 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 ()
@@ -137,16 +160,32 @@ Examples:
137160 // Validate the program (considers objects defined within the script)
138161 validationErrors := exec .ValidateProgram (prog )
139162 if len (validationErrors ) > 0 {
140- fmt .Fprintf (os .Stderr , "Reference errors:\n " )
141- for _ , err := range validationErrors {
142- fmt .Fprintf (os .Stderr , " %v\n " , err )
163+ if isStructured {
164+ var refViolations []linter.Violation
165+ for _ , err := range validationErrors {
166+ refViolations = append (refViolations , linter.Violation {
167+ RuleID : "MDL-REF" ,
168+ Severity : linter .SeverityError ,
169+ Message : err .Error (),
170+ })
171+ }
172+ formatter .Format (refViolations , os .Stderr )
173+ } else {
174+ fmt .Fprintf (os .Stderr , "Reference errors:\n " )
175+ for _ , err := range validationErrors {
176+ fmt .Fprintf (os .Stderr , " %v\n " , err )
177+ }
178+ fmt .Fprintf (os .Stderr , "\n ✗ %d reference error(s) found\n " , len (validationErrors ))
143179 }
144- fmt .Fprintf (os .Stderr , "\n ✗ %d reference error(s) found\n " , len (validationErrors ))
145180 os .Exit (1 )
146181 }
147- fmt .Printf ("✓ All references valid\n " )
182+ if ! isStructured {
183+ fmt .Printf ("✓ All references valid\n " )
184+ }
148185 }
149186
150- fmt .Println ("\n Check passed!" )
187+ if ! isStructured {
188+ fmt .Println ("\n Check passed!" )
189+ }
151190 },
152191}
0 commit comments