mxrb 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/mxrb +458 -10
- data/docs/de-DE/README.md +1 -0
- data/docs/de-DE/oql-sql.md +42 -0
- data/docs/de-DE/project-structure.md +201 -2
- data/docs/de-DE/runtime-ruby.md +104 -0
- data/docs/de-DE/runtime-schema-migrations.md +44 -0
- data/docs/de-DE/validation-matrix.md +42 -4
- data/docs/en-US/README.md +1 -0
- data/docs/en-US/oql-sql.md +41 -0
- data/docs/en-US/project-structure.md +192 -2
- data/docs/en-US/runtime-ruby.md +100 -0
- data/docs/en-US/runtime-schema-migrations.md +41 -0
- data/docs/en-US/validation-matrix.md +39 -4
- data/docs/pt-BR/README.md +1 -0
- data/docs/pt-BR/entity-dsl.md +8 -0
- data/docs/pt-BR/oql-sql.md +41 -0
- data/docs/pt-BR/project-structure.md +197 -2
- data/docs/pt-BR/runtime-ruby.md +108 -0
- data/docs/pt-BR/runtime-schema-migrations.md +40 -0
- data/docs/pt-BR/validation-matrix.md +42 -5
- data/docs/pt-BR/writing.md +28 -0
- data/lib/mxrb/cli/help.rb +426 -0
- data/lib/mxrb/cli/release.rb +137 -0
- data/lib/mxrb/compiler/compatibility_analyzer.rb +1 -1
- data/lib/mxrb/compiler/data_grid_bundle_compiler.rb +8 -1
- data/lib/mxrb/compiler/domain_document_compiler.rb +3 -0
- data/lib/mxrb/compiler/gallery_bundle_compiler.rb +11 -1
- data/lib/mxrb/compiler/generic_widget_bundle_compiler.rb +76 -19
- data/lib/mxrb/compiler/legacy_custom_widget_compiler.rb +159 -0
- data/lib/mxrb/compiler/legacy_data_grid_compiler.rb +43 -7
- data/lib/mxrb/compiler/legacy_page_builder.rb +1248 -23
- data/lib/mxrb/compiler/packager.rb +27 -13
- data/lib/mxrb/compiler/page_bundle_compiler.rb +13 -4
- data/lib/mxrb/compiler/portable_packager.rb +16 -11
- data/lib/mxrb/compiler/web_bundle_builder.rb +5 -1
- data/lib/mxrb/compiler/web_shell_materializer.rb +42 -2
- data/lib/mxrb/compiler/widget_package_extractor.rb +3 -0
- data/lib/mxrb/domain_diagram/lifecycle.rb +272 -0
- data/lib/mxrb/domain_diagram.rb +409 -0
- data/lib/mxrb/dsl/builder.rb +62 -11
- data/lib/mxrb/environment.rb +226 -0
- data/lib/mxrb/exporter.rb +265 -45
- data/lib/mxrb/http/server.rb +107 -0
- data/lib/mxrb/initializer.rb +80 -9
- data/lib/mxrb/integrity/validator.rb +32 -7
- data/lib/mxrb/io/bson_codec.rb +42 -1
- data/lib/mxrb/io/mpr_file.rb +146 -3
- data/lib/mxrb/model/attribute.rb +3 -0
- data/lib/mxrb/model/entity.rb +44 -2
- data/lib/mxrb/model/microflow.rb +3 -1
- data/lib/mxrb/model/module.rb +71 -0
- data/lib/mxrb/model/page.rb +126 -15
- data/lib/mxrb/model/project.rb +3 -0
- data/lib/mxrb/modeler/catalog.rb +178 -0
- data/lib/mxrb/official_marketplace/module_package_importer.rb +23 -12
- data/lib/mxrb/official_marketplace/widget_package_installer.rb +15 -11
- data/lib/mxrb/official_marketplace.rb +9 -3
- data/lib/mxrb/oql/reverse_translator.rb +394 -0
- data/lib/mxrb/oql/server.rb +4 -8
- data/lib/mxrb/oql.rb +32 -4
- data/lib/mxrb/progress.rb +242 -0
- data/lib/mxrb/project_lifecycle.rb +5 -2
- data/lib/mxrb/ruby_app/exporter.rb +1749 -0
- data/lib/mxrb/ruby_app/preset.rb +506 -0
- data/lib/mxrb/ruby_app/session_manager.rb +122 -0
- data/lib/mxrb/ruby_app.rb +1361 -0
- data/lib/mxrb/runtime/access_control.rb +408 -0
- data/lib/mxrb/runtime/native.rb +1015 -93
- data/lib/mxrb/runtime/scheduler.rb +396 -0
- data/lib/mxrb/runtime/schema_migrator.rb +598 -0
- data/lib/mxrb/runtime/shared_store.rb +335 -0
- data/lib/mxrb/runtime/sqlite_store.rb +729 -0
- data/lib/mxrb/scaffold/generator.rb +11 -3
- data/lib/mxrb/team_server.rb +10 -7
- data/lib/mxrb/uml/activity_diagram.rb +118 -0
- data/lib/mxrb/uml/class_diagram.rb +118 -0
- data/lib/mxrb/uml/sequence_diagram.rb +112 -0
- data/lib/mxrb/uml/server.rb +146 -0
- data/lib/mxrb/uml/support.rb +35 -0
- data/lib/mxrb/version.rb +1 -1
- data/lib/mxrb/web_ui/assets/abnfDiagram-N423BO3Z-C4JD3cEC.js +1 -0
- data/lib/mxrb/web_ui/assets/arc-3Z53kgFp.js +1 -0
- data/lib/mxrb/web_ui/assets/architecture-TIHT7OUA-BStBTLea.js +1 -0
- data/lib/mxrb/web_ui/assets/architectureDiagram-T3A2C74G-DBwqnM4J.js +36 -0
- data/lib/mxrb/web_ui/assets/array-BifhSqXX.js +1 -0
- data/lib/mxrb/web_ui/assets/blockDiagram-VBNYF7ZC-DLtuHt-j.js +132 -0
- data/lib/mxrb/web_ui/assets/c4Diagram-5PPSVZJV-ConSk_pe.js +10 -0
- data/lib/mxrb/web_ui/assets/channel-BhPvD7Dt.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-2GRJ4B5K-D2HpWsf_.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-4I5QYGJK-CiIdNwaF.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-5RXB4S5H-Bu_AaEkE.js +231 -0
- data/lib/mxrb/web_ui/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
- data/lib/mxrb/web_ui/assets/chunk-6Q2QTUOP-wQkNmt_X.js +88 -0
- data/lib/mxrb/web_ui/assets/chunk-7BUUIJ7U-Bb538aSH.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-GF5L2VYU-G8MmiBzU.js +206 -0
- data/lib/mxrb/web_ui/assets/chunk-I66GZJ75-CulcrLPh.js +127 -0
- data/lib/mxrb/web_ui/assets/chunk-JQJVKLGR-ukjzcdlL.js +156 -0
- data/lib/mxrb/web_ui/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-KBJHAD2P-Wm35lYov.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-KEIR6QF5-BICK3FdT.js +161 -0
- data/lib/mxrb/web_ui/assets/chunk-NSK5VX7P-D2nYrCY4.js +2 -0
- data/lib/mxrb/web_ui/assets/chunk-QR6OTTB3-BrdIzg4Q.js +62 -0
- data/lib/mxrb/web_ui/assets/chunk-RYQCIY6F-CCfZMcW6.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-UBXNYLIW-BPEVYsFK.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-W5SLKNZC-2E6OPhA4.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-WRU74C26-CBIvOyWp.js +70 -0
- data/lib/mxrb/web_ui/assets/chunk-XXDRQBXY-pH58XAyl.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
- data/lib/mxrb/web_ui/assets/classDiagram-JCYQIIEL-xiqo4D89.js +1 -0
- data/lib/mxrb/web_ui/assets/classDiagram-v2-OCEON4UE-xiqo4D89.js +1 -0
- data/lib/mxrb/web_ui/assets/cose-bilkent-JH36ORCC-t_flPpii.js +1 -0
- data/lib/mxrb/web_ui/assets/cynefin-VYW2F7L2-BIqktTEv.js +1 -0
- data/lib/mxrb/web_ui/assets/cynefinDiagram-MW4NZA55-C2d--lut.js +62 -0
- data/lib/mxrb/web_ui/assets/cytoscape.esm-B-NFISlW.js +321 -0
- data/lib/mxrb/web_ui/assets/dagre-Buvkdvvj.js +1 -0
- data/lib/mxrb/web_ui/assets/dagre-VZM6K2ZE-CSz2_tb5.js +4 -0
- data/lib/mxrb/web_ui/assets/defaultLocale-BFoDCU3G.js +1 -0
- data/lib/mxrb/web_ui/assets/diagram-7IWD3JNH-DCt7u7V_.js +30 -0
- data/lib/mxrb/web_ui/assets/diagram-B4RE2ZJO-DqZBqkMu.js +3 -0
- data/lib/mxrb/web_ui/assets/diagram-LBJQPF4R-ClIYbIsI.js +24 -0
- data/lib/mxrb/web_ui/assets/diagram-Q27KOJAE-DFxhvthJ.js +24 -0
- data/lib/mxrb/web_ui/assets/diagram-UB23O5K3-BSUTXptv.js +41 -0
- data/lib/mxrb/web_ui/assets/dist-D2qOEbeJ.js +1 -0
- data/lib/mxrb/web_ui/assets/domain-mGOZ1KCG.css +1 -0
- data/lib/mxrb/web_ui/assets/domain-qsjXhy4v.js +1 -0
- data/lib/mxrb/web_ui/assets/ebnfDiagram-BXEA7PRR-B5reICEi.js +1 -0
- data/lib/mxrb/web_ui/assets/erDiagram-JOGREHBK-Co5Mxn2p.js +85 -0
- data/lib/mxrb/web_ui/assets/eventmodeling-45OFAUF4-C1ylhSks.js +1 -0
- data/lib/mxrb/web_ui/assets/flowDiagram-UKHOOZJN-CHXaJIaS.js +1 -0
- data/lib/mxrb/web_ui/assets/ganttDiagram-PKOTCBZU-DPPPaWaz.js +292 -0
- data/lib/mxrb/web_ui/assets/gitGraph-TEB2WS4Q-qS77ywA9.js +1 -0
- data/lib/mxrb/web_ui/assets/gitGraphDiagram-DS77QQ5N-DpAv6-BT.js +106 -0
- data/lib/mxrb/web_ui/assets/graphlib-DS17s2tU.js +1 -0
- data/lib/mxrb/web_ui/assets/info-DKCQHKI2-C9VD1Y4e.js +1 -0
- data/lib/mxrb/web_ui/assets/infoDiagram-6WML65LV-Bk1kbcCy.js +2 -0
- data/lib/mxrb/web_ui/assets/init-C-OQMol4.js +1 -0
- data/lib/mxrb/web_ui/assets/ishikawaDiagram-WSZJBQD7-0gcISBFR.js +70 -0
- data/lib/mxrb/web_ui/assets/journeyDiagram-NVQOT4AX-Dt0RQnlh.js +139 -0
- data/lib/mxrb/web_ui/assets/jsx-runtime-DV0a5kSb.js +9 -0
- data/lib/mxrb/web_ui/assets/kanban-definition-27J2QSJJ-DIPQM7w9.js +89 -0
- data/lib/mxrb/web_ui/assets/katex-CXMH3UgJ.js +257 -0
- data/lib/mxrb/web_ui/assets/line-C0rYD-tL.js +1 -0
- data/lib/mxrb/web_ui/assets/linear-BPPxWorj.js +1 -0
- data/lib/mxrb/web_ui/assets/map-BaFkSB1l.js +1 -0
- data/lib/mxrb/web_ui/assets/mermaid-parser.core-B_UPzTxa.js +7 -0
- data/lib/mxrb/web_ui/assets/mindmap-definition-FAOFIHXS-CdJRSMuk.js +96 -0
- data/lib/mxrb/web_ui/assets/modeler-BNqHthwk.css +1 -0
- data/lib/mxrb/web_ui/assets/modeler-CQmqflbg.js +1 -0
- data/lib/mxrb/web_ui/assets/ordinal-BDEzSJ7C.js +1 -0
- data/lib/mxrb/web_ui/assets/packet-7NZHBO7P-CwQ4NSBs.js +1 -0
- data/lib/mxrb/web_ui/assets/path-fybaL0A-.js +1 -0
- data/lib/mxrb/web_ui/assets/pegDiagram-VL7TDLO6-D40S7ppx.js +1 -0
- data/lib/mxrb/web_ui/assets/pie-RZYD4A2V-CJroHMKh.js +1 -0
- data/lib/mxrb/web_ui/assets/pieDiagram-7S7Q4E2Y-QB54__BV.js +39 -0
- data/lib/mxrb/web_ui/assets/quadrantDiagram-CIZ2JOQS-DBhDS6ag.js +7 -0
- data/lib/mxrb/web_ui/assets/radar-I7S5WNFK-DdIUwd2d.js +1 -0
- data/lib/mxrb/web_ui/assets/railroad-3IZDKUUU-B1Lw6Xyq.js +1 -0
- data/lib/mxrb/web_ui/assets/railroad-abnf-AHOZXSZD-CQgQoeak.js +1 -0
- data/lib/mxrb/web_ui/assets/railroad-ebnf-EBAXGLYW-D7qEQ2x8.js +1 -0
- data/lib/mxrb/web_ui/assets/railroad-peg-LSFZ7HO6-C005Vxbb.js +1 -0
- data/lib/mxrb/web_ui/assets/railroadDiagram-AXF67PYL-BBP2qk7M.js +1 -0
- data/lib/mxrb/web_ui/assets/requirementDiagram-LRYGKXZP-D2cLsAoI.js +84 -0
- data/lib/mxrb/web_ui/assets/rough.esm-Dy-Kn_BL.js +1 -0
- data/lib/mxrb/web_ui/assets/sankeyDiagram-W5VNT64P-Bpi3FiP2.js +40 -0
- data/lib/mxrb/web_ui/assets/sequenceDiagram-SI44F4Z6-DCRcDlVe.js +162 -0
- data/lib/mxrb/web_ui/assets/sizeCapture-X5ZJPWSS-B0uUizjq.js +1 -0
- data/lib/mxrb/web_ui/assets/src-CvxfUak2.js +1 -0
- data/lib/mxrb/web_ui/assets/stateDiagram-OKZ733FA-C2GCEoxl.js +1 -0
- data/lib/mxrb/web_ui/assets/stateDiagram-v2-UEYNNEHI-D2gWgedh.js +1 -0
- data/lib/mxrb/web_ui/assets/swimlanes-SLNWSIFB-CRI9irEW.js +2 -0
- data/lib/mxrb/web_ui/assets/swimlanesDiagram-ULZ7WXOC-C5Wb_-hZ.js +8 -0
- data/lib/mxrb/web_ui/assets/theme-_mxc7BdY.css +1 -0
- data/lib/mxrb/web_ui/assets/timeline-definition-Z64GVDOM-B1-mNg-h.js +120 -0
- data/lib/mxrb/web_ui/assets/treeView-QDETBFTQ-7CTvIwKq.js +1 -0
- data/lib/mxrb/web_ui/assets/treemap-6X3UGDF4-CtL22pq5.js +1 -0
- data/lib/mxrb/web_ui/assets/uml-C3KAFGTq.js +51 -0
- data/lib/mxrb/web_ui/assets/uml-Dn-qd01X.css +1 -0
- data/lib/mxrb/web_ui/assets/vennDiagram-T6HMQDX7-BzVnUEAy.js +34 -0
- data/lib/mxrb/web_ui/assets/wardley-OPB4EBWU-JNi-QNag.js +1 -0
- data/lib/mxrb/web_ui/assets/wardleyDiagram-T6FBY63Y-BUwmAQ-B.js +78 -0
- data/lib/mxrb/web_ui/assets/xychartDiagram-ELKLHX3M-DEQS8sKp.js +7 -0
- data/lib/mxrb/web_ui/domain.html +15 -0
- data/lib/mxrb/web_ui/modeler.html +16 -0
- data/lib/mxrb/web_ui/uml.html +31 -0
- data/lib/mxrb/web_ui.rb +89 -0
- data/lib/mxrb/widget_certification.rb +208 -0
- data/lib/mxrb/writer.rb +278 -41
- data/lib/mxrb.rb +38 -8
- metadata +157 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2d95f5a294643904d99fdac9afbf3d0e6f08e1aa209c8aff81b812daec751c9e
|
|
4
|
+
data.tar.gz: eba324a63596fc22694d5fb672a3a1bc072e937d1d4d92715c0f907c68f23931
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f3499ae32520b02952d2ded0622ec8be158a8d7e3ae36da5937b4cd5e187fb963100ad01925917f1d583db5b50dcf52b5a171abc09c128267dfcdb4d812ffe59
|
|
7
|
+
data.tar.gz: d8c1c51f90002b755ad9a3f03e4656c352cb09744ff8a893cae380cbb9d0b3b81074acbf758c788935b30ae6741efe8df7d5f87cfc06f3b2d25424211914c64c
|
data/bin/mxrb
CHANGED
|
@@ -62,14 +62,103 @@ def render_index_advice(advice, json:) # rubocop:disable Metrics/AbcSize
|
|
|
62
62
|
puts '[mxrb] No evidence-backed index candidates' if advice.candidates.empty?
|
|
63
63
|
end
|
|
64
64
|
|
|
65
|
+
def extract_cli_value!(arguments, name) # rubocop:disable Metrics/AbcSize
|
|
66
|
+
attached = arguments.select { _1.start_with?("#{name}=") }
|
|
67
|
+
index = arguments.index(name)
|
|
68
|
+
raise ArgumentError, "use #{name} only once" if attached.size + (index ? 1 : 0) > 1
|
|
69
|
+
|
|
70
|
+
return arguments.delete(attached.first).split('=', 2).last if attached.one?
|
|
71
|
+
return unless index
|
|
72
|
+
|
|
73
|
+
raise ArgumentError, "#{name} requires a value" unless arguments[index + 1]
|
|
74
|
+
|
|
75
|
+
arguments.slice!(index, 2).last
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def load_environment!(name, root:)
|
|
79
|
+
Mxrb::Environment.load(name, root:)
|
|
80
|
+
rescue Mxrb::Environment::Error, Mxrb::Environment::InvalidName => e
|
|
81
|
+
abort "[mxrb] #{e.message}"
|
|
82
|
+
end
|
|
83
|
+
|
|
65
84
|
SCAFFOLD_COMMANDS = (Mxrb::Scaffold::Help::COMMANDS.keys - ["design"]).freeze
|
|
66
85
|
|
|
86
|
+
progress_disabled = ARGV.delete("--no-progress")
|
|
67
87
|
command = ARGV.shift
|
|
88
|
+
command = 'diagram-er' if command == 'domain-model'
|
|
89
|
+
Mxrb::Progress.configure(enabled: false) if progress_disabled || ARGV.include?("--json")
|
|
90
|
+
|
|
91
|
+
command_flags = %w[--commands --comands]
|
|
92
|
+
if command.nil?
|
|
93
|
+
puts Mxrb::CLI::Help.welcome(release: Mxrb::CLI::Releases.new.status)
|
|
94
|
+
exit
|
|
95
|
+
elsif %w[--help -h help].include?(command)
|
|
96
|
+
path = command == 'help' ? ARGV.reject { _1.start_with?('-') } : []
|
|
97
|
+
puts(path.empty? ? Mxrb::CLI::Help.overview : Mxrb::CLI::Help.command(path))
|
|
98
|
+
exit
|
|
99
|
+
elsif command_flags.include?(command)
|
|
100
|
+
puts Mxrb::CLI::Help.commands
|
|
101
|
+
exit
|
|
102
|
+
elsif (commands_flag = (ARGV & command_flags).first)
|
|
103
|
+
ARGV.delete(commands_flag)
|
|
104
|
+
puts Mxrb::CLI::Help.commands(command)
|
|
105
|
+
exit
|
|
106
|
+
elsif (help_flag = (ARGV & %w[--help -h]).first)
|
|
107
|
+
help_index = ARGV.index(help_flag)
|
|
108
|
+
path = [command] + ARGV.take(help_index).reject { _1.start_with?('-') }.take(1)
|
|
109
|
+
puts Mxrb::CLI::Help.command(path)
|
|
110
|
+
exit
|
|
111
|
+
end
|
|
68
112
|
|
|
69
113
|
case command
|
|
70
114
|
when '--version', '-v'
|
|
71
115
|
puts "mxrb #{Mxrb::VERSION}"
|
|
72
116
|
|
|
117
|
+
when 'changelog'
|
|
118
|
+
version = ARGV.shift
|
|
119
|
+
abort "Unknown arguments: #{ARGV.join(' ')}" unless ARGV.empty?
|
|
120
|
+
begin
|
|
121
|
+
release = Mxrb::CLI::Releases.new.changelog(version)
|
|
122
|
+
puts "#{release.fetch(:title)}#{release[:published_at] ? " (#{release[:published_at]})" : ''}"
|
|
123
|
+
puts
|
|
124
|
+
puts release.fetch(:body).empty? ? 'No release notes were published.' : release.fetch(:body)
|
|
125
|
+
puts
|
|
126
|
+
puts release.fetch(:url)
|
|
127
|
+
rescue Mxrb::CLI::ReleaseError => e
|
|
128
|
+
abort "[mxrb] #{e.message}"
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
when 'update'
|
|
132
|
+
check = !ARGV.delete('--check').nil?
|
|
133
|
+
show_changelog = !ARGV.delete('--changelog').nil?
|
|
134
|
+
abort 'Use only one of --check or --changelog' if check && show_changelog
|
|
135
|
+
abort "Unknown arguments: #{ARGV.join(' ')}" unless ARGV.empty?
|
|
136
|
+
begin
|
|
137
|
+
releases = Mxrb::CLI::Releases.new
|
|
138
|
+
if show_changelog
|
|
139
|
+
release = releases.changelog
|
|
140
|
+
puts "#{release.fetch(:title)}\n\n#{release.fetch(:body)}\n\n#{release.fetch(:url)}"
|
|
141
|
+
elsif check
|
|
142
|
+
status = releases.status(force: true)
|
|
143
|
+
abort '[mxrb] Could not check the latest published version' unless status.latest
|
|
144
|
+
if status.available?
|
|
145
|
+
puts "[mxrb] Update available: #{status.installed} -> #{status.latest}"
|
|
146
|
+
puts '[mxrb] Review it with `mxrb changelog`; install it with `mxrb update`.'
|
|
147
|
+
else
|
|
148
|
+
puts "[mxrb] #{status.installed} is the latest published version."
|
|
149
|
+
end
|
|
150
|
+
else
|
|
151
|
+
status = Mxrb::CLI::Updater.new(releases:).update!
|
|
152
|
+
if status.available?
|
|
153
|
+
puts "[mxrb] Updated MXRB from #{status.installed} to #{status.latest}."
|
|
154
|
+
else
|
|
155
|
+
puts "[mxrb] #{status.installed} is already the latest published version."
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
rescue Mxrb::CLI::ReleaseError => e
|
|
159
|
+
abort "[mxrb] #{e.message}"
|
|
160
|
+
end
|
|
161
|
+
|
|
73
162
|
when 'doctor'
|
|
74
163
|
json = ARGV.delete('--json')
|
|
75
164
|
root = ARGV.shift || Dir.pwd
|
|
@@ -234,6 +323,15 @@ when "generate"
|
|
|
234
323
|
ENV["MXRB_OUTPUT_PATH"] = File.expand_path(target)
|
|
235
324
|
end
|
|
236
325
|
load File.expand_path(source)
|
|
326
|
+
generated_path = target || Mxrb.last_defined_path
|
|
327
|
+
if generated_path && File.file?(generated_path)
|
|
328
|
+
result = Mxrb.validate(generated_path)
|
|
329
|
+
result.warnings.each { warn "[mxrb] warning: #{_1}" }
|
|
330
|
+
unless result.valid?
|
|
331
|
+
result.errors.each { warn "[mxrb] error: #{_1}" }
|
|
332
|
+
abort "[mxrb] Generated MPR failed validation"
|
|
333
|
+
end
|
|
334
|
+
end
|
|
237
335
|
puts "[mxrb] Generated #{target || 'project from definition'}"
|
|
238
336
|
|
|
239
337
|
when "widgets"
|
|
@@ -304,10 +402,260 @@ when "frontend"
|
|
|
304
402
|
exit 1 unless plan.safe?
|
|
305
403
|
|
|
306
404
|
when "export"
|
|
307
|
-
source = ARGV.shift or abort "Usage: mxrb export <file.mpr> <ruby-project-dir>"
|
|
308
|
-
output = ARGV.shift or abort "Usage: mxrb export <file.mpr> <ruby-project-dir>"
|
|
309
|
-
|
|
310
|
-
|
|
405
|
+
source = ARGV.shift or abort "Usage: mxrb export <file.mpr> <ruby-project-dir> [--mode mendix|ruby]"
|
|
406
|
+
output = ARGV.shift or abort "Usage: mxrb export <file.mpr> <ruby-project-dir> [--mode mendix|ruby]"
|
|
407
|
+
mode_equals = ARGV.find { _1.start_with?('--mode=') }
|
|
408
|
+
ARGV.delete(mode_equals) if mode_equals
|
|
409
|
+
mode_index = ARGV.index("--mode")
|
|
410
|
+
abort 'Use only one --mode option' if mode_equals && mode_index
|
|
411
|
+
mode = if mode_equals
|
|
412
|
+
mode_equals.split('=', 2).last
|
|
413
|
+
elsif mode_index
|
|
414
|
+
ARGV.slice!(mode_index, 2).last
|
|
415
|
+
else
|
|
416
|
+
'mendix'
|
|
417
|
+
end
|
|
418
|
+
abort "--mode requires mendix or ruby" unless %w[mendix ruby].include?(mode)
|
|
419
|
+
stack_flags = %w[--flymetothemoon --onrails].select { ARGV.delete(_1) }
|
|
420
|
+
abort 'Use only one of --flymetothemoon or --onrails' if stack_flags.size > 1
|
|
421
|
+
abort 'Ruby stack presets require --mode ruby' if stack_flags.any? && mode != 'ruby'
|
|
422
|
+
stack = stack_flags.first&.delete_prefix('--')
|
|
423
|
+
abort "Unknown arguments: #{ARGV.join(' ')}" unless ARGV.empty?
|
|
424
|
+
destination = Mxrb::Exporter.new(source, output, mode:).export!
|
|
425
|
+
Mxrb::RubyApp::Preset.apply!(destination, stack) if stack
|
|
426
|
+
suffix = stack ? " with #{stack}" : ''
|
|
427
|
+
puts "[mxrb] Exported #{mode} project#{suffix} to #{destination}"
|
|
428
|
+
|
|
429
|
+
when 'diagram-er'
|
|
430
|
+
lifecycle_action = %w[up down status destroy __serve].include?(ARGV.first) ? ARGV.shift : nil
|
|
431
|
+
domain_usage = if lifecycle_action
|
|
432
|
+
"Usage: mxrb diagram-er #{lifecycle_action} FILE.mpr [options]"
|
|
433
|
+
else
|
|
434
|
+
'Usage: mxrb diagram-er FILE.mpr [--module NAME] [--output FILE] [--port PORT] [--force]'
|
|
435
|
+
end
|
|
436
|
+
source = ARGV.shift or abort domain_usage
|
|
437
|
+
option = lambda do |name|
|
|
438
|
+
index = ARGV.index(name)
|
|
439
|
+
next unless index
|
|
440
|
+
|
|
441
|
+
abort "#{name} requires a value" unless ARGV[index + 1]
|
|
442
|
+
ARGV.slice!(index, 2).last
|
|
443
|
+
end
|
|
444
|
+
modules = []
|
|
445
|
+
modules_given = false
|
|
446
|
+
while (index = ARGV.index('--module'))
|
|
447
|
+
abort '--module requires a value' unless ARGV[index + 1]
|
|
448
|
+
modules_given = true
|
|
449
|
+
modules << ARGV.slice!(index, 2).last
|
|
450
|
+
end
|
|
451
|
+
output = option.call('--output')
|
|
452
|
+
port = option.call('--port')
|
|
453
|
+
token = option.call('--token') if lifecycle_action == '__serve'
|
|
454
|
+
state_root = option.call('--state-root') if lifecycle_action == '__serve'
|
|
455
|
+
force = !ARGV.delete('--force').nil?
|
|
456
|
+
yes = !ARGV.delete('--yes').nil?
|
|
457
|
+
json = !ARGV.delete('--json').nil?
|
|
458
|
+
begin
|
|
459
|
+
if lifecycle_action
|
|
460
|
+
lifecycle = Mxrb::DomainDiagram::Lifecycle.new(
|
|
461
|
+
source, state_root: state_root || Mxrb::DomainDiagram::Lifecycle.default_state_root,
|
|
462
|
+
executable: File.expand_path(__FILE__)
|
|
463
|
+
)
|
|
464
|
+
selected_modules = modules if modules_given
|
|
465
|
+
if lifecycle_action == '__serve' && !(output && port && token && state_root)
|
|
466
|
+
abort '__serve requires --output, --port, --token, and --state-root'
|
|
467
|
+
end
|
|
468
|
+
status = case lifecycle_action
|
|
469
|
+
when 'up'
|
|
470
|
+
abort "Unknown arguments: #{ARGV.join(' ')}" unless ARGV.empty?
|
|
471
|
+
lifecycle.up(output:, modules: selected_modules, port:, force:)
|
|
472
|
+
when 'down'
|
|
473
|
+
valid = ARGV.empty? && !output && !port && !force && !yes && !json
|
|
474
|
+
abort "Unknown arguments: #{ARGV.join(' ')}" unless valid
|
|
475
|
+
lifecycle.down
|
|
476
|
+
when 'status'
|
|
477
|
+
abort "Unknown arguments: #{ARGV.join(' ')}" unless ARGV.empty? && !output && !port && !force && !yes
|
|
478
|
+
lifecycle.status
|
|
479
|
+
when 'destroy'
|
|
480
|
+
abort "Unknown arguments: #{ARGV.join(' ')}" unless ARGV.empty? && !output && !port && !force && !json
|
|
481
|
+
lifecycle.destroy(confirm: yes)
|
|
482
|
+
when '__serve'
|
|
483
|
+
abort "Unknown arguments: #{ARGV.join(' ')}" unless ARGV.empty? && !force && !yes && !json
|
|
484
|
+
lifecycle.run_worker(output:, modules:, port:, token:)
|
|
485
|
+
exit
|
|
486
|
+
end
|
|
487
|
+
if json
|
|
488
|
+
puts JSON.pretty_generate(status.to_h)
|
|
489
|
+
else
|
|
490
|
+
puts "[mxrb] ER diagram: #{status.state}"
|
|
491
|
+
puts "[mxrb] URL: #{status.url}" if status.url
|
|
492
|
+
puts "[mxrb] Layout MPR: #{status.output}" if status.output
|
|
493
|
+
puts "[mxrb] Log: #{status.log}" if status.log
|
|
494
|
+
end
|
|
495
|
+
exit
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
abort "Unknown arguments: #{ARGV.join(' ')}" unless ARGV.empty? && !yes && !json && !token && !state_root
|
|
499
|
+
server = Mxrb::DomainDiagram::Server.new(
|
|
500
|
+
source, output:, modules:, port: port || 4568, force:
|
|
501
|
+
)
|
|
502
|
+
puts "[mxrb] ER Diagram: http://127.0.0.1:#{port || 4568}"
|
|
503
|
+
puts "[mxrb] Layout MPR: #{server.output}"
|
|
504
|
+
puts '[mxrb] Use Exportar PNG in the browser to create the diagram image.'
|
|
505
|
+
trap('INT') { Thread.new { server.shutdown } }
|
|
506
|
+
server.start
|
|
507
|
+
rescue ArgumentError => e
|
|
508
|
+
abort "[mxrb] #{e.message}"
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
when 'uml'
|
|
512
|
+
uml_usage = 'Usage: mxrb uml FILE.mpr [--export class|activity|sequence] ' \
|
|
513
|
+
'[--format mermaid|plantuml] [options]'
|
|
514
|
+
source = ARGV.shift or abort uml_usage
|
|
515
|
+
pull = lambda do |name|
|
|
516
|
+
equals = ARGV.find { _1.start_with?("#{name}=") }
|
|
517
|
+
if equals
|
|
518
|
+
ARGV.delete(equals)
|
|
519
|
+
next equals.split('=', 2).last
|
|
520
|
+
end
|
|
521
|
+
index = ARGV.index(name)
|
|
522
|
+
next unless index
|
|
523
|
+
|
|
524
|
+
abort "#{name} requires a value" unless ARGV[index + 1]
|
|
525
|
+
ARGV.slice!(index, 2).last
|
|
526
|
+
end
|
|
527
|
+
modules = []
|
|
528
|
+
loop do
|
|
529
|
+
value = pull.call('--module')
|
|
530
|
+
break unless value
|
|
531
|
+
|
|
532
|
+
modules << value
|
|
533
|
+
end
|
|
534
|
+
export = pull.call('--export')
|
|
535
|
+
format = pull.call('--format') || 'mermaid'
|
|
536
|
+
microflow = pull.call('--microflow')
|
|
537
|
+
root = pull.call('--root')
|
|
538
|
+
depth = pull.call('--depth') || 2
|
|
539
|
+
port = pull.call('--port') || 4569
|
|
540
|
+
abort "Unknown arguments: #{ARGV.join(' ')}" unless ARGV.empty?
|
|
541
|
+
abort '--format requires mermaid or plantuml' unless %w[mermaid plantuml].include?(format)
|
|
542
|
+
abort '--export requires class, activity, or sequence' if export && !%w[class activity sequence].include?(export)
|
|
543
|
+
begin
|
|
544
|
+
unless export
|
|
545
|
+
viewer_options = modules.empty? && !microflow && !root && depth.to_s == '2' && format == 'mermaid'
|
|
546
|
+
abort 'Viewer mode only accepts --port' unless viewer_options
|
|
547
|
+
|
|
548
|
+
server = Mxrb::Uml::Server.new(source, port:)
|
|
549
|
+
puts "[mxrb] UML viewer: http://127.0.0.1:#{port}"
|
|
550
|
+
puts "[mxrb] Project modeler: http://127.0.0.1:#{port}/modeler"
|
|
551
|
+
puts '[mxrb] Use Ctrl+C to stop the server.'
|
|
552
|
+
trap('INT') { Thread.new { server.shutdown } }
|
|
553
|
+
server.start
|
|
554
|
+
exit
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
project = Mxrb::Model::Project.open(source)
|
|
558
|
+
diagram = case export
|
|
559
|
+
when 'class'
|
|
560
|
+
selected = project.modules
|
|
561
|
+
unless modules.empty?
|
|
562
|
+
unknown = modules - selected.map(&:name)
|
|
563
|
+
raise ArgumentError, "unknown modules: #{unknown.join(', ')}" unless unknown.empty?
|
|
564
|
+
|
|
565
|
+
selected = selected.select { modules.include?(_1.name) }
|
|
566
|
+
end
|
|
567
|
+
Mxrb::Uml::ClassDiagram.new(selected)
|
|
568
|
+
when 'activity'
|
|
569
|
+
raise ArgumentError, '--microflow is required for activity export' if microflow.to_s.empty?
|
|
570
|
+
|
|
571
|
+
module_name, flow_name = microflow.split('.', 2)
|
|
572
|
+
flow = project.modules.find { _1.name == module_name }&.microflows&.find { _1.name == flow_name }
|
|
573
|
+
raise ArgumentError, "microflow not found: #{microflow}" unless flow
|
|
574
|
+
|
|
575
|
+
Mxrb::Uml::ActivityDiagram.new(flow)
|
|
576
|
+
when 'sequence'
|
|
577
|
+
raise ArgumentError, 'use either --root or --module for sequence export' if root && modules.any?
|
|
578
|
+
raise ArgumentError, '--root or --module is required for sequence export' unless root || modules.one?
|
|
579
|
+
|
|
580
|
+
Mxrb::Uml::SequenceDiagram.new(
|
|
581
|
+
project.semantic_index, root:, module_name: modules.first, depth:
|
|
582
|
+
)
|
|
583
|
+
end
|
|
584
|
+
puts(format == 'plantuml' ? diagram.to_plantuml : diagram.to_mermaid)
|
|
585
|
+
rescue ArgumentError, Mxrb::Error => e
|
|
586
|
+
abort "[mxrb] #{e.message}"
|
|
587
|
+
ensure
|
|
588
|
+
project&.close
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
when "run"
|
|
592
|
+
run_usage = <<~USAGE
|
|
593
|
+
Usage: mxrb run [DIR] [options]
|
|
594
|
+
|
|
595
|
+
Start the Ruby backend and React + Vite frontend together.
|
|
596
|
+
|
|
597
|
+
Options:
|
|
598
|
+
--host HOST Bind host (default: 127.0.0.1)
|
|
599
|
+
--server-port PORT Ruby backend port (default: 9292)
|
|
600
|
+
--client-port PORT React + Vite port (default: 5173)
|
|
601
|
+
--environment NAME Load .env and config/environments/NAME.env
|
|
602
|
+
--no-frontend Start only the Ruby backend
|
|
603
|
+
|
|
604
|
+
Compatibility aliases: --api-port for --server-port, --port for --client-port.
|
|
605
|
+
The global --no-progress option is optional and only suppresses progress output.
|
|
606
|
+
USAGE
|
|
607
|
+
if %w[-h --help help].include?(ARGV.first)
|
|
608
|
+
puts run_usage
|
|
609
|
+
exit
|
|
610
|
+
end
|
|
611
|
+
root = ARGV.first&.start_with?("--") ? Dir.pwd : (ARGV.shift || Dir.pwd)
|
|
612
|
+
environment_name = extract_cli_value!(ARGV, '--environment')
|
|
613
|
+
option = lambda do |names, fallback|
|
|
614
|
+
matches = Array(names).filter_map do |name|
|
|
615
|
+
index = ARGV.index(name)
|
|
616
|
+
[name, index] if index
|
|
617
|
+
end
|
|
618
|
+
abort "Use only one of #{Array(names).join(' or ')}" if matches.size > 1
|
|
619
|
+
next fallback if matches.empty?
|
|
620
|
+
|
|
621
|
+
name, index = matches.first
|
|
622
|
+
abort "#{name} requires a value" unless ARGV[index + 1]
|
|
623
|
+
ARGV.slice!(index, 2).last
|
|
624
|
+
end
|
|
625
|
+
host = option.call("--host", "127.0.0.1")
|
|
626
|
+
server_port = option.call(%w[--server-port --api-port], 9292)
|
|
627
|
+
client_port = option.call(%w[--client-port --port], 5173)
|
|
628
|
+
frontend = !ARGV.delete("--no-frontend")
|
|
629
|
+
abort "Unknown arguments: #{ARGV.join(' ')}" unless ARGV.empty?
|
|
630
|
+
environment = load_environment!(environment_name, root:)
|
|
631
|
+
supervisor = Mxrb::RubyApp::Supervisor.new(
|
|
632
|
+
root, host:, api_port: server_port, frontend_port: client_port, frontend:, environment:
|
|
633
|
+
)
|
|
634
|
+
puts "[mxrb] Environment: #{environment.name}"
|
|
635
|
+
puts "[mxrb] Ruby server: http://#{host}:#{server_port}"
|
|
636
|
+
puts "[mxrb] React client: http://#{host}:#{client_port}" if frontend
|
|
637
|
+
trap("INT") { Thread.new { supervisor.shutdown } }
|
|
638
|
+
supervisor.start
|
|
639
|
+
|
|
640
|
+
when 'env'
|
|
641
|
+
root = ARGV.first&.start_with?('--') ? Dir.pwd : (ARGV.shift || Dir.pwd)
|
|
642
|
+
environment_name = extract_cli_value!(ARGV, '--environment')
|
|
643
|
+
json = ARGV.delete('--json')
|
|
644
|
+
abort "Unknown arguments: #{ARGV.join(' ')}" unless ARGV.empty?
|
|
645
|
+
environment = load_environment!(environment_name, root:)
|
|
646
|
+
payload = {
|
|
647
|
+
environment: environment.name, requested: environment.requested_name,
|
|
648
|
+
root: environment.root, sources: environment.sources,
|
|
649
|
+
keys: environment.to_h.keys.sort
|
|
650
|
+
}
|
|
651
|
+
if json
|
|
652
|
+
puts JSON.pretty_generate(payload)
|
|
653
|
+
else
|
|
654
|
+
puts "Environment : #{payload.fetch(:environment)}"
|
|
655
|
+
puts "Root : #{payload.fetch(:root)}"
|
|
656
|
+
payload.fetch(:sources).each { puts "Source : #{_1}" }
|
|
657
|
+
puts "Keys : #{payload.fetch(:keys).join(', ')}"
|
|
658
|
+
end
|
|
311
659
|
|
|
312
660
|
when "validate"
|
|
313
661
|
path = ARGV.shift or abort "Usage: mxrb validate <file.mpr>"
|
|
@@ -625,6 +973,71 @@ when "oql"
|
|
|
625
973
|
end
|
|
626
974
|
end
|
|
627
975
|
|
|
976
|
+
when "query"
|
|
977
|
+
usage = 'Usage: mxrb query "SELECT ..." --from sql|oql ' \
|
|
978
|
+
'[--to oql|sql] [--dialect ansi|postgresql|sql_server] ' \
|
|
979
|
+
'[--project FILE.mpr] [--input FILE] [--json]'
|
|
980
|
+
option = lambda do |name|
|
|
981
|
+
index = ARGV.index(name)
|
|
982
|
+
next unless index
|
|
983
|
+
|
|
984
|
+
abort "#{name} requires a value" unless ARGV[index + 1]
|
|
985
|
+
ARGV.slice!(index, 2).last
|
|
986
|
+
end
|
|
987
|
+
source_language = option.call('--from') || abort('--from is required: use sql or oql')
|
|
988
|
+
abort '--from must be sql or oql' unless %w[sql oql].include?(source_language)
|
|
989
|
+
|
|
990
|
+
target_language = option.call('--to') || { 'sql' => 'oql', 'oql' => 'sql' }.fetch(source_language)
|
|
991
|
+
unless [%w[sql oql], %w[oql sql]].include?([source_language, target_language])
|
|
992
|
+
abort 'Supported query conversions are sql to oql and oql to sql'
|
|
993
|
+
end
|
|
994
|
+
dialect = (option.call('--dialect') || 'postgresql').to_sym
|
|
995
|
+
project_path = option.call('--project')
|
|
996
|
+
abort '--project applies only when converting SQL to OQL' if project_path && source_language != 'sql'
|
|
997
|
+
|
|
998
|
+
input = option.call('--input')
|
|
999
|
+
json = !ARGV.delete('--json').nil?
|
|
1000
|
+
abort 'Query must be provided either as an argument or through --input' if input && !ARGV.empty?
|
|
1001
|
+
source = if input == '-'
|
|
1002
|
+
$stdin.read
|
|
1003
|
+
elsif input
|
|
1004
|
+
File.read(input)
|
|
1005
|
+
else
|
|
1006
|
+
ARGV.shift || abort(usage)
|
|
1007
|
+
end
|
|
1008
|
+
abort "Unknown arguments: #{ARGV.join(' ')}" unless ARGV.empty?
|
|
1009
|
+
begin
|
|
1010
|
+
projection = if source_language == 'sql'
|
|
1011
|
+
if project_path
|
|
1012
|
+
Mxrb.open(project_path) { _1.sql_to_oql(source, dialect:) }
|
|
1013
|
+
else
|
|
1014
|
+
Mxrb::Oql::ReverseTranslator.new(dialect:).translate(source)
|
|
1015
|
+
end
|
|
1016
|
+
else
|
|
1017
|
+
Mxrb::Oql::Translator.new(dialect:).translate_source(source)
|
|
1018
|
+
end
|
|
1019
|
+
rescue ArgumentError, Mxrb::Error, Errno::ENOENT => e
|
|
1020
|
+
abort "[mxrb] error: #{e.message}"
|
|
1021
|
+
end
|
|
1022
|
+
sql = projection.sql
|
|
1023
|
+
oql = source_language == 'oql' ? projection.query.oql : projection.oql
|
|
1024
|
+
payload = {
|
|
1025
|
+
supported: projection.supported?, from: source_language, to: target_language,
|
|
1026
|
+
sql:, oql:,
|
|
1027
|
+
dialect: projection.dialect, confidence: projection.confidence,
|
|
1028
|
+
parameters: projection.parameters, warnings: projection.warnings
|
|
1029
|
+
}
|
|
1030
|
+
if json
|
|
1031
|
+
puts JSON.pretty_generate(payload)
|
|
1032
|
+
else
|
|
1033
|
+
puts "#{source_language.upcase} source:"
|
|
1034
|
+
puts source
|
|
1035
|
+
puts "#{target_language.upcase} (#{projection.dialect}, #{projection.confidence}):"
|
|
1036
|
+
puts((target_language == 'sql' ? sql : oql) || '(not generated)')
|
|
1037
|
+
projection.warnings.each { warn "[mxrb] warning: #{_1}" }
|
|
1038
|
+
end
|
|
1039
|
+
exit 1 unless projection.supported?
|
|
1040
|
+
|
|
628
1041
|
when "analyze"
|
|
629
1042
|
option = lambda do |name|
|
|
630
1043
|
index = ARGV.index(name)
|
|
@@ -956,6 +1369,7 @@ when "test"
|
|
|
956
1369
|
plan_only = ARGV.delete("--plan")
|
|
957
1370
|
docker = ARGV.delete("--docker")
|
|
958
1371
|
native = ARGV.delete("--native")
|
|
1372
|
+
environment_name = extract_cli_value!(ARGV, '--environment')
|
|
959
1373
|
abort "--native and --docker are mutually exclusive" if native && docker
|
|
960
1374
|
report_option = lambda do |name|
|
|
961
1375
|
index = ARGV.index(name)
|
|
@@ -986,9 +1400,11 @@ when "test"
|
|
|
986
1400
|
else
|
|
987
1401
|
Mxrb::Runtime::Executor
|
|
988
1402
|
end
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
1403
|
+
environment = load_environment!(environment_name, root: File.dirname(File.expand_path(path)))
|
|
1404
|
+
puts "[mxrb] Environment: #{environment.name}"
|
|
1405
|
+
execution = environment.with do
|
|
1406
|
+
executor.new(path, definition, plan: plan, output: $stdout).run
|
|
1407
|
+
end
|
|
992
1408
|
execution.result.tests.each do |test|
|
|
993
1409
|
puts "[#{test.passed? ? 'pass' : 'fail'}] #{test.name}: #{test.message}"
|
|
994
1410
|
end
|
|
@@ -1485,13 +1901,29 @@ when "tree"
|
|
|
1485
1901
|
end
|
|
1486
1902
|
|
|
1487
1903
|
when "init"
|
|
1488
|
-
name = ARGV.shift or abort "Usage: mxrb init <project_name> [--mxrb-path DIR]"
|
|
1904
|
+
name = ARGV.shift or abort "Usage: mxrb init <project_name> [--mode mendix|ruby] [--mxrb-path DIR]"
|
|
1905
|
+
mode_equals = ARGV.find { _1.start_with?('--mode=') }
|
|
1906
|
+
ARGV.delete(mode_equals) if mode_equals
|
|
1907
|
+
mode_index = ARGV.index('--mode')
|
|
1908
|
+
abort 'Use only one --mode option' if mode_equals && mode_index
|
|
1909
|
+
mode = if mode_equals
|
|
1910
|
+
mode_equals.split('=', 2).last
|
|
1911
|
+
elsif mode_index
|
|
1912
|
+
ARGV.slice!(mode_index, 2).last
|
|
1913
|
+
else
|
|
1914
|
+
'mendix'
|
|
1915
|
+
end
|
|
1916
|
+
abort '--mode requires mendix or ruby' unless %w[mendix ruby].include?(mode)
|
|
1917
|
+
stack_flags = %w[--flymetothemoon --onrails].select { ARGV.delete(_1) }
|
|
1918
|
+
abort 'Use only one of --flymetothemoon or --onrails' if stack_flags.size > 1
|
|
1919
|
+
abort 'Ruby stack presets require --mode ruby' if stack_flags.any? && mode != 'ruby'
|
|
1920
|
+
stack = stack_flags.first&.delete_prefix('--')
|
|
1489
1921
|
path_index = ARGV.index('--mxrb-path')
|
|
1490
1922
|
mxrb_path = path_index ? ARGV.slice!(path_index, 2).last : nil
|
|
1491
1923
|
abort '--mxrb-path requires a value' if path_index && mxrb_path.nil?
|
|
1492
1924
|
abort "Unknown arguments: #{ARGV.join(' ')}" unless ARGV.empty?
|
|
1493
1925
|
begin
|
|
1494
|
-
result = Mxrb::Initializer.new(name, mxrb_path:).scaffold
|
|
1926
|
+
result = Mxrb::Initializer.new(name, mxrb_path:, mode:, stack:).scaffold
|
|
1495
1927
|
rescue ArgumentError => e
|
|
1496
1928
|
abort "[mxrb] error: #{e.message}"
|
|
1497
1929
|
end
|
|
@@ -1499,13 +1931,24 @@ when "init"
|
|
|
1499
1931
|
puts "\nDone. Next steps:"
|
|
1500
1932
|
puts " cd #{result.root}"
|
|
1501
1933
|
puts " bundle install"
|
|
1502
|
-
|
|
1934
|
+
if mode == 'ruby'
|
|
1935
|
+
puts ' npm install --prefix frontend'
|
|
1936
|
+
puts ' bundle exec mxrb run .'
|
|
1937
|
+
puts ' bundle exec ruby project.rb # materialize build/*.mpr for Mendix'
|
|
1938
|
+
else
|
|
1939
|
+
puts ' bundle exec mxrb generate project.rb'
|
|
1940
|
+
end
|
|
1503
1941
|
|
|
1504
1942
|
else
|
|
1943
|
+
unless ENV['MXRB_LEGACY_HELP'] == '1'
|
|
1944
|
+
abort "[mxrb] Unknown command #{command.inspect}. Run `mxrb --commands` to list commands " \
|
|
1945
|
+
'or `mxrb --help` for guided examples.'
|
|
1946
|
+
end
|
|
1505
1947
|
puts <<~USAGE
|
|
1506
1948
|
mxrb — Pure-Ruby Mendix .mpr toolkit
|
|
1507
1949
|
|
|
1508
1950
|
Commands:
|
|
1951
|
+
--no-progress Disable interactive progress rendering
|
|
1509
1952
|
--version, -v Show the installed MXRB version
|
|
1510
1953
|
doctor [DIR] [--json] Check project files and local toolchain
|
|
1511
1954
|
benchmark <file.mpr> Measure open, index and validation time
|
|
@@ -1530,6 +1973,11 @@ else
|
|
|
1530
1973
|
frontend migrate <file.mpr> Preview frontend schema/layout/theme migration
|
|
1531
1974
|
[--apply] [--json] Apply only a safe plan or emit structured output
|
|
1532
1975
|
export <file.mpr> <directory> Convert an MPR to editable Ruby
|
|
1976
|
+
--mode mendix|ruby Mendix DSL (default) or executable Ruby app
|
|
1977
|
+
run [directory] Start Ruby API and React + Vite together
|
|
1978
|
+
--host HOST --port PORT Vite host/port (default 127.0.0.1:5173)
|
|
1979
|
+
--api-port PORT Ruby API port (default 9292)
|
|
1980
|
+
--no-frontend Start only the Ruby API
|
|
1533
1981
|
validate <file.mpr> Check MPR structure, hashes and v2 contents
|
|
1534
1982
|
preflight <file.mpr> [--json] Audit native compiler/runtime compatibility
|
|
1535
1983
|
compare <left.mpr> <right.mpr> Compare structural MPR snapshots
|
data/docs/de-DE/README.md
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
- [Ruby-First-Roadmap](ruby-first-roadmap.md)
|
|
14
14
|
- [Validierungsmatrix](validation-matrix.md)
|
|
15
15
|
- [Nativer Compiler und Runtime](compiler.md)
|
|
16
|
+
- [Ruby-Runtime ohne Java und Umgebungen](runtime-ruby.md)
|
|
16
17
|
- [Qualitätsbericht für Build und Runtime](native-runtime-quality-report.md)
|
|
17
18
|
- [Projekte erstellen und bearbeiten](writing.md)
|
|
18
19
|
- [Projekt-Scaffolds](scaffolds.md)
|
data/docs/de-DE/oql-sql.md
CHANGED
|
@@ -44,6 +44,48 @@ exakten Mendix Runtime geprüft werden. Assoziationspfad-Joins gelten als nicht
|
|
|
44
44
|
unterstützt, solange Runtime-Speichermetadaten den korrekten Join nicht
|
|
45
45
|
beweisen können.
|
|
46
46
|
|
|
47
|
+
## Sichere Konvertierung von SQL nach OQL
|
|
48
|
+
|
|
49
|
+
Der Rückweg akzeptiert eine schreibgeschützte `SELECT`-Teilmenge in PostgreSQL,
|
|
50
|
+
SQL Server oder ANSI und erzeugt logisches OQL. Mit dem Projekt werden die
|
|
51
|
+
exakte Groß-/Kleinschreibung von Modulen, Entitäten und Attributen
|
|
52
|
+
wiederhergestellt:
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
projection = Mxrb.open("Shop.mpr") do |project|
|
|
56
|
+
project.sql_to_oql(
|
|
57
|
+
'SELECT p."name" FROM "shop$product" p WHERE p."name" = :Name',
|
|
58
|
+
dialect: :postgresql
|
|
59
|
+
)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
puts projection.oql if projection.supported?
|
|
63
|
+
# SELECT p/Name FROM Shop.Product p WHERE p/Name = $Name
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Der einheitliche Befehl `query` konvertiert in beide Richtungen. `--input -`
|
|
67
|
+
liest stdin und `--json` liefert das typisierte Ergebnis:
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
bundle exec mxrb query \
|
|
71
|
+
'SELECT p."name" FROM "shop$product" p WHERE p."name" = :Name' \
|
|
72
|
+
--from sql --to oql --project Shop.mpr --dialect postgresql
|
|
73
|
+
bundle exec mxrb query 'SELECT p/Name FROM Shop.Product p' \
|
|
74
|
+
--from oql --to sql --dialect sql_server
|
|
75
|
+
bundle exec mxrb query --input query.sql --from sql --dialect sql_server --json
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Die Teilmenge umfasst Aliase, explizite Joins, kommaseparierte Quellen,
|
|
79
|
+
`WHERE`, `GROUP BY`, `HAVING`, `UNION`, `ORDER BY`, `LIMIT`/`OFFSET`, bekannte
|
|
80
|
+
OQL-Funktionen und benannte Parameter (`:Name`, `@Name` oder `$Name`). Physische
|
|
81
|
+
Tabellen `module$entity` werden zu `Module.Entity`; ohne `--project` wird die
|
|
82
|
+
Schreibweise abgeleitet und das Ergebnis erhält die Vertrauensstufe `inferred`.
|
|
83
|
+
|
|
84
|
+
Schreiboperationen, mehrere Anweisungen, CTEs, Tabellen-Unterabfragen in
|
|
85
|
+
`FROM`/`JOIN`, positionale Parameter, unbekannte Funktionen und Erweiterungen ohne sichere OQL-Entsprechung wie
|
|
86
|
+
`ILIKE`, `DISTINCT ON`, `TOP`, `::` und die Verkettung `||` liefern
|
|
87
|
+
`supported? == false` mit einer Erklärung in `warnings`.
|
|
88
|
+
|
|
47
89
|
## Dialektabhängige Analyse
|
|
48
90
|
|
|
49
91
|
`Oql::Analyzer` erkennt Kosten- und Portabilitätsmuster im Originaltext,
|