mxrb 0.1.3 → 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 +455 -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/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/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/page_bundle_compiler.rb +13 -4
- 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 +43 -9
- data/lib/mxrb/environment.rb +226 -0
- data/lib/mxrb/exporter.rb +89 -15
- data/lib/mxrb/http/server.rb +107 -0
- data/lib/mxrb/initializer.rb +80 -9
- data/lib/mxrb/integrity/validator.rb +14 -0
- 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 +28 -2
- data/lib/mxrb/model/microflow.rb +3 -1
- 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/oql/reverse_translator.rb +394 -0
- data/lib/mxrb/oql/server.rb +4 -8
- data/lib/mxrb/oql.rb +23 -1
- 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/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 +200 -24
- data/lib/mxrb.rb +26 -1
- metadata +156 -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,16 +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
|
|
|
67
86
|
progress_disabled = ARGV.delete("--no-progress")
|
|
68
87
|
command = ARGV.shift
|
|
88
|
+
command = 'diagram-er' if command == 'domain-model'
|
|
69
89
|
Mxrb::Progress.configure(enabled: false) if progress_disabled || ARGV.include?("--json")
|
|
70
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
|
|
112
|
+
|
|
71
113
|
case command
|
|
72
114
|
when '--version', '-v'
|
|
73
115
|
puts "mxrb #{Mxrb::VERSION}"
|
|
74
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
|
+
|
|
75
162
|
when 'doctor'
|
|
76
163
|
json = ARGV.delete('--json')
|
|
77
164
|
root = ARGV.shift || Dir.pwd
|
|
@@ -236,6 +323,15 @@ when "generate"
|
|
|
236
323
|
ENV["MXRB_OUTPUT_PATH"] = File.expand_path(target)
|
|
237
324
|
end
|
|
238
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
|
|
239
335
|
puts "[mxrb] Generated #{target || 'project from definition'}"
|
|
240
336
|
|
|
241
337
|
when "widgets"
|
|
@@ -306,10 +402,260 @@ when "frontend"
|
|
|
306
402
|
exit 1 unless plan.safe?
|
|
307
403
|
|
|
308
404
|
when "export"
|
|
309
|
-
source = ARGV.shift or abort "Usage: mxrb export <file.mpr> <ruby-project-dir>"
|
|
310
|
-
output = ARGV.shift or abort "Usage: mxrb export <file.mpr> <ruby-project-dir>"
|
|
311
|
-
|
|
312
|
-
|
|
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
|
|
313
659
|
|
|
314
660
|
when "validate"
|
|
315
661
|
path = ARGV.shift or abort "Usage: mxrb validate <file.mpr>"
|
|
@@ -627,6 +973,71 @@ when "oql"
|
|
|
627
973
|
end
|
|
628
974
|
end
|
|
629
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
|
+
|
|
630
1041
|
when "analyze"
|
|
631
1042
|
option = lambda do |name|
|
|
632
1043
|
index = ARGV.index(name)
|
|
@@ -958,6 +1369,7 @@ when "test"
|
|
|
958
1369
|
plan_only = ARGV.delete("--plan")
|
|
959
1370
|
docker = ARGV.delete("--docker")
|
|
960
1371
|
native = ARGV.delete("--native")
|
|
1372
|
+
environment_name = extract_cli_value!(ARGV, '--environment')
|
|
961
1373
|
abort "--native and --docker are mutually exclusive" if native && docker
|
|
962
1374
|
report_option = lambda do |name|
|
|
963
1375
|
index = ARGV.index(name)
|
|
@@ -988,9 +1400,11 @@ when "test"
|
|
|
988
1400
|
else
|
|
989
1401
|
Mxrb::Runtime::Executor
|
|
990
1402
|
end
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
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
|
|
994
1408
|
execution.result.tests.each do |test|
|
|
995
1409
|
puts "[#{test.passed? ? 'pass' : 'fail'}] #{test.name}: #{test.message}"
|
|
996
1410
|
end
|
|
@@ -1487,13 +1901,29 @@ when "tree"
|
|
|
1487
1901
|
end
|
|
1488
1902
|
|
|
1489
1903
|
when "init"
|
|
1490
|
-
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('--')
|
|
1491
1921
|
path_index = ARGV.index('--mxrb-path')
|
|
1492
1922
|
mxrb_path = path_index ? ARGV.slice!(path_index, 2).last : nil
|
|
1493
1923
|
abort '--mxrb-path requires a value' if path_index && mxrb_path.nil?
|
|
1494
1924
|
abort "Unknown arguments: #{ARGV.join(' ')}" unless ARGV.empty?
|
|
1495
1925
|
begin
|
|
1496
|
-
result = Mxrb::Initializer.new(name, mxrb_path:).scaffold
|
|
1926
|
+
result = Mxrb::Initializer.new(name, mxrb_path:, mode:, stack:).scaffold
|
|
1497
1927
|
rescue ArgumentError => e
|
|
1498
1928
|
abort "[mxrb] error: #{e.message}"
|
|
1499
1929
|
end
|
|
@@ -1501,9 +1931,19 @@ when "init"
|
|
|
1501
1931
|
puts "\nDone. Next steps:"
|
|
1502
1932
|
puts " cd #{result.root}"
|
|
1503
1933
|
puts " bundle install"
|
|
1504
|
-
|
|
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
|
|
1505
1941
|
|
|
1506
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
|
|
1507
1947
|
puts <<~USAGE
|
|
1508
1948
|
mxrb — Pure-Ruby Mendix .mpr toolkit
|
|
1509
1949
|
|
|
@@ -1533,6 +1973,11 @@ else
|
|
|
1533
1973
|
frontend migrate <file.mpr> Preview frontend schema/layout/theme migration
|
|
1534
1974
|
[--apply] [--json] Apply only a safe plan or emit structured output
|
|
1535
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
|
|
1536
1981
|
validate <file.mpr> Check MPR structure, hashes and v2 contents
|
|
1537
1982
|
preflight <file.mpr> [--json] Audit native compiler/runtime compatibility
|
|
1538
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,
|