Skip to content

Commit f87c86d

Browse files
committed
Merge branch 'issues-2'
2 parents cbdb26c + 155ca32 commit f87c86d

64 files changed

Lines changed: 574 additions & 372 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cmd/mxcli/cmd_check.go

Lines changed: 65 additions & 26 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()
@@ -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("\nCheck passed!")
187+
if !isStructured {
188+
fmt.Println("\nCheck passed!")
189+
}
151190
},
152191
}

mdl/executor/cmd_agenteditor_agents.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import (
1616
"github.com/mendixlabs/mxcli/sdk/agenteditor"
1717
)
1818

19-
// showAgentEditorAgents handles SHOW AGENTS [IN module].
20-
func showAgentEditorAgents(ctx *ExecContext, moduleName string) error {
19+
// listAgentEditorAgents handles SHOW AGENTS [IN module].
20+
func listAgentEditorAgents(ctx *ExecContext, moduleName string) error {
2121
if !ctx.Connected() {
2222
return mdlerrors.NewNotConnected()
2323
}

mdl/executor/cmd_agenteditor_kbs.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import (
1616
"github.com/mendixlabs/mxcli/sdk/agenteditor"
1717
)
1818

19-
// showAgentEditorKnowledgeBases handles SHOW KNOWLEDGE BASES [IN module].
20-
func showAgentEditorKnowledgeBases(ctx *ExecContext, moduleName string) error {
19+
// listAgentEditorKnowledgeBases handles SHOW KNOWLEDGE BASES [IN module].
20+
func listAgentEditorKnowledgeBases(ctx *ExecContext, moduleName string) error {
2121
if !ctx.Connected() {
2222
return mdlerrors.NewNotConnected()
2323
}

mdl/executor/cmd_agenteditor_mcpservices.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import (
1616
"github.com/mendixlabs/mxcli/sdk/agenteditor"
1717
)
1818

19-
// showAgentEditorConsumedMCPServices handles SHOW CONSUMED MCP SERVICES [IN module].
20-
func showAgentEditorConsumedMCPServices(ctx *ExecContext, moduleName string) error {
19+
// listAgentEditorConsumedMCPServices handles SHOW CONSUMED MCP SERVICES [IN module].
20+
func listAgentEditorConsumedMCPServices(ctx *ExecContext, moduleName string) error {
2121
if !ctx.Connected() {
2222
return mdlerrors.NewNotConnected()
2323
}

mdl/executor/cmd_agenteditor_mock_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ func TestShowAgentEditorModels_Mock(t *testing.T) {
307307
}
308308

309309
ctx, buf := newMockCtx(t, withBackend(mb), withHierarchy(h))
310-
assertNoError(t, showAgentEditorModels(ctx, ""))
310+
assertNoError(t, listAgentEditorModels(ctx, ""))
311311

312312
out := buf.String()
313313
assertContainsStr(t, out, "Qualified Name")
@@ -369,7 +369,7 @@ func TestShowAgentEditorAgents_Mock(t *testing.T) {
369369
}
370370

371371
ctx, buf := newMockCtx(t, withBackend(mb), withHierarchy(h))
372-
assertNoError(t, showAgentEditorAgents(ctx, ""))
372+
assertNoError(t, listAgentEditorAgents(ctx, ""))
373373

374374
out := buf.String()
375375
assertContainsStr(t, out, "Qualified Name")
@@ -429,7 +429,7 @@ func TestShowAgentEditorKnowledgeBases_Mock(t *testing.T) {
429429
}
430430

431431
ctx, buf := newMockCtx(t, withBackend(mb), withHierarchy(h))
432-
assertNoError(t, showAgentEditorKnowledgeBases(ctx, ""))
432+
assertNoError(t, listAgentEditorKnowledgeBases(ctx, ""))
433433

434434
out := buf.String()
435435
assertContainsStr(t, out, "Qualified Name")
@@ -488,7 +488,7 @@ func TestShowAgentEditorConsumedMCPServices_Mock(t *testing.T) {
488488
}
489489

490490
ctx, buf := newMockCtx(t, withBackend(mb), withHierarchy(h))
491-
assertNoError(t, showAgentEditorConsumedMCPServices(ctx, ""))
491+
assertNoError(t, listAgentEditorConsumedMCPServices(ctx, ""))
492492

493493
out := buf.String()
494494
assertContainsStr(t, out, "Qualified Name")

mdl/executor/cmd_agenteditor_models.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import (
1616
"github.com/mendixlabs/mxcli/sdk/agenteditor"
1717
)
1818

19-
// showAgentEditorModels handles SHOW MODELS [IN module].
20-
func showAgentEditorModels(ctx *ExecContext, moduleName string) error {
19+
// listAgentEditorModels handles SHOW MODELS [IN module].
20+
func listAgentEditorModels(ctx *ExecContext, moduleName string) error {
2121
if !ctx.Connected() {
2222
return mdlerrors.NewNotConnected()
2323
}

mdl/executor/cmd_associations.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -247,8 +247,8 @@ func execDropAssociation(ctx *ExecContext, s *ast.DropAssociationStmt) error {
247247
return mdlerrors.NewNotFound("association", s.Name.String())
248248
}
249249

250-
// showAssociations handles SHOW ASSOCIATIONS command.
251-
func showAssociations(ctx *ExecContext, moduleName string) error {
250+
// listAssociations handles SHOW ASSOCIATIONS command.
251+
func listAssociations(ctx *ExecContext, moduleName string) error {
252252
// Build module ID -> name map (single query)
253253
modules, err := ctx.Backend.ListModules()
254254
if err != nil {
@@ -333,8 +333,8 @@ func showAssociations(ctx *ExecContext, moduleName string) error {
333333
return writeResult(ctx, result)
334334
}
335335

336-
// showAssociation handles SHOW ASSOCIATION command.
337-
func showAssociation(ctx *ExecContext, name *ast.QualifiedName) error {
336+
// listAssociation handles SHOW ASSOCIATION command.
337+
func listAssociation(ctx *ExecContext, name *ast.QualifiedName) error {
338338
if name == nil {
339339
return mdlerrors.NewValidation("association name required")
340340
}

mdl/executor/cmd_associations_mock_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func TestShowAssociations_Mock(t *testing.T) {
3030
}
3131

3232
ctx, buf := newMockCtx(t, withBackend(mb))
33-
assertNoError(t, showAssociations(ctx, ""))
33+
assertNoError(t, listAssociations(ctx, ""))
3434

3535
out := buf.String()
3636
assertContainsStr(t, out, "MyModule.Order_Customer")
@@ -68,7 +68,7 @@ func TestShowAssociations_Mock_FilterByModule(t *testing.T) {
6868
}
6969

7070
ctx, buf := newMockCtx(t, withBackend(mb))
71-
assertNoError(t, showAssociations(ctx, "HR"))
71+
assertNoError(t, listAssociations(ctx, "HR"))
7272

7373
out := buf.String()
7474
assertNotContainsStr(t, out, "Sales.Order_Product")

mdl/executor/cmd_businessevents.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import (
1212
"github.com/mendixlabs/mxcli/model"
1313
)
1414

15-
// showBusinessEventServices displays a table of all business event service documents.
16-
func showBusinessEventServices(ctx *ExecContext, inModule string) error {
15+
// listBusinessEventServices displays a table of all business event service documents.
16+
func listBusinessEventServices(ctx *ExecContext, inModule string) error {
1717
if !ctx.Connected() {
1818
return mdlerrors.NewNotConnected()
1919
}
@@ -38,7 +38,7 @@ func showBusinessEventServices(ctx *ExecContext, inModule string) error {
3838
filtered = append(filtered, svc)
3939
}
4040

41-
if len(filtered) == 0 {
41+
if len(filtered) == 0 && ctx.Format != FormatJSON {
4242
if inModule != "" {
4343
fmt.Fprintf(ctx.Output, "No business event services found in module %s\n", inModule)
4444
} else {
@@ -86,14 +86,14 @@ func showBusinessEventServices(ctx *ExecContext, inModule string) error {
8686
return writeResult(ctx, result)
8787
}
8888

89-
// showBusinessEventClients displays a table of all business event client documents.
90-
func showBusinessEventClients(ctx *ExecContext, inModule string) error {
89+
// listBusinessEventClients displays a table of all business event client documents.
90+
func listBusinessEventClients(ctx *ExecContext, inModule string) error {
9191
fmt.Fprintln(ctx.Output, "Business event clients are not yet implemented.")
9292
return nil
9393
}
9494

95-
// showBusinessEvents displays a table of individual messages across all business event services.
96-
func showBusinessEvents(ctx *ExecContext, inModule string) error {
95+
// listBusinessEvents displays a table of individual messages across all business event services.
96+
func listBusinessEvents(ctx *ExecContext, inModule string) error {
9797
if !ctx.Connected() {
9898
return mdlerrors.NewNotConnected()
9999
}
@@ -150,7 +150,7 @@ func showBusinessEvents(ctx *ExecContext, inModule string) error {
150150
}
151151
}
152152

153-
if len(rows) == 0 {
153+
if len(rows) == 0 && ctx.Format != FormatJSON {
154154
if inModule != "" {
155155
fmt.Fprintf(ctx.Output, "No business events found in module %s\n", inModule)
156156
} else {

mdl/executor/cmd_businessevents_mock_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func TestShowBusinessEventServices_Mock(t *testing.T) {
2828
}
2929

3030
ctx, buf := newMockCtx(t, withBackend(mb), withHierarchy(h))
31-
assertNoError(t, showBusinessEventServices(ctx, ""))
31+
assertNoError(t, listBusinessEventServices(ctx, ""))
3232

3333
out := buf.String()
3434
assertContainsStr(t, out, "QualifiedName")
@@ -37,7 +37,7 @@ func TestShowBusinessEventServices_Mock(t *testing.T) {
3737

3838
func TestShowBusinessEventClients_Mock(t *testing.T) {
3939
ctx, buf := newMockCtx(t)
40-
assertNoError(t, showBusinessEventClients(ctx, ""))
40+
assertNoError(t, listBusinessEventClients(ctx, ""))
4141
assertContainsStr(t, buf.String(), "not yet implemented")
4242
}
4343

0 commit comments

Comments
 (0)