Skip to content

Commit 8329266

Browse files
committed
Merge remote-tracking branch 'upstream/main' into refactor/split-large-files
# Conflicts: # mdl/executor/cmd_entities.go # mdl/executor/executor.go
2 parents 21a9812 + 42c684e commit 8329266

57 files changed

Lines changed: 15185 additions & 13316 deletions

Some content is hidden

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

.claude/skills/mendix/create-page.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Guide for writing CREATE PAGE statements in Mendix Definition Language (MDL).
88
```sql
99
CREATE [OR REPLACE] PAGE Module.PageName
1010
(
11-
[Params: { $ParamName: Module.EntityType, ... },]
11+
[Params: { $ParamName: Module.EntityType | PrimitiveType, ... },]
1212
[Variables: { $varName: DataType = 'defaultExpression', ... },]
1313
Title: 'Page Title',
1414
Layout: Module.LayoutName,

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,13 @@ mxcli -p app.mpr -c "SHOW MODULES"
170170
# List entities in a module
171171
mxcli -p app.mpr -c "SHOW ENTITIES IN MyModule"
172172

173-
# Describe an entity, microflow, page, or workflow
173+
# Describe any element (module, entity, microflow, nanoflow, page, etc.)
174+
mxcli describe -p app.mpr module MyModule
174175
mxcli describe -p app.mpr entity MyModule.Customer
175176
mxcli describe -p app.mpr microflow MyModule.ProcessOrder
177+
mxcli describe -p app.mpr nanoflow MyModule.ValidateInput
176178
mxcli describe -p app.mpr page MyModule.CustomerOverview
177-
mxcli describe -p app.mpr workflow MyModule.MyWorkflow
179+
mxcli describe -p app.mpr json structure MyModule.CustomerResponse
178180
```
179181

180182
### Full-Text Search

cmd/mxcli/cmd_describe.go

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,42 +17,48 @@ var describeCmd = &cobra.Command{
1717
Long: `Describe an element from a Mendix project in MDL syntax.
1818
1919
Types:
20+
module Describe a module (all contents)
2021
entity Describe an entity
2122
externalentity Describe an external entity (alias for entity)
2223
association Describe an association
2324
enumeration Describe an enumeration
2425
constant Describe a constant
2526
microflow Describe a microflow
27+
nanoflow Describe a nanoflow
2628
workflow Describe a workflow
2729
page Describe a page
2830
snippet Describe a snippet
2931
layout Describe a layout
3032
javaaction Describe a java action
33+
jsonstructure Describe a JSON structure (also: "json structure")
34+
importmapping Describe an import mapping (also: "import mapping")
35+
exportmapping Describe an export mapping (also: "export mapping")
36+
restclient Describe a consumed REST service (also: "rest client")
3137
odataclient Describe a consumed OData service
3238
odataservice Describe a published OData service
39+
imagecollection Describe an image collection (also: "image collection")
3340
businesseventservice Describe a business event service (also: "business event service")
41+
databaseconnection Describe a database connection (also: "database connection")
3442
modulerole Describe a module role
3543
userrole Describe a user role
3644
projectsecurity Show project security settings
45+
settings Describe project settings
3746
demouser Describe a demo user
3847
navigation Describe a navigation profile
3948
systemoverview Module dependency graph (requires --format elk)
4049
4150
Example:
51+
mxcli describe -p app.mpr module MyModule
4252
mxcli describe -p app.mpr entity MyModule.Customer
4353
mxcli describe -p app.mpr microflow MyModule.ProcessOrder
44-
mxcli describe -p app.mpr workflow MyModule.MyWorkflow
54+
mxcli describe -p app.mpr nanoflow MyModule.ValidateInput
55+
mxcli describe -p app.mpr page MyModule.Customer_Overview
56+
mxcli describe -p app.mpr json structure MyModule.CustomerResponse
57+
mxcli describe -p app.mpr import mapping MyModule.IMM_Customer
58+
mxcli describe -p app.mpr export mapping MyModule.EMM_Customer
59+
mxcli describe -p app.mpr rest client MyModule.PetStoreAPI
60+
mxcli describe -p app.mpr settings Settings
4561
mxcli describe -p app.mpr navigation Responsive
46-
mxcli describe -p app.mpr layout Atlas_Core.PopupLayout
47-
mxcli describe -p app.mpr javaaction MyModule.MyAction
48-
mxcli describe -p app.mpr odataclient MyModule.ExternalAPI
49-
mxcli describe -p app.mpr odataservice MyModule.CustomerAPI
50-
mxcli describe -p app.mpr businesseventservice MyModule.CustomerEventsApi
51-
mxcli describe -p app.mpr business event service MyModule.CustomerEventsApi
52-
mxcli describe -p app.mpr constant MyModule.BaseUrl
53-
mxcli describe -p app.mpr modulerole MyModule.User
54-
mxcli describe -p app.mpr userrole Administrator
55-
mxcli describe -p app.mpr projectsecurity ProjectSecurity
5662
mxcli describe -p app.mpr --format elk systemoverview SystemOverview
5763
`,
5864
Args: cobra.MinimumNArgs(2),
@@ -70,6 +76,8 @@ Example:
7076

7177
var mdlCmd string
7278
switch objectType {
79+
case "MODULE":
80+
mdlCmd = fmt.Sprintf("DESCRIBE MODULE %s", name)
7381
case "ENTITY":
7482
mdlCmd = fmt.Sprintf("DESCRIBE ENTITY %s", name)
7583
case "ASSOCIATION":
@@ -78,6 +86,8 @@ Example:
7886
mdlCmd = fmt.Sprintf("DESCRIBE ENUMERATION %s", name)
7987
case "MICROFLOW":
8088
mdlCmd = fmt.Sprintf("DESCRIBE MICROFLOW %s", name)
89+
case "NANOFLOW":
90+
mdlCmd = fmt.Sprintf("DESCRIBE NANOFLOW %s", name)
8191
case "WORKFLOW":
8292
mdlCmd = fmt.Sprintf("DESCRIBE WORKFLOW %s", name)
8393
case "PAGE":
@@ -92,16 +102,28 @@ Example:
92102
mdlCmd = fmt.Sprintf("DESCRIBE USER ROLE '%s'", name)
93103
case "PROJECTSECURITY", "PROJECT SECURITY":
94104
mdlCmd = "SHOW PROJECT SECURITY"
105+
case "SETTINGS":
106+
mdlCmd = "DESCRIBE SETTINGS"
95107
case "DEMOUSER", "DEMO USER":
96108
mdlCmd = fmt.Sprintf("DESCRIBE DEMO USER '%s'", name)
97109
case "JAVAACTION", "JAVA ACTION":
98110
mdlCmd = fmt.Sprintf("DESCRIBE JAVA ACTION %s", name)
99111
case "CONSTANT":
100112
mdlCmd = fmt.Sprintf("DESCRIBE CONSTANT %s", name)
113+
case "JSONSTRUCTURE", "JSON STRUCTURE":
114+
mdlCmd = fmt.Sprintf("DESCRIBE JSON STRUCTURE %s", name)
115+
case "IMPORTMAPPING", "IMPORT MAPPING":
116+
mdlCmd = fmt.Sprintf("DESCRIBE IMPORT MAPPING %s", name)
117+
case "EXPORTMAPPING", "EXPORT MAPPING":
118+
mdlCmd = fmt.Sprintf("DESCRIBE EXPORT MAPPING %s", name)
119+
case "RESTCLIENT", "REST CLIENT":
120+
mdlCmd = fmt.Sprintf("DESCRIBE REST CLIENT %s", name)
101121
case "ODATACLIENT", "ODATA CLIENT":
102122
mdlCmd = fmt.Sprintf("DESCRIBE ODATA CLIENT %s", name)
103123
case "ODATASERVICE", "ODATA SERVICE":
104124
mdlCmd = fmt.Sprintf("DESCRIBE ODATA SERVICE %s", name)
125+
case "IMAGECOLLECTION", "IMAGE COLLECTION":
126+
mdlCmd = fmt.Sprintf("DESCRIBE IMAGE COLLECTION %s", name)
105127
case "BUSINESSEVENTSERVICE", "BUSINESS EVENT SERVICE":
106128
mdlCmd = fmt.Sprintf("DESCRIBE BUSINESS EVENT SERVICE %s", name)
107129
case "DATABASECONNECTION", "DATABASE CONNECTION":
@@ -116,8 +138,8 @@ Example:
116138
mdlCmd = "" // handled directly by format-specific path
117139
default:
118140
fmt.Fprintf(os.Stderr, "Unknown type: %s\n", strings.Join(args[:len(args)-1], " "))
119-
fmt.Fprintln(os.Stderr, "Valid types: entity, association, enumeration, constant, microflow, workflow, page, snippet, layout, javaaction, odataclient, odataservice, businesseventservice, databaseconnection, modulerole, userrole, projectsecurity, demouser, navigation, systemoverview")
120-
fmt.Fprintln(os.Stderr, "Multi-word types also accepted: business event service, odata service, java action, database connection, etc.")
141+
fmt.Fprintln(os.Stderr, "Valid types: module, entity, association, enumeration, constant, microflow, nanoflow, workflow, page, snippet, layout, javaaction, jsonstructure, importmapping, exportmapping, restclient, odataclient, odataservice, imagecollection, businesseventservice, databaseconnection, modulerole, userrole, projectsecurity, settings, demouser, navigation, systemoverview")
142+
fmt.Fprintln(os.Stderr, "Multi-word types also accepted: json structure, import mapping, export mapping, rest client, image collection, business event service, etc.")
121143
os.Exit(1)
122144
}
123145

cmd/mxcli/cmd_new.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ Examples:
8888
os.Exit(1)
8989
}
9090

91+
// Clean up duplicate locale files that mx create-project generates.
92+
// MxBuild's AtlasPlugin.LoadTranslations crashes with "An item with the same
93+
// key has already been added" when duplicate translation.json files exist.
94+
if removed := cleanupDuplicateLocaleFiles(absDir); removed > 0 {
95+
fmt.Printf(" Cleaned %d duplicate locale file(s)\n", removed)
96+
}
97+
9198
// Verify .mpr was created — mx create-project names the file after --app-name
9299
mprPath := filepath.Join(absDir, appName+".mpr")
93100
if _, err := os.Stat(mprPath); os.IsNotExist(err) {
@@ -153,6 +160,51 @@ Examples:
153160
},
154161
}
155162

163+
// cleanupDuplicateLocaleFiles removes duplicate locale files that mx create-project
164+
// generates in themesource/atlas_core/. MxBuild crashes when multiple translation.json
165+
// files map to the same locale key (e.g., "en-US").
166+
//
167+
// Studio Pro-created projects have locale files only at:
168+
// themesource/atlas_core/locales/<locale>/translation.json
169+
//
170+
// mx create-project additionally creates duplicates in nested subdirectories
171+
// (e.g., locales/en-US/atlas_core/locales/en-US/translation.json).
172+
// We keep only the top-level files and remove any deeper duplicates.
173+
func cleanupDuplicateLocaleFiles(projectDir string) int {
174+
localesDir := filepath.Join(projectDir, "themesource", "atlas_core", "locales")
175+
if _, err := os.Stat(localesDir); os.IsNotExist(err) {
176+
return 0
177+
}
178+
179+
removed := 0
180+
// Walk locale directories (en-US, nl-NL, etc.)
181+
entries, err := os.ReadDir(localesDir)
182+
if err != nil {
183+
return 0
184+
}
185+
for _, entry := range entries {
186+
if !entry.IsDir() {
187+
continue
188+
}
189+
localeDir := filepath.Join(localesDir, entry.Name())
190+
// Check for nested subdirectories that duplicate the locale
191+
subEntries, err := os.ReadDir(localeDir)
192+
if err != nil {
193+
continue
194+
}
195+
for _, sub := range subEntries {
196+
if sub.IsDir() {
197+
// Any subdirectory under a locale dir is a duplicate tree
198+
dupPath := filepath.Join(localeDir, sub.Name())
199+
if err := os.RemoveAll(dupPath); err == nil {
200+
removed++
201+
}
202+
}
203+
}
204+
}
205+
return removed
206+
}
207+
156208
func init() {
157209
newCmd.Flags().String("version", "", "Mendix version (e.g., 11.8.0) — required")
158210
newCmd.Flags().String("output-dir", "", "Output directory (default: ./<app-name>)")

cmd/mxcli/cmd_rename.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package main
4+
5+
import (
6+
"fmt"
7+
"os"
8+
"strings"
9+
10+
"github.com/mendixlabs/mxcli/mdl/visitor"
11+
"github.com/spf13/cobra"
12+
)
13+
14+
var renameCmd = &cobra.Command{
15+
Use: "rename <type> <qualified-name> <new-name>",
16+
Short: "Rename a project element and update all references",
17+
Long: `Rename an element and automatically update all cross-references.
18+
19+
Types:
20+
entity Rename an entity
21+
microflow Rename a microflow
22+
nanoflow Rename a nanoflow
23+
page Rename a page
24+
enumeration Rename an enumeration
25+
association Rename an association
26+
constant Rename a constant
27+
module Rename a module (updates all qualified names)
28+
29+
Use --dry-run to preview changes without modifying.
30+
31+
Example:
32+
mxcli rename -p app.mpr entity MyModule.Customer Client
33+
mxcli rename -p app.mpr microflow MyModule.ACT_Old ACT_New
34+
mxcli rename -p app.mpr page MyModule.OldPage NewPage
35+
mxcli rename -p app.mpr module OldModule NewModule
36+
mxcli rename -p app.mpr entity MyModule.Customer Client --dry-run
37+
`,
38+
Args: cobra.ExactArgs(3),
39+
Run: func(cmd *cobra.Command, args []string) {
40+
projectPath, _ := cmd.Flags().GetString("project")
41+
if projectPath == "" {
42+
fmt.Fprintln(os.Stderr, "Error: --project (-p) is required")
43+
os.Exit(1)
44+
}
45+
46+
dryRun, _ := cmd.Flags().GetBool("dry-run")
47+
48+
objectType := strings.ToUpper(args[0])
49+
qualifiedName := args[1]
50+
newName := args[2]
51+
52+
var mdlCmd string
53+
dryRunSuffix := ""
54+
if dryRun {
55+
dryRunSuffix = " DRY RUN"
56+
}
57+
58+
switch objectType {
59+
case "ENTITY":
60+
mdlCmd = fmt.Sprintf("RENAME ENTITY %s TO %s%s", qualifiedName, newName, dryRunSuffix)
61+
case "MICROFLOW":
62+
mdlCmd = fmt.Sprintf("RENAME MICROFLOW %s TO %s%s", qualifiedName, newName, dryRunSuffix)
63+
case "NANOFLOW":
64+
mdlCmd = fmt.Sprintf("RENAME NANOFLOW %s TO %s%s", qualifiedName, newName, dryRunSuffix)
65+
case "PAGE":
66+
mdlCmd = fmt.Sprintf("RENAME PAGE %s TO %s%s", qualifiedName, newName, dryRunSuffix)
67+
case "ENUMERATION":
68+
mdlCmd = fmt.Sprintf("RENAME ENUMERATION %s TO %s%s", qualifiedName, newName, dryRunSuffix)
69+
case "ASSOCIATION":
70+
mdlCmd = fmt.Sprintf("RENAME ASSOCIATION %s TO %s%s", qualifiedName, newName, dryRunSuffix)
71+
case "CONSTANT":
72+
mdlCmd = fmt.Sprintf("RENAME CONSTANT %s TO %s%s", qualifiedName, newName, dryRunSuffix)
73+
case "MODULE":
74+
mdlCmd = fmt.Sprintf("RENAME MODULE %s TO %s%s", qualifiedName, newName, dryRunSuffix)
75+
default:
76+
fmt.Fprintf(os.Stderr, "Unknown type: %s\n", args[0])
77+
fmt.Fprintln(os.Stderr, "Valid types: entity, microflow, nanoflow, page, enumeration, association, constant, module")
78+
os.Exit(1)
79+
}
80+
81+
exec, logger := newLoggedExecutor("subcommand")
82+
defer logger.Close()
83+
defer exec.Close()
84+
85+
// Connect
86+
connectProg, _ := visitor.Build(fmt.Sprintf("CONNECT LOCAL '%s' FOR WRITING", projectPath))
87+
for _, stmt := range connectProg.Statements {
88+
if err := exec.Execute(stmt); err != nil {
89+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
90+
os.Exit(1)
91+
}
92+
}
93+
94+
// Execute rename
95+
renameProg, errs := visitor.Build(mdlCmd)
96+
if len(errs) > 0 {
97+
for _, err := range errs {
98+
fmt.Fprintf(os.Stderr, "Parse error: %v\n", err)
99+
}
100+
os.Exit(1)
101+
}
102+
103+
for _, stmt := range renameProg.Statements {
104+
if err := exec.Execute(stmt); err != nil {
105+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
106+
os.Exit(1)
107+
}
108+
}
109+
},
110+
}
111+
112+
func init() {
113+
renameCmd.Flags().Bool("dry-run", false, "Preview changes without modifying")
114+
rootCmd.AddCommand(renameCmd)
115+
}

cmd/mxcli/cmd_show.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ import (
1111
)
1212

1313
var showCmd = &cobra.Command{
14-
Use: "show <type> [name]",
15-
Short: "Show project elements",
16-
Long: `Show elements from a Mendix project.
14+
Use: "show <type> [name]",
15+
Aliases: []string{"list"},
16+
Short: "List project elements",
17+
Long: `List elements from a Mendix project. (Also available as "mxcli list")
1718
1819
Types:
1920
modules List all modules

cmd/mxcli/help_topics/page.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ Basic syntax:
1414
-- widgets
1515
}
1616

17-
With parameters (for detail pages):
17+
With parameters (entity or primitive types):
1818
CREATE PAGE Module.Name
1919
(
20-
Params: { $Param: Module.Entity },
20+
Params: { $Param: Module.Entity, $Qty: Integer },
2121
Title: 'Title',
2222
Layout: Module.Layout
2323
)

cmd/mxcli/help_topics/snippet.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ Basic syntax (no parameters):
1010
-- widgets
1111
}
1212

13-
With parameters:
13+
With parameters (entity or primitive types):
1414
CREATE SNIPPET Module.Name (
15-
Params: { $Param: Module.Entity }
15+
Params: { $Param: Module.Entity, $Label: String }
1616
)
1717
{
1818
DATAVIEW dv (DataSource: $Param) {

cmd/mxcli/lsp_completions_gen.go

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)