mxrb 0.1.0
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 +7 -0
- data/LICENSE +21 -0
- data/README.de-DE.md +108 -0
- data/README.md +172 -0
- data/README.pt-BR.md +109 -0
- data/bin/mxrb +1613 -0
- data/docs/README.md +10 -0
- data/docs/de-DE/README.md +24 -0
- data/docs/de-DE/architectural-patterns.md +26 -0
- data/docs/de-DE/architectural-standard.md +48 -0
- data/docs/de-DE/architecture.md +76 -0
- data/docs/de-DE/compiler.md +162 -0
- data/docs/de-DE/conventions.md +19 -0
- data/docs/de-DE/design-system.md +52 -0
- data/docs/de-DE/entity-dsl.md +53 -0
- data/docs/de-DE/native-runtime-quality-report.md +74 -0
- data/docs/de-DE/oql-sql.md +211 -0
- data/docs/de-DE/platform-api-integration.md +36 -0
- data/docs/de-DE/platform-operations.md +243 -0
- data/docs/de-DE/project-structure.md +32 -0
- data/docs/de-DE/ruby-first-roadmap.md +116 -0
- data/docs/de-DE/scaffolds.md +59 -0
- data/docs/de-DE/semantic-refactoring.md +56 -0
- data/docs/de-DE/team-server.md +33 -0
- data/docs/de-DE/validation-matrix.md +64 -0
- data/docs/de-DE/vetclinic-acceptance.md +24 -0
- data/docs/de-DE/writing.md +138 -0
- data/docs/en-US/README.md +24 -0
- data/docs/en-US/architectural-patterns.md +151 -0
- data/docs/en-US/architectural-standard.md +89 -0
- data/docs/en-US/architecture.md +170 -0
- data/docs/en-US/compiler.md +157 -0
- data/docs/en-US/conventions.md +82 -0
- data/docs/en-US/design-system.md +163 -0
- data/docs/en-US/entity-dsl.md +53 -0
- data/docs/en-US/native-runtime-quality-report.md +73 -0
- data/docs/en-US/oql-sql.md +201 -0
- data/docs/en-US/platform-api-integration.md +36 -0
- data/docs/en-US/platform-operations.md +244 -0
- data/docs/en-US/project-structure.md +49 -0
- data/docs/en-US/ruby-first-roadmap.md +186 -0
- data/docs/en-US/scaffolds.md +57 -0
- data/docs/en-US/semantic-refactoring.md +198 -0
- data/docs/en-US/team-server.md +32 -0
- data/docs/en-US/validation-matrix.md +257 -0
- data/docs/en-US/vetclinic-acceptance.md +23 -0
- data/docs/en-US/writing.md +655 -0
- data/docs/pt-BR/README.md +24 -0
- data/docs/pt-BR/architectural-patterns.md +25 -0
- data/docs/pt-BR/architectural-standard.md +533 -0
- data/docs/pt-BR/architecture.md +300 -0
- data/docs/pt-BR/compiler.md +162 -0
- data/docs/pt-BR/conventions.md +19 -0
- data/docs/pt-BR/design-system.md +65 -0
- data/docs/pt-BR/entity-dsl.md +116 -0
- data/docs/pt-BR/native-runtime-quality-report.md +73 -0
- data/docs/pt-BR/oql-sql.md +208 -0
- data/docs/pt-BR/platform-api-integration.md +36 -0
- data/docs/pt-BR/platform-operations.md +260 -0
- data/docs/pt-BR/project-structure.md +32 -0
- data/docs/pt-BR/ruby-first-roadmap.md +239 -0
- data/docs/pt-BR/scaffolds.md +104 -0
- data/docs/pt-BR/semantic-refactoring.md +55 -0
- data/docs/pt-BR/team-server.md +59 -0
- data/docs/pt-BR/validation-matrix.md +86 -0
- data/docs/pt-BR/vetclinic-acceptance.md +50 -0
- data/docs/pt-BR/writing.md +177 -0
- data/examples/sudoku_evaluation.rb +14 -0
- data/examples/sudoku_functional_test.rb +28 -0
- data/lib/mxrb/architecture/graph.rb +124 -0
- data/lib/mxrb/architecture/validator.rb +98 -0
- data/lib/mxrb/benchmark.rb +33 -0
- data/lib/mxrb/compare.rb +390 -0
- data/lib/mxrb/compiler/adapter.rb +96 -0
- data/lib/mxrb/compiler/artifact_document_compiler.rb +102 -0
- data/lib/mxrb/compiler/artifact_materializer.rb +53 -0
- data/lib/mxrb/compiler/client_model_materializer.rb +42 -0
- data/lib/mxrb/compiler/code_action_document_compiler.rb +64 -0
- data/lib/mxrb/compiler/code_action_materializer.rb +35 -0
- data/lib/mxrb/compiler/code_action_type_compiler.rb +32 -0
- data/lib/mxrb/compiler/combo_box_bundle_compiler.rb +314 -0
- data/lib/mxrb/compiler/compatibility_analyzer.rb +169 -0
- data/lib/mxrb/compiler/constants_materializer.rb +111 -0
- data/lib/mxrb/compiler/data_grid_bundle_compiler.rb +290 -0
- data/lib/mxrb/compiler/database_connector_action_compiler.rb +280 -0
- data/lib/mxrb/compiler/deployment_asset_copier.rb +60 -0
- data/lib/mxrb/compiler/deployment_bootstrapper.rb +208 -0
- data/lib/mxrb/compiler/deployment_materializer.rb +43 -0
- data/lib/mxrb/compiler/deployment_metadata.rb +64 -0
- data/lib/mxrb/compiler/domain_document_compiler.rb +153 -0
- data/lib/mxrb/compiler/domain_model_materializer.rb +35 -0
- data/lib/mxrb/compiler/domain_security_compiler.rb +82 -0
- data/lib/mxrb/compiler/gallery_bundle_compiler.rb +190 -0
- data/lib/mxrb/compiler/generic_widget_bundle_compiler.rb +281 -0
- data/lib/mxrb/compiler/image_bundle_compiler.rb +216 -0
- data/lib/mxrb/compiler/java_proxy_generator.rb +509 -0
- data/lib/mxrb/compiler/legacy_data_grid_compiler.rb +267 -0
- data/lib/mxrb/compiler/legacy_page_builder.rb +287 -0
- data/lib/mxrb/compiler/mda.rb +99 -0
- data/lib/mxrb/compiler/microflow_document_compiler.rb +85 -0
- data/lib/mxrb/compiler/microflow_materializer.rb +48 -0
- data/lib/mxrb/compiler/microflow_node_compiler.rb +250 -0
- data/lib/mxrb/compiler/model_package.rb +116 -0
- data/lib/mxrb/compiler/model_values.rb +67 -0
- data/lib/mxrb/compiler/nanoflow_program_compiler.rb +483 -0
- data/lib/mxrb/compiler/navigation_document_compiler.rb +93 -0
- data/lib/mxrb/compiler/packager.rb +100 -0
- data/lib/mxrb/compiler/page_bundle_builder.rb +56 -0
- data/lib/mxrb/compiler/page_bundle_compiler.rb +2004 -0
- data/lib/mxrb/compiler/page_document_compiler.rb +77 -0
- data/lib/mxrb/compiler/portable_packager.rb +356 -0
- data/lib/mxrb/compiler/project_jar_archive.rb +84 -0
- data/lib/mxrb/compiler/project_jar_builder.rb +121 -0
- data/lib/mxrb/compiler/project_materializer.rb +139 -0
- data/lib/mxrb/compiler/project_model_orderer.rb +52 -0
- data/lib/mxrb/compiler/runtime_data_types.rb +31 -0
- data/lib/mxrb/compiler/runtime_model_schema.rb +90 -0
- data/lib/mxrb/compiler/schemas/runtime-10.24.0.73019.json +1052 -0
- data/lib/mxrb/compiler/schemas/runtime-11.json +1215 -0
- data/lib/mxrb/compiler/schemas/runtime-6.10.8.json +1148 -0
- data/lib/mxrb/compiler/schemas/runtime-7.17.0.json +1144 -0
- data/lib/mxrb/compiler/schemas/runtime-7.5.0.json +1215 -0
- data/lib/mxrb/compiler/schemas/runtime-9.6.1.29396.json +868 -0
- data/lib/mxrb/compiler/schemas/system-model-10.24.0.73019.b64 +1135 -0
- data/lib/mxrb/compiler/schemas/system-model-11.12.1.b64 +815 -0
- data/lib/mxrb/compiler/schemas/system-model-6.10.8.b64 +497 -0
- data/lib/mxrb/compiler/schemas/system-model-7.17.0.b64 +519 -0
- data/lib/mxrb/compiler/schemas/system-model-7.5.0.b64 +504 -0
- data/lib/mxrb/compiler/schemas/system-model-9.6.1.29396.b64 +816 -0
- data/lib/mxrb/compiler/security_materializer.rb +104 -0
- data/lib/mxrb/compiler/settings_document_compiler.rb +45 -0
- data/lib/mxrb/compiler/settings_materializer.rb +25 -0
- data/lib/mxrb/compiler/source_model.rb +128 -0
- data/lib/mxrb/compiler/system_model_seed.rb +88 -0
- data/lib/mxrb/compiler/system_queue_materializer.rb +54 -0
- data/lib/mxrb/compiler/system_text_materializer.rb +49 -0
- data/lib/mxrb/compiler/translation_materializer.rb +95 -0
- data/lib/mxrb/compiler/web_bundle_builder.rb +155 -0
- data/lib/mxrb/compiler/web_list_data_source.rb +139 -0
- data/lib/mxrb/compiler/web_operation_compiler.rb +614 -0
- data/lib/mxrb/compiler/web_shell_materializer.rb +194 -0
- data/lib/mxrb/compiler/widget_package_extractor.rb +63 -0
- data/lib/mxrb/doctor.rb +116 -0
- data/lib/mxrb/dsl/builder.rb +1636 -0
- data/lib/mxrb/errors.rb +18 -0
- data/lib/mxrb/evaluation.rb +131 -0
- data/lib/mxrb/exporter.rb +1716 -0
- data/lib/mxrb/frontend/migrator.rb +775 -0
- data/lib/mxrb/functional.rb +307 -0
- data/lib/mxrb/github/annotator.rb +161 -0
- data/lib/mxrb/initializer.rb +257 -0
- data/lib/mxrb/integrity/validator.rb +136 -0
- data/lib/mxrb/io/bson_codec.rb +145 -0
- data/lib/mxrb/io/mpr_file.rb +558 -0
- data/lib/mxrb/io/mxunit_codec.rb +42 -0
- data/lib/mxrb/marketplace.rb +380 -0
- data/lib/mxrb/model/association.rb +98 -0
- data/lib/mxrb/model/attribute.rb +100 -0
- data/lib/mxrb/model/connector.rb +17 -0
- data/lib/mxrb/model/design_materializer.rb +133 -0
- data/lib/mxrb/model/design_migration.rb +126 -0
- data/lib/mxrb/model/design_system.rb +111 -0
- data/lib/mxrb/model/domain_model.rb +51 -0
- data/lib/mxrb/model/entity.rb +180 -0
- data/lib/mxrb/model/menu.rb +38 -0
- data/lib/mxrb/model/microflow.rb +100 -0
- data/lib/mxrb/model/module.rb +142 -0
- data/lib/mxrb/model/navigation.rb +127 -0
- data/lib/mxrb/model/page.rb +410 -0
- data/lib/mxrb/model/project.rb +187 -0
- data/lib/mxrb/model/unit.rb +48 -0
- data/lib/mxrb/module_initializer.rb +75 -0
- data/lib/mxrb/official_marketplace/content_api.rb +292 -0
- data/lib/mxrb/official_marketplace/dependency_resolver.rb +329 -0
- data/lib/mxrb/official_marketplace/lifecycle.rb +367 -0
- data/lib/mxrb/official_marketplace/module_package_importer.rb +318 -0
- data/lib/mxrb/official_marketplace/widget_package_installer.rb +414 -0
- data/lib/mxrb/official_marketplace.rb +720 -0
- data/lib/mxrb/oql/analyzer.rb +155 -0
- data/lib/mxrb/oql/index_advisor.rb +85 -0
- data/lib/mxrb/oql/plan_analyzer.rb +185 -0
- data/lib/mxrb/oql/server.rb +132 -0
- data/lib/mxrb/oql/sql_server_plan_analyzer.rb +190 -0
- data/lib/mxrb/oql/sql_server_workload_analyzer.rb +80 -0
- data/lib/mxrb/oql/workload_analyzer.rb +175 -0
- data/lib/mxrb/oql/workload_baseline.rb +60 -0
- data/lib/mxrb/oql.rb +424 -0
- data/lib/mxrb/project_lifecycle.rb +76 -0
- data/lib/mxrb/protocols/plan.rb +86 -0
- data/lib/mxrb/protocols.rb +123 -0
- data/lib/mxrb/runtime/database_workspace.rb +677 -0
- data/lib/mxrb/runtime/docker_executor.rb +41 -0
- data/lib/mxrb/runtime/docker_workspace.rb +29 -0
- data/lib/mxrb/runtime/executor.rb +169 -0
- data/lib/mxrb/runtime/java_locator.rb +26 -0
- data/lib/mxrb/runtime/native.rb +474 -0
- data/lib/mxrb/runtime/sql_server_database.rb +146 -0
- data/lib/mxrb/runtime/toolchain.rb +82 -0
- data/lib/mxrb/scaffold/cli.rb +113 -0
- data/lib/mxrb/scaffold/generator.rb +246 -0
- data/lib/mxrb/scaffold/help.rb +80 -0
- data/lib/mxrb/scaffold/page_templates.rb +54 -0
- data/lib/mxrb/scaffold/recipes.rb +198 -0
- data/lib/mxrb/scaffold/registry.rb +82 -0
- data/lib/mxrb/scaffold/templates.rb +723 -0
- data/lib/mxrb/scaffold/transaction.rb +84 -0
- data/lib/mxrb/schema/tables.rb +55 -0
- data/lib/mxrb/semantic/analyzer.rb +473 -0
- data/lib/mxrb/semantic/batch_plan.rb +68 -0
- data/lib/mxrb/semantic/domain_mutator.rb +419 -0
- data/lib/mxrb/semantic/embedder.rb +51 -0
- data/lib/mxrb/semantic/extractor.rb +290 -0
- data/lib/mxrb/semantic/index.rb +623 -0
- data/lib/mxrb/semantic/inliner.rb +216 -0
- data/lib/mxrb/semantic/mover.rb +153 -0
- data/lib/mxrb/semantic/onnx_embedder.rb +34 -0
- data/lib/mxrb/semantic/remover.rb +70 -0
- data/lib/mxrb/semantic/renamer.rb +211 -0
- data/lib/mxrb/semantic/tfidf_embedder.rb +46 -0
- data/lib/mxrb/semantic/vec_store.rb +75 -0
- data/lib/mxrb/team_server.rb +390 -0
- data/lib/mxrb/templates/project/10.24.0.73019.json +32 -0
- data/lib/mxrb/templates/project/11.12.1.json +32 -0
- data/lib/mxrb/templates/project/6.10.8.json +50 -0
- data/lib/mxrb/templates/project/7.17.0.json +50 -0
- data/lib/mxrb/templates/project/7.5.0.json +50 -0
- data/lib/mxrb/templates/project/9.6.1.29396.json +50 -0
- data/lib/mxrb/version.rb +5 -0
- data/lib/mxrb/widget_package.rb +338 -0
- data/lib/mxrb/widget_synchronizer.rb +31 -0
- data/lib/mxrb/writer.rb +3775 -0
- data/lib/mxrb.rb +188 -0
- data/marketplace/catalog.json +10 -0
- data/marketplace/modules/shared-kernel/domain/README.md +4 -0
- data/marketplace/modules/shared-kernel/module.rb +5 -0
- data/marketplace/modules/shared-kernel/mxrb-module.json +9 -0
- metadata +447 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
|
|
5
|
+
module Mxrb
|
|
6
|
+
module Compiler
|
|
7
|
+
# Copies project-owned libraries, resources, and compiled theme assets into deployment.
|
|
8
|
+
class DeploymentAssetCopier
|
|
9
|
+
include ModelValues
|
|
10
|
+
|
|
11
|
+
SAFE_IDENTIFIER = /\A[A-Za-z_][A-Za-z0-9_]*\z/
|
|
12
|
+
|
|
13
|
+
def initialize(project_root, deployment, copier, source: nil)
|
|
14
|
+
@project_root = project_root
|
|
15
|
+
@deployment = deployment
|
|
16
|
+
@copier = copier
|
|
17
|
+
@source = source
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def copy
|
|
21
|
+
%w[userlib vendorlib].each do |name|
|
|
22
|
+
@copier.call(File.join(@project_root, name), File.join(@deployment, 'model', 'lib', 'userlib'))
|
|
23
|
+
end
|
|
24
|
+
copy_root('resources', 'model/resources')
|
|
25
|
+
copy_root('theme/web', 'web')
|
|
26
|
+
copy_root('theme-cache/web', 'web')
|
|
27
|
+
copy_theme_public_assets
|
|
28
|
+
export_images if @source
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def copy_root(source, destination)
|
|
34
|
+
@copier.call(File.join(@project_root, source), File.join(@deployment, destination))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def copy_theme_public_assets
|
|
38
|
+
pattern = File.join(@project_root, 'themesource', '*', 'public')
|
|
39
|
+
Dir.glob(pattern).sort.each { @copier.call(_1, File.join(@deployment, 'web')) }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def export_images # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
43
|
+
directory = File.join(@deployment, 'web', 'img')
|
|
44
|
+
FileUtils.mkdir_p(directory)
|
|
45
|
+
@source.units_of('Images$ImageCollection').each do |unit|
|
|
46
|
+
collection = unit.document
|
|
47
|
+
array(collection['Images']).each do |item|
|
|
48
|
+
names = [unit.module_name, collection['Name'], item['Name']]
|
|
49
|
+
unless names.all? { _1.to_s.match?(SAFE_IDENTIFIER) }
|
|
50
|
+
raise CompilationError, "unsafe image identifier #{names.inspect}"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
filename = "#{names.join('$')}.#{image_format(item)}"
|
|
54
|
+
File.binwrite(File.join(directory, filename), image_bytes(item['Image']))
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'zip'
|
|
6
|
+
|
|
7
|
+
module Mxrb
|
|
8
|
+
module Compiler
|
|
9
|
+
DeploymentBootstrap = Data.define(:deployment, :created, :template_root)
|
|
10
|
+
|
|
11
|
+
# Creates a deployment workspace from versioned Studio Pro templates without invoking its builders.
|
|
12
|
+
class DeploymentBootstrapper # rubocop:disable Metrics/ClassLength
|
|
13
|
+
COMMON_TEMPLATE_ROOTS = %w[data log model native run tmp].freeze
|
|
14
|
+
REQUIRED_DIRECTORIES = %w[
|
|
15
|
+
data/database data/files data/tmp log model/bundles model/lib/userlib model/resources run tmp web/img
|
|
16
|
+
].freeze
|
|
17
|
+
|
|
18
|
+
def initialize(mpr_path, deployment:, mendix_home: nil)
|
|
19
|
+
@mpr_path = File.expand_path(mpr_path)
|
|
20
|
+
@project_root = File.dirname(@mpr_path)
|
|
21
|
+
@deployment = File.expand_path(deployment)
|
|
22
|
+
@source = SourceModel.read(@mpr_path)
|
|
23
|
+
@version_root = resolve_version_root(mendix_home)
|
|
24
|
+
@template_root = File.join(@version_root, 'modeler', 'runtemplates', 'deployment')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def prepare
|
|
28
|
+
return prepare_existing if ready?
|
|
29
|
+
|
|
30
|
+
validate_templates!
|
|
31
|
+
prepare_fresh
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def prepare_existing
|
|
35
|
+
ensure_web_build_templates if modern_react_web?
|
|
36
|
+
ensure_required_directories
|
|
37
|
+
copy_project_assets
|
|
38
|
+
finalize_web_shell
|
|
39
|
+
DeploymentBootstrap.new(deployment: @deployment, created: false, template_root: @template_root)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def prepare_fresh
|
|
43
|
+
FileUtils.mkdir_p(@deployment)
|
|
44
|
+
copy_version_templates
|
|
45
|
+
ensure_required_directories
|
|
46
|
+
render_templates
|
|
47
|
+
initialize_model
|
|
48
|
+
copy_project_assets
|
|
49
|
+
finalize_web_shell
|
|
50
|
+
DeploymentBootstrap.new(deployment: @deployment, created: true, template_root: @template_root)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def ready?
|
|
56
|
+
Adapter::REQUIRED_FILES.all? { File.file?(File.join(@deployment, _1)) }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def resolve_version_root(mendix_home)
|
|
60
|
+
root = File.expand_path(mendix_home || File.join(Dir.home, '.local', 'share', 'mendix', @source.version))
|
|
61
|
+
File.basename(root) == 'runtime' ? File.dirname(root) : root
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def validate_templates!
|
|
65
|
+
return if File.directory?(@template_root) || File.file?(deployment_archive)
|
|
66
|
+
|
|
67
|
+
raise CompilationError, "Mendix #{@source.version} deployment templates not found at #{@template_root}"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def copy_version_templates
|
|
71
|
+
extract_deployment_archive if legacy_archive?
|
|
72
|
+
COMMON_TEMPLATE_ROOTS.each { copy_tree(File.join(@template_root, _1), File.join(@deployment, _1)) }
|
|
73
|
+
web_template_roots.each do |source_name, destination_name|
|
|
74
|
+
copy_tree(File.join(@template_root, source_name), File.join(@deployment, destination_name))
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def web_template_roots
|
|
79
|
+
return { 'react-web' => 'web' } if modern_react_web?
|
|
80
|
+
return { 'dojo-web' => 'web' } if @source.version.to_i == 10
|
|
81
|
+
return { 'web' => 'web', 'modern-web' => 'modern-web' } if @source.version.to_i == 9
|
|
82
|
+
|
|
83
|
+
{ 'web' => 'web' }
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def modern_react_web?
|
|
87
|
+
@source.version.to_i >= 11 || (@source.version.to_i == 10 && @source.optimized_web_client?)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def legacy_archive? = @source.version.to_i <= 7 && File.file?(deployment_archive)
|
|
91
|
+
def deployment_archive = File.join(@version_root, 'modeler', 'deployment.mxz')
|
|
92
|
+
|
|
93
|
+
def extract_deployment_archive # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
94
|
+
root = "#{File.expand_path(@deployment)}#{File::SEPARATOR}"
|
|
95
|
+
Zip::File.open(deployment_archive) do |archive|
|
|
96
|
+
archive.each do |entry|
|
|
97
|
+
destination = File.expand_path(entry.name, @deployment)
|
|
98
|
+
unless destination.start_with?(root)
|
|
99
|
+
raise CompilationError, "unsafe deployment template entry #{entry.name.inspect}"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
entry.directory? ? FileUtils.mkdir_p(destination) : extract_template_entry(entry, destination)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
rescue Zip::Error => e
|
|
106
|
+
raise CompilationError, "invalid deployment template #{deployment_archive}: #{e.message}"
|
|
107
|
+
end # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
|
108
|
+
|
|
109
|
+
def extract_template_entry(entry, destination)
|
|
110
|
+
return if File.exist?(destination)
|
|
111
|
+
|
|
112
|
+
FileUtils.mkdir_p(File.dirname(destination))
|
|
113
|
+
entry.get_input_stream do |input|
|
|
114
|
+
File.open(destination, 'wb') { |output| ::IO.copy_stream(input, output) }
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def copy_tree(source, destination)
|
|
119
|
+
return unless File.directory?(source)
|
|
120
|
+
|
|
121
|
+
FileUtils.mkdir_p(destination)
|
|
122
|
+
Dir.children(source).sort.each do |name|
|
|
123
|
+
from = File.join(source, name)
|
|
124
|
+
to = File.join(destination, name)
|
|
125
|
+
next if File.exist?(to)
|
|
126
|
+
|
|
127
|
+
File.directory?(from) ? copy_tree(from, to) : FileUtils.cp(from, to)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def render_templates
|
|
132
|
+
Dir.glob(File.join(@deployment, '**', '*.template')).sort.each do |source|
|
|
133
|
+
destination = source.delete_suffix('.template')
|
|
134
|
+
File.write(destination, render(File.read(source)))
|
|
135
|
+
FileUtils.rm_f(source)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def ensure_web_build_templates
|
|
140
|
+
validate_templates!
|
|
141
|
+
%w[rspack.config.mjs.template rollup.config.mjs.template].each do |name|
|
|
142
|
+
source = File.join(@template_root, 'react-web', name)
|
|
143
|
+
destination = File.join(@deployment, 'web', name)
|
|
144
|
+
FileUtils.cp(source, destination) unless File.exist?(destination.delete_suffix('.template'))
|
|
145
|
+
end
|
|
146
|
+
render_templates
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def render(content)
|
|
150
|
+
replacements.reduce(content) { |result, (token, value)| result.gsub(token, value) }
|
|
151
|
+
.gsub('\\{', '{').gsub('\\}', '}')
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def replacements
|
|
155
|
+
{
|
|
156
|
+
'{InstallDir:JsStringEncode}' => @version_root,
|
|
157
|
+
'{InstallDir:HtmlAttributeEncode}' => @version_root,
|
|
158
|
+
'{DeploymentDir:JsStringEncode}' => @deployment,
|
|
159
|
+
'{DeploymentDir:HtmlAttributeEncode}' => @deployment,
|
|
160
|
+
'{ProjectDir:HtmlAttributeEncode}' => @project_root,
|
|
161
|
+
'{ProjectName:HtmlAttributeEncode}' => project_name,
|
|
162
|
+
'{EnableWatchman:true|false}' => 'false', '{MxBuildNumber}' => "mxrb-#{@source.version}"
|
|
163
|
+
}
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def initialize_model
|
|
167
|
+
model = File.join(@deployment, 'model')
|
|
168
|
+
FileUtils.mkdir_p(model)
|
|
169
|
+
SystemModelSeed.for(@source.version).package.write(File.join(model, 'model.mdp'))
|
|
170
|
+
initialize_json_files(model)
|
|
171
|
+
ProjectJarArchive.new(@mpr_path, @project_root, @deployment)
|
|
172
|
+
.write(File.join(model, 'bundles', 'project.jar'), empty_classes)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def initialize_json_files(model)
|
|
176
|
+
metadata = DeploymentMetadata.new(@mpr_path, @source)
|
|
177
|
+
write_json(File.join(model, 'metadata.json'), metadata.document)
|
|
178
|
+
write_json(File.join(model, 'dependencies.json'), metadata.dependencies)
|
|
179
|
+
write_json(File.join(model, 'microflows.json'), {})
|
|
180
|
+
write_json(File.join(model, 'operations.json'), [])
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def empty_classes
|
|
184
|
+
path = File.join(@deployment, 'tmp', 'mxrb-empty-classes')
|
|
185
|
+
FileUtils.mkdir_p(path)
|
|
186
|
+
path
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def project_name = File.basename(@mpr_path, File.extname(@mpr_path))
|
|
190
|
+
|
|
191
|
+
def write_json(path, value) = File.write(path, JSON.pretty_generate(value))
|
|
192
|
+
|
|
193
|
+
def copy_project_assets
|
|
194
|
+
DeploymentAssetCopier.new(
|
|
195
|
+
@project_root, @deployment, method(:copy_tree), source: @source
|
|
196
|
+
).copy
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def ensure_required_directories
|
|
200
|
+
REQUIRED_DIRECTORIES.each { FileUtils.mkdir_p(File.join(@deployment, _1)) }
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def finalize_web_shell
|
|
204
|
+
WebShellMaterializer.new(File.join(@deployment, 'web'), version: @source.version).materialize
|
|
205
|
+
end
|
|
206
|
+
end # rubocop:enable Metrics/ClassLength
|
|
207
|
+
end
|
|
208
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mxrb
|
|
4
|
+
module Compiler
|
|
5
|
+
DeploymentMaterialization = Data.define(:deployment, :mendix_version, :stages)
|
|
6
|
+
|
|
7
|
+
# Runs the complete native MPR-to-deployment model pipeline in dependency order.
|
|
8
|
+
class DeploymentMaterializer
|
|
9
|
+
STAGES = [
|
|
10
|
+
SecurityMaterializer, ConstantsMaterializer, DomainModelMaterializer,
|
|
11
|
+
ArtifactMaterializer, TranslationMaterializer, SystemTextMaterializer,
|
|
12
|
+
SystemQueueMaterializer, ClientModelMaterializer,
|
|
13
|
+
CodeActionMaterializer, SettingsMaterializer, MicroflowMaterializer, ProjectMaterializer
|
|
14
|
+
].freeze
|
|
15
|
+
|
|
16
|
+
def initialize(mpr_path, deployment: nil, mendix_home: nil)
|
|
17
|
+
@mpr_path = File.expand_path(mpr_path)
|
|
18
|
+
@deployment = File.expand_path(deployment || File.join(File.dirname(@mpr_path), 'deployment'))
|
|
19
|
+
@mendix_home = mendix_home
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def materialize
|
|
23
|
+
source = SourceModel.read(@mpr_path)
|
|
24
|
+
DeploymentBootstrapper.new(
|
|
25
|
+
@mpr_path, deployment: @deployment, mendix_home: @mendix_home
|
|
26
|
+
).prepare
|
|
27
|
+
Adapter.for(source.version).validate_deployment!(@deployment)
|
|
28
|
+
results = materialize_stages
|
|
29
|
+
DeploymentMaterialization.new(
|
|
30
|
+
deployment: @deployment, mendix_version: source.version, stages: results.freeze
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def materialize_stages
|
|
37
|
+
STAGES.to_h do |stage|
|
|
38
|
+
[stage.name.split('::').last, stage.new(@mpr_path, deployment: @deployment).materialize]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mxrb
|
|
4
|
+
module Compiler
|
|
5
|
+
# Derives initial Runtime metadata from an application MPR.
|
|
6
|
+
class DeploymentMetadata
|
|
7
|
+
def initialize(mpr_path, source)
|
|
8
|
+
@mpr_path = mpr_path
|
|
9
|
+
@source = source
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def document
|
|
13
|
+
{
|
|
14
|
+
'RuntimeVersion' => @source.version, 'ProjectID' => project_id,
|
|
15
|
+
'ProjectName' => project_name, 'ModelVersion' => 'unversioned', 'Description' => '',
|
|
16
|
+
'AdminUser' => 'MxAdmin', 'AdminRole' => '', 'JavaVersion' => java_version,
|
|
17
|
+
'Roles' => {}, 'Constants' => [], 'ScheduledEvents' => [], 'Languages' => languages,
|
|
18
|
+
'Configuration' => configuration, 'RequestHandlers' => request_handlers,
|
|
19
|
+
'ModelRuntimeCompatibilityHash' => ''
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def dependencies
|
|
24
|
+
{ 'schemaVersion' => '2.3', 'appName' => project_name, 'published' => [], 'consumed' => [] }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def project_id
|
|
30
|
+
@source.units.find { _1.document['$Type'] == 'Projects$Project' }&.id.to_s
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def project_name = File.basename(@mpr_path, File.extname(@mpr_path))
|
|
34
|
+
def java_version = Runtime::Toolchain.new(@mpr_path).plan.java_version.to_i
|
|
35
|
+
|
|
36
|
+
def languages
|
|
37
|
+
@source.documents.flat_map { collect_languages(_1) }.uniq.sort
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def collect_languages(value)
|
|
41
|
+
case value
|
|
42
|
+
when Hash
|
|
43
|
+
own = value['$Type'] == 'Texts$Translation' ? [value['LanguageCode'].to_s] : []
|
|
44
|
+
own + value.values.flat_map { collect_languages(_1) }
|
|
45
|
+
when Array then value.flat_map { collect_languages(_1) }
|
|
46
|
+
else []
|
|
47
|
+
end.reject(&:empty?)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def configuration
|
|
51
|
+
{
|
|
52
|
+
'SourceDatabaseType' => 'HSQLDB', 'SourceDatabaseName' => 'home',
|
|
53
|
+
'SourceBuiltInDatabasePath' => 'model/sampledata/data/database'
|
|
54
|
+
}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def request_handlers
|
|
58
|
+
[['/api/', true], ['/link/', true], ['/p/', false]].map do |name, enabled|
|
|
59
|
+
{ 'Name' => name, 'DefaultEnabled' => enabled, 'MatchExactly' => false }
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mxrb
|
|
4
|
+
module Compiler
|
|
5
|
+
# Converts domain-model documents from editor shape to Runtime shape.
|
|
6
|
+
class DomainDocumentCompiler # rubocop:disable Metrics/ClassLength
|
|
7
|
+
include ModelValues
|
|
8
|
+
|
|
9
|
+
def initialize(source)
|
|
10
|
+
@source = source
|
|
11
|
+
domain_units = source.respond_to?(:units_of) ? source.units_of('DomainModels$DomainModel') : []
|
|
12
|
+
@entities = domain_units.each_with_object({}) do |unit, result|
|
|
13
|
+
array(unit.document['Entities']).each do |entity|
|
|
14
|
+
result["#{unit.module_name}.#{entity['Name']}"] = entity
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
@security = DomainSecurityCompiler.new(source)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def compile(unit) # rubocop:disable Metrics/AbcSize
|
|
21
|
+
source = unit.document
|
|
22
|
+
{
|
|
23
|
+
'$ID' => source['$ID'], '$Type' => source['$Type'],
|
|
24
|
+
'Entities' => array(source['Entities']).map { compile_entity(_1, unit.module_name) },
|
|
25
|
+
'Associations' => array(source['Associations']).map { @security.association(_1, unit.module_name) },
|
|
26
|
+
'CrossAssociations' => array(source['CrossAssociations']).map do |association|
|
|
27
|
+
@security.association(association, unit.module_name)
|
|
28
|
+
end
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def compile_entity(source, module_name)
|
|
35
|
+
name = source['Name'].to_s
|
|
36
|
+
entity_content(source).merge(
|
|
37
|
+
'Source' => compile_entity_source(source['Source']),
|
|
38
|
+
'GUID' => source['GUID'], 'Image' => source['Image'].to_s,
|
|
39
|
+
'QualifiedName' => "#{module_name}.#{name}", 'UnqualifiedName' => name
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def compile_entity_source(source) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
44
|
+
return nil unless source
|
|
45
|
+
return plain_document(source) unless source['$Type'] == 'DomainModels$OqlViewEntitySource'
|
|
46
|
+
|
|
47
|
+
qualified_name = source['SourceDocument'].to_s
|
|
48
|
+
document = @source.units.find do |unit|
|
|
49
|
+
unit.document['$Type'] == 'DomainModels$ViewEntitySourceDocument' &&
|
|
50
|
+
"#{unit.module_name}.#{unit.document['Name']}" == qualified_name
|
|
51
|
+
end
|
|
52
|
+
raise CompilationError, "OQL view source #{qualified_name.inspect} not found" unless document
|
|
53
|
+
|
|
54
|
+
source.slice('$ID', '$Type', 'SourceDocument').merge(
|
|
55
|
+
'OqlRuntime' => document.document['Oql'].to_s,
|
|
56
|
+
'SourceDocumentName' => qualified_name,
|
|
57
|
+
'SourceType' => 'OQL'
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def entity_content(source) # rubocop:disable Metrics/AbcSize
|
|
62
|
+
{
|
|
63
|
+
'$ID' => source['$ID'], '$Type' => source['$Type'],
|
|
64
|
+
'MaybeGeneralization' => compile_generalization(source['MaybeGeneralization']),
|
|
65
|
+
'Attributes' => array(source['Attributes']).map { compile_attribute(_1) },
|
|
66
|
+
'ValidationRules' => array(source['ValidationRules']).map { compile_validation(_1) },
|
|
67
|
+
'Events' => plain_array(source['Events']),
|
|
68
|
+
'Indexes' => array(source['Indexes']).map { compile_index(_1) },
|
|
69
|
+
'AccessRules' => array(source['AccessRules']).map { @security.access_rule(_1) }
|
|
70
|
+
}
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def compile_generalization(source)
|
|
74
|
+
type = source.fetch('$Type')
|
|
75
|
+
result = { '$ID' => source['$ID'], '$Type' => type }
|
|
76
|
+
result['Key'] = source['Key'] if type == 'DomainModels$NoGeneralization'
|
|
77
|
+
result.merge(generalization_flags(source, type))
|
|
78
|
+
.merge('Generalization' => source['Generalization'].to_s)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def generalization_flags(source, type)
|
|
82
|
+
inherited = inherited_flags(source['Generalization']) if type == 'DomainModels$Generalization'
|
|
83
|
+
{
|
|
84
|
+
'Persistable' => source.fetch('Persistable', inherited&.fetch('Persistable', false)) == true,
|
|
85
|
+
'HasCreatedDateAttr' => source.fetch('HasCreatedDateAttr',
|
|
86
|
+
inherited&.fetch('HasCreatedDateAttr', false)) == true,
|
|
87
|
+
'HasChangedDateAttr' => source.fetch('HasChangedDateAttr',
|
|
88
|
+
inherited&.fetch('HasChangedDateAttr', false)) == true,
|
|
89
|
+
'HasOwnerAttr' => source.fetch('HasOwnerAttr', inherited&.fetch('HasOwnerAttr', false)) == true,
|
|
90
|
+
'HasChangedByAttr' => source.fetch('HasChangedByAttr', inherited&.fetch('HasChangedByAttr', false)) == true
|
|
91
|
+
}
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def inherited_flags(qualified_name)
|
|
95
|
+
return system_flags if qualified_name.to_s.start_with?('System.')
|
|
96
|
+
|
|
97
|
+
parent = @entities[qualified_name.to_s]
|
|
98
|
+
return system_flags unless parent
|
|
99
|
+
|
|
100
|
+
generalization = parent['MaybeGeneralization'] || {}
|
|
101
|
+
generalization_flags(generalization, generalization['$Type'])
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def system_flags
|
|
105
|
+
{
|
|
106
|
+
'Persistable' => true, 'HasCreatedDateAttr' => true, 'HasChangedDateAttr' => true,
|
|
107
|
+
'HasOwnerAttr' => true, 'HasChangedByAttr' => true
|
|
108
|
+
}
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def compile_attribute(source)
|
|
112
|
+
{
|
|
113
|
+
'$ID' => source['$ID'], '$Type' => source['$Type'],
|
|
114
|
+
'Value' => plain_document(source['Value']), 'Type' => compile_attribute_type(source['NewType']),
|
|
115
|
+
'Name' => source['Name'], 'GUID' => source['GUID']
|
|
116
|
+
}
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def compile_attribute_type(source)
|
|
120
|
+
result = plain_document(source)
|
|
121
|
+
if result['$Type'] == 'DomainModels$DateTimeAttributeType'
|
|
122
|
+
result['LocalizeDate'] = source.fetch('LocalizeDate', true) == true
|
|
123
|
+
end
|
|
124
|
+
result
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def compile_validation(source)
|
|
128
|
+
message = source['Message'] || {}
|
|
129
|
+
{
|
|
130
|
+
'$ID' => source['$ID'], '$Type' => source['$Type'],
|
|
131
|
+
'Message' => message.slice('$ID', '$Type'),
|
|
132
|
+
'RuleInfo' => plain_document(source['RuleInfo']), 'Attribute' => source['Attribute'].to_s
|
|
133
|
+
}
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def compile_index(source)
|
|
137
|
+
{
|
|
138
|
+
'$ID' => source['$ID'], '$Type' => source['$Type'],
|
|
139
|
+
'Attributes' => array(source['Attributes']).map { compile_indexed_attribute(_1) },
|
|
140
|
+
'GUID' => source['GUID'], 'IncludeInOffline' => source['IncludeInOffline'] == true
|
|
141
|
+
}
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def compile_indexed_attribute(source)
|
|
145
|
+
result = plain_document(source)
|
|
146
|
+
result['AssociationPointer'] ||= BSON::Binary.new(
|
|
147
|
+
IO::BsonCodec.uuid_to_blob('00000000-0000-0000-0000-000000000000'), :generic
|
|
148
|
+
)
|
|
149
|
+
result
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mxrb
|
|
4
|
+
module Compiler
|
|
5
|
+
DomainModelMaterialization = Data.define(:model_path, :domain_models, :entities)
|
|
6
|
+
|
|
7
|
+
# Replaces or inserts Runtime domain-model documents in model.mdp.
|
|
8
|
+
class DomainModelMaterializer
|
|
9
|
+
def initialize(mpr_path, deployment:)
|
|
10
|
+
@mpr_path = File.expand_path(mpr_path)
|
|
11
|
+
@deployment = File.expand_path(deployment)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def materialize
|
|
15
|
+
source = SourceModel.read(@mpr_path)
|
|
16
|
+
Adapter.for(source.version)
|
|
17
|
+
compiler = DomainDocumentCompiler.new(source)
|
|
18
|
+
documents = source.units_of('DomainModels$DomainModel').map { compiler.compile(_1) }
|
|
19
|
+
path = File.join(@deployment, 'model', 'model.mdp')
|
|
20
|
+
write_model(path, documents)
|
|
21
|
+
DomainModelMaterialization.new(
|
|
22
|
+
model_path: path, domain_models: documents.length,
|
|
23
|
+
entities: documents.sum { _1.fetch('Entities').length }
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def write_model(path, documents)
|
|
30
|
+
package = documents.reduce(ModelPackage.read(path)) { |result, document| result.upsert(document) }
|
|
31
|
+
package.write(path)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mxrb
|
|
4
|
+
module Compiler
|
|
5
|
+
# Resolves project roles and association security into Runtime fields.
|
|
6
|
+
class DomainSecurityCompiler
|
|
7
|
+
include ModelValues
|
|
8
|
+
|
|
9
|
+
def initialize(source)
|
|
10
|
+
@role_map = project_role_map(source)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def access_rule(source)
|
|
14
|
+
module_roles = array(source['AllowedModuleRoles']).map(&:to_s)
|
|
15
|
+
{
|
|
16
|
+
'$ID' => source['$ID'], '$Type' => source['$Type'],
|
|
17
|
+
'MemberAccesses' => array(source['MemberAccesses']).map { member_access(_1) },
|
|
18
|
+
'AllowedUserRoles' => module_roles.flat_map { @role_map.fetch(_1, []) }.uniq,
|
|
19
|
+
'AllowCreate' => source['AllowCreate'] == true, 'AllowDelete' => source['AllowDelete'] == true,
|
|
20
|
+
'XPathConstraint' => source['XPathConstraint'].to_s
|
|
21
|
+
}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def association(source, module_name)
|
|
25
|
+
name = source['Name'].to_s
|
|
26
|
+
result = association_fields(source).merge(
|
|
27
|
+
'QualifiedName' => "#{module_name}.#{name}",
|
|
28
|
+
'UnqualifiedName' => name, 'Navigability' => 'BothDirections'
|
|
29
|
+
)
|
|
30
|
+
child_key = source['$Type'] == 'DomainModels$CrossAssociation' ? 'Child' : 'ChildPointer'
|
|
31
|
+
result.merge(child_key => source[child_key])
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def member_access(source)
|
|
37
|
+
{
|
|
38
|
+
'$ID' => source['$ID'], '$Type' => source['$Type'],
|
|
39
|
+
'Attribute' => source['Attribute'].to_s, 'Association' => source['Association'].to_s,
|
|
40
|
+
'AccessRights' => source['AccessRights']
|
|
41
|
+
}
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def association_fields(source)
|
|
45
|
+
{
|
|
46
|
+
'$ID' => source['$ID'], '$Type' => source['$Type'],
|
|
47
|
+
'DeleteBehavior' => delete_behavior(source['DeleteBehavior']),
|
|
48
|
+
'Source' => source['Source'], 'GUID' => source['GUID'], 'Type' => source['Type'],
|
|
49
|
+
'Owner' => source['Owner'], 'StorageFormat' => source['StorageFormat'],
|
|
50
|
+
'ParentPointer' => source['ParentPointer']
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def delete_behavior(source)
|
|
55
|
+
{
|
|
56
|
+
'$ID' => source['$ID'], '$Type' => source['$Type'],
|
|
57
|
+
'ParentErrorMessage' => text_reference(source['ParentErrorMessage']),
|
|
58
|
+
'ChildErrorMessage' => text_reference(source['ChildErrorMessage']),
|
|
59
|
+
'ParentDeleteBehavior' => runtime_delete_behavior(source['ParentDeleteBehavior']),
|
|
60
|
+
'ChildDeleteBehavior' => runtime_delete_behavior(source['ChildDeleteBehavior'])
|
|
61
|
+
}
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def text_reference(source)
|
|
65
|
+
source&.slice('$ID', '$Type')
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def runtime_delete_behavior(value)
|
|
69
|
+
value == 'NoAction' ? 'DeleteMeAndReferences' : value
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def project_role_map(source)
|
|
73
|
+
security = source.documents('Security$ProjectSecurity').first
|
|
74
|
+
return {} unless security
|
|
75
|
+
|
|
76
|
+
array(security['UserRoles']).each_with_object(Hash.new { |hash, key| hash[key] = [] }) do |role, map|
|
|
77
|
+
array(role['ModuleRoles']).each { |module_role| map[module_role.to_s] << role['Name'].to_s }
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|