archimate 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.projectile +18 -0
- data/.rubocop.yml +13 -0
- data/.travis.yml +4 -0
- data/.yardocs +15 -0
- data/Gemfile +5 -0
- data/Guardfile +27 -0
- data/LICENSE +201 -0
- data/README.md +94 -0
- data/Rakefile +29 -0
- data/TODOs.org +286 -0
- data/archimate.gemspec +51 -0
- data/bin/archimate +17 -0
- data/bin/console +13 -0
- data/bin/setup +8 -0
- data/exe/archidiff +7 -0
- data/exe/archidiff-summary +7 -0
- data/exe/archimate +7 -0
- data/exe/archimerge +7 -0
- data/exe/fmtxml +7 -0
- data/lib/archimate/cli/archi.rb +189 -0
- data/lib/archimate/cli/cleanup.rb +54 -0
- data/lib/archimate/cli/conflict_resolver.rb +39 -0
- data/lib/archimate/cli/convert.rb +39 -0
- data/lib/archimate/cli/diff.rb +31 -0
- data/lib/archimate/cli/diff_summary.rb +101 -0
- data/lib/archimate/cli/duper.rb +85 -0
- data/lib/archimate/cli/lint.rb +16 -0
- data/lib/archimate/cli/mapper.rb +82 -0
- data/lib/archimate/cli/merge.rb +49 -0
- data/lib/archimate/cli/merger.rb +109 -0
- data/lib/archimate/cli/stats.rb +42 -0
- data/lib/archimate/cli/svger.rb +40 -0
- data/lib/archimate/color.rb +53 -0
- data/lib/archimate/config.rb +35 -0
- data/lib/archimate/data_model/any_attribute.rb +13 -0
- data/lib/archimate/data_model/any_element.rb +15 -0
- data/lib/archimate/data_model/archimate_node.rb +181 -0
- data/lib/archimate/data_model/bounds.rb +72 -0
- data/lib/archimate/data_model/color.rb +47 -0
- data/lib/archimate/data_model/concept.rb +14 -0
- data/lib/archimate/data_model/concern.rb +17 -0
- data/lib/archimate/data_model/connection.rb +107 -0
- data/lib/archimate/data_model/constants.rb +82 -0
- data/lib/archimate/data_model/container.rb +17 -0
- data/lib/archimate/data_model/diagram.rb +40 -0
- data/lib/archimate/data_model/diffable_array.rb +213 -0
- data/lib/archimate/data_model/diffable_primitive.rb +83 -0
- data/lib/archimate/data_model/documentation.rb +14 -0
- data/lib/archimate/data_model/element.rb +87 -0
- data/lib/archimate/data_model/font.rb +54 -0
- data/lib/archimate/data_model/label.rb +19 -0
- data/lib/archimate/data_model/lang_string.rb +41 -0
- data/lib/archimate/data_model/location.rb +31 -0
- data/lib/archimate/data_model/metadata.rb +14 -0
- data/lib/archimate/data_model/model.rb +217 -0
- data/lib/archimate/data_model/modeling_note.rb +13 -0
- data/lib/archimate/data_model/named_referenceable.rb +14 -0
- data/lib/archimate/data_model/organization.rb +40 -0
- data/lib/archimate/data_model/property.rb +25 -0
- data/lib/archimate/data_model/property_definition.rb +16 -0
- data/lib/archimate/data_model/referenceable.rb +29 -0
- data/lib/archimate/data_model/relationship.rb +85 -0
- data/lib/archimate/data_model/schema_info.rb +18 -0
- data/lib/archimate/data_model/style.rb +32 -0
- data/lib/archimate/data_model/view.rb +12 -0
- data/lib/archimate/data_model/view_concept.rb +18 -0
- data/lib/archimate/data_model/view_node.rb +114 -0
- data/lib/archimate/data_model/viewpoint.rb +87 -0
- data/lib/archimate/data_model.rb +54 -0
- data/lib/archimate/diff/archimate_array_reference.rb +113 -0
- data/lib/archimate/diff/archimate_identified_node_reference.rb +41 -0
- data/lib/archimate/diff/archimate_node_attribute_reference.rb +70 -0
- data/lib/archimate/diff/archimate_node_reference.rb +80 -0
- data/lib/archimate/diff/change.rb +49 -0
- data/lib/archimate/diff/conflict.rb +31 -0
- data/lib/archimate/diff/conflicts/base_conflict.rb +53 -0
- data/lib/archimate/diff/conflicts/deleted_items_child_updated_conflict.rb +30 -0
- data/lib/archimate/diff/conflicts/deleted_items_referenced_conflict.rb +63 -0
- data/lib/archimate/diff/conflicts/path_conflict.rb +51 -0
- data/lib/archimate/diff/conflicts.rb +89 -0
- data/lib/archimate/diff/delete.rb +41 -0
- data/lib/archimate/diff/difference.rb +113 -0
- data/lib/archimate/diff/insert.rb +43 -0
- data/lib/archimate/diff/merge.rb +70 -0
- data/lib/archimate/diff/move.rb +51 -0
- data/lib/archimate/diff.rb +17 -0
- data/lib/archimate/export/csv_export.rb +32 -0
- data/lib/archimate/export/cypher.rb +171 -0
- data/lib/archimate/export/graph_ml.rb +131 -0
- data/lib/archimate/export/n_quads.rb +142 -0
- data/lib/archimate/file_format.rb +30 -0
- data/lib/archimate/file_formats/archi_file_format.rb +151 -0
- data/lib/archimate/file_formats/archi_file_reader.rb +252 -0
- data/lib/archimate/file_formats/archi_file_writer.rb +230 -0
- data/lib/archimate/file_formats/archimate_v2.rb +461 -0
- data/lib/archimate/file_formats/model_exchange_file/xml_lang_string.rb +35 -0
- data/lib/archimate/file_formats/model_exchange_file/xml_metadata.rb +115 -0
- data/lib/archimate/file_formats/model_exchange_file/xml_property_definitions.rb +28 -0
- data/lib/archimate/file_formats/model_exchange_file/xml_property_defs.rb +27 -0
- data/lib/archimate/file_formats/model_exchange_file_reader.rb +237 -0
- data/lib/archimate/file_formats/model_exchange_file_reader_21.rb +73 -0
- data/lib/archimate/file_formats/model_exchange_file_reader_30.rb +134 -0
- data/lib/archimate/file_formats/model_exchange_file_writer.rb +157 -0
- data/lib/archimate/file_formats/model_exchange_file_writer_21.rb +143 -0
- data/lib/archimate/file_formats/model_exchange_file_writer_30.rb +153 -0
- data/lib/archimate/file_formats/writer.rb +56 -0
- data/lib/archimate/lint/duplicate_entities.rb +121 -0
- data/lib/archimate/lint/linter.rb +146 -0
- data/lib/archimate/logging.rb +55 -0
- data/lib/archimate/maybe_io.rb +34 -0
- data/lib/archimate/progress_indicator.rb +29 -0
- data/lib/archimate/svg/archimate.css +232 -0
- data/lib/archimate/svg/child.rb +29 -0
- data/lib/archimate/svg/connection.rb +184 -0
- data/lib/archimate/svg/css_style.rb +31 -0
- data/lib/archimate/svg/diagram.rb +87 -0
- data/lib/archimate/svg/entity/and_junction.rb +14 -0
- data/lib/archimate/svg/entity/application_collaboration.rb +14 -0
- data/lib/archimate/svg/entity/application_component.rb +41 -0
- data/lib/archimate/svg/entity/application_event.rb +13 -0
- data/lib/archimate/svg/entity/application_function.rb +13 -0
- data/lib/archimate/svg/entity/application_interaction.rb +13 -0
- data/lib/archimate/svg/entity/application_interface.rb +13 -0
- data/lib/archimate/svg/entity/application_process.rb +13 -0
- data/lib/archimate/svg/entity/application_service.rb +13 -0
- data/lib/archimate/svg/entity/artifact.rb +39 -0
- data/lib/archimate/svg/entity/assessment.rb +14 -0
- data/lib/archimate/svg/entity/base_entity.rb +128 -0
- data/lib/archimate/svg/entity/business_actor.rb +14 -0
- data/lib/archimate/svg/entity/business_collaboration.rb +14 -0
- data/lib/archimate/svg/entity/business_event.rb +10 -0
- data/lib/archimate/svg/entity/business_function.rb +13 -0
- data/lib/archimate/svg/entity/business_interaction.rb +13 -0
- data/lib/archimate/svg/entity/business_interface.rb +13 -0
- data/lib/archimate/svg/entity/business_object.rb +13 -0
- data/lib/archimate/svg/entity/business_process.rb +13 -0
- data/lib/archimate/svg/entity/business_role.rb +14 -0
- data/lib/archimate/svg/entity/business_service.rb +13 -0
- data/lib/archimate/svg/entity/capability.rb +14 -0
- data/lib/archimate/svg/entity/communication_network.rb +14 -0
- data/lib/archimate/svg/entity/communication_path.rb +14 -0
- data/lib/archimate/svg/entity/constraint.rb +15 -0
- data/lib/archimate/svg/entity/contract.rb +13 -0
- data/lib/archimate/svg/entity/course_of_action.rb +14 -0
- data/lib/archimate/svg/entity/data_entity.rb +29 -0
- data/lib/archimate/svg/entity/data_object.rb +13 -0
- data/lib/archimate/svg/entity/deliverable.rb +13 -0
- data/lib/archimate/svg/entity/device.rb +48 -0
- data/lib/archimate/svg/entity/diagram_model_reference.rb +22 -0
- data/lib/archimate/svg/entity/diagram_object.rb +30 -0
- data/lib/archimate/svg/entity/distribution_network.rb +14 -0
- data/lib/archimate/svg/entity/driver.rb +14 -0
- data/lib/archimate/svg/entity/equipment.rb +16 -0
- data/lib/archimate/svg/entity/event_entity.rb +36 -0
- data/lib/archimate/svg/entity/facility.rb +16 -0
- data/lib/archimate/svg/entity/function_entity.rb +14 -0
- data/lib/archimate/svg/entity/gap.rb +21 -0
- data/lib/archimate/svg/entity/goal.rb +14 -0
- data/lib/archimate/svg/entity/group.rb +24 -0
- data/lib/archimate/svg/entity/implementation_event.rb +13 -0
- data/lib/archimate/svg/entity/infrastructure_function.rb +13 -0
- data/lib/archimate/svg/entity/infrastructure_interface.rb +13 -0
- data/lib/archimate/svg/entity/infrastructure_service.rb +13 -0
- data/lib/archimate/svg/entity/interaction_entity.rb +14 -0
- data/lib/archimate/svg/entity/interface_entity.rb +35 -0
- data/lib/archimate/svg/entity/junction.rb +19 -0
- data/lib/archimate/svg/entity/location.rb +14 -0
- data/lib/archimate/svg/entity/material.rb +14 -0
- data/lib/archimate/svg/entity/meaning.rb +40 -0
- data/lib/archimate/svg/entity/motivation_entity.rb +40 -0
- data/lib/archimate/svg/entity/network.rb +14 -0
- data/lib/archimate/svg/entity/node.rb +33 -0
- data/lib/archimate/svg/entity/node_shape.rb +64 -0
- data/lib/archimate/svg/entity/note.rb +30 -0
- data/lib/archimate/svg/entity/or_junction.rb +14 -0
- data/lib/archimate/svg/entity/outcome.rb +15 -0
- data/lib/archimate/svg/entity/path.rb +14 -0
- data/lib/archimate/svg/entity/plateau.rb +15 -0
- data/lib/archimate/svg/entity/principle.rb +15 -0
- data/lib/archimate/svg/entity/process_entity.rb +63 -0
- data/lib/archimate/svg/entity/product.rb +20 -0
- data/lib/archimate/svg/entity/rect.rb +13 -0
- data/lib/archimate/svg/entity/rect_entity.rb +25 -0
- data/lib/archimate/svg/entity/representation.rb +31 -0
- data/lib/archimate/svg/entity/requirement.rb +15 -0
- data/lib/archimate/svg/entity/resource.rb +14 -0
- data/lib/archimate/svg/entity/rounded_rect_entity.rb +23 -0
- data/lib/archimate/svg/entity/service_entity.rb +51 -0
- data/lib/archimate/svg/entity/sketch_model_sticky.rb +14 -0
- data/lib/archimate/svg/entity/stakeholder.rb +15 -0
- data/lib/archimate/svg/entity/system_software.rb +14 -0
- data/lib/archimate/svg/entity/technology_collaboration.rb +14 -0
- data/lib/archimate/svg/entity/technology_event.rb +13 -0
- data/lib/archimate/svg/entity/technology_function.rb +13 -0
- data/lib/archimate/svg/entity/technology_interaction.rb +13 -0
- data/lib/archimate/svg/entity/technology_interface.rb +13 -0
- data/lib/archimate/svg/entity/technology_process.rb +13 -0
- data/lib/archimate/svg/entity/technology_service.rb +13 -0
- data/lib/archimate/svg/entity/value.rb +27 -0
- data/lib/archimate/svg/entity/work_package.rb +14 -0
- data/lib/archimate/svg/entity.rb +93 -0
- data/lib/archimate/svg/entity_factory.rb +17 -0
- data/lib/archimate/svg/extents.rb +27 -0
- data/lib/archimate/svg/point.rb +7 -0
- data/lib/archimate/svg/svg_template.rb +27 -0
- data/lib/archimate/svg/svg_template.svg.erb +169 -0
- data/lib/archimate/version.rb +4 -0
- data/lib/archimate.rb +114 -0
- metadata +623 -0
@@ -0,0 +1,143 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "nokogiri"
|
3
|
+
|
4
|
+
module Archimate
|
5
|
+
module FileFormats
|
6
|
+
# Archimate version 2.1 Model Exchange Format Writer
|
7
|
+
class ModelExchangeFileWriter21 < ModelExchangeFileWriter
|
8
|
+
def initialize(model)
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def model_attrs
|
13
|
+
model_namespaces.merge(
|
14
|
+
"xsi:schemaLocation" => model.schema_locations.join(" "),
|
15
|
+
"identifier" => identifier(model.id)
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def serialize_model(xml)
|
20
|
+
xml.model(model_attrs) do
|
21
|
+
ModelExchangeFile::XmlMetadata.new(model.metadata).serialize(xml)
|
22
|
+
ModelExchangeFile::XmlLangString.new(model.name, :name).serialize(xml)
|
23
|
+
ModelExchangeFile::XmlLangString.new(model.documentation, :documentation).serialize(xml)
|
24
|
+
serialize_properties(xml, model)
|
25
|
+
serialize_elements(xml)
|
26
|
+
serialize_relationships(xml)
|
27
|
+
serialize_organization_root(xml, model.organizations)
|
28
|
+
serialize_property_defs(xml)
|
29
|
+
serialize_views(xml)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def serialize_property_defs(xml)
|
34
|
+
return if model.property_definitions.empty?
|
35
|
+
ModelExchangeFile::XmlPropertyDefs.new(model.property_definitions).serialize(xml)
|
36
|
+
end
|
37
|
+
|
38
|
+
def serialize_label(xml, str)
|
39
|
+
return if str.nil? || str.strip.empty?
|
40
|
+
name_attrs = str.lang && !str.lang.empty? ? {"xml:lang" => str.lang} : {}
|
41
|
+
xml.label(name_attrs) { xml.text text_proc(str) }
|
42
|
+
end
|
43
|
+
|
44
|
+
def serialize_organization_root(xml, organizations)
|
45
|
+
return unless organizations && organizations.size > 0
|
46
|
+
xml.organization do
|
47
|
+
serialize(xml, organizations)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def serialize_item(xml, item)
|
52
|
+
xml.item(identifierref: identifier(item))
|
53
|
+
end
|
54
|
+
|
55
|
+
def serialize_property(xml, property)
|
56
|
+
xml.property(identifierref: property.property_definition.id) do
|
57
|
+
ModelExchangeFile::XmlLangString.new(property.value, :value).serialize(xml)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def serialize_views(xml)
|
62
|
+
return if model.diagrams.empty?
|
63
|
+
xml.views do
|
64
|
+
serialize(xml, model.diagrams)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def serialize_diagram(xml, diagram)
|
69
|
+
xml.view(
|
70
|
+
remove_nil_values(
|
71
|
+
identifier: identifier(diagram.id),
|
72
|
+
viewpoint: diagram.viewpoint_type,
|
73
|
+
"xsi:type": diagram.type
|
74
|
+
)
|
75
|
+
) do
|
76
|
+
elementbase(xml, diagram)
|
77
|
+
serialize(xml, diagram.nodes)
|
78
|
+
serialize(xml, diagram.connections)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def view_node_attrs(view_node, x_offset = 0, y_offset = 0)
|
83
|
+
attrs = {
|
84
|
+
identifier: identifier(view_node.id),
|
85
|
+
elementref: nil,
|
86
|
+
x: view_node.bounds ? (view_node.bounds&.x + x_offset).round : nil,
|
87
|
+
y: view_node.bounds ? (view_node.bounds&.y + y_offset).round : nil,
|
88
|
+
w: view_node.bounds&.width&.round,
|
89
|
+
h: view_node.bounds&.height&.round,
|
90
|
+
type: nil
|
91
|
+
}
|
92
|
+
if view_node.archimate_element
|
93
|
+
attrs[:elementref] = identifier(view_node.archimate_element)
|
94
|
+
elsif view_node.model
|
95
|
+
# Since it doesn't seem to be forbidden, we just assume we can use
|
96
|
+
# the elementref for views in views
|
97
|
+
attrs[:elementref] = view_node.model
|
98
|
+
attrs[:type] = "model"
|
99
|
+
else
|
100
|
+
attrs[:type] = "group"
|
101
|
+
end
|
102
|
+
remove_nil_values(attrs)
|
103
|
+
end
|
104
|
+
|
105
|
+
def serialize_view_node(xml, view_node, x_offset = 0, y_offset = 0)
|
106
|
+
attrs = view_node_attrs(view_node, x_offset, y_offset)
|
107
|
+
xml.node(attrs) do
|
108
|
+
serialize_label(xml, view_node.name) if attrs[:type] == "group"
|
109
|
+
serialize(xml, view_node.style) if view_node.style
|
110
|
+
view_node.nodes.each do |c|
|
111
|
+
serialize_view_node(xml, c) # , attrs[:x].to_f, attrs[:y].to_f)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def font_style_string(font)
|
117
|
+
font&.style_string
|
118
|
+
end
|
119
|
+
|
120
|
+
def serialize_connection(xml, sc)
|
121
|
+
xml.connection(
|
122
|
+
identifier: identifier(sc.id),
|
123
|
+
relationshipref: identifier(sc.relationship),
|
124
|
+
source: identifier(sc.source),
|
125
|
+
target: identifier(sc.target)
|
126
|
+
) do
|
127
|
+
serialize(xml, sc.bendpoints)
|
128
|
+
serialize(xml, sc.style)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def meff_type(el_type)
|
133
|
+
el_type = el_type.sub(/^/, "")
|
134
|
+
case el_type
|
135
|
+
when 'AndJunction', 'OrJunction'
|
136
|
+
'Junction'
|
137
|
+
else
|
138
|
+
el_type
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "nokogiri"
|
3
|
+
|
4
|
+
module Archimate
|
5
|
+
module FileFormats
|
6
|
+
class ModelExchangeFileWriter30 < ModelExchangeFileWriter
|
7
|
+
def initialize(model)
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def model_attrs
|
12
|
+
remove_nil_values(
|
13
|
+
model_namespaces.merge(
|
14
|
+
"xsi:schemaLocation" => model.schema_locations.join(" "),
|
15
|
+
"identifier" => identifier(model.id),
|
16
|
+
"version" => model.version
|
17
|
+
)
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def serialize_model(xml)
|
22
|
+
xml.model(model_attrs) do
|
23
|
+
ModelExchangeFile::XmlLangString.new(model.name, :name).serialize(xml)
|
24
|
+
ModelExchangeFile::XmlLangString.new(model.documentation, :documentation).serialize(xml)
|
25
|
+
ModelExchangeFile::XmlMetadata.new(model.metadata).serialize(xml)
|
26
|
+
serialize_properties(xml, model)
|
27
|
+
serialize_elements(xml)
|
28
|
+
serialize_relationships(xml)
|
29
|
+
serialize_organization_root(xml, model.organizations)
|
30
|
+
serialize_property_defs(xml)
|
31
|
+
serialize_views(xml)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def serialize_property_defs(xml)
|
36
|
+
return if model.property_definitions.empty?
|
37
|
+
ModelExchangeFile::XmlPropertyDefinitions.new(model.property_definitions).serialize(xml)
|
38
|
+
end
|
39
|
+
|
40
|
+
def serialize_label(xml, str, tag = :name)
|
41
|
+
return if str.nil? || str.strip.empty?
|
42
|
+
name_attrs = str.lang && !str.lang.empty? ? {"xml:lang" => str.lang} : {}
|
43
|
+
xml.send(tag, name_attrs) { xml.text text_proc(str) }
|
44
|
+
end
|
45
|
+
|
46
|
+
def relationship_attributes(relationship)
|
47
|
+
attrs = super
|
48
|
+
attrs["accessType"] = relationship.access_type if relationship.access_type
|
49
|
+
attrs
|
50
|
+
end
|
51
|
+
|
52
|
+
def serialize_organization_root(xml, organizations)
|
53
|
+
return unless organizations && organizations.size > 0
|
54
|
+
xml.organizations do
|
55
|
+
serialize_organization_body(xml, organizations[0])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def serialize_item(xml, item)
|
60
|
+
xml.item(identifierRef: identifier(item))
|
61
|
+
end
|
62
|
+
|
63
|
+
def serialize_property(xml, property)
|
64
|
+
xml.property("propertyDefinitionRef" => property.property_definition.id) do
|
65
|
+
ModelExchangeFile::XmlLangString.new(property.value, :value).serialize(xml)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def serialize_views(xml)
|
70
|
+
return if model.diagrams.empty?
|
71
|
+
xml.views do
|
72
|
+
xml.diagrams {
|
73
|
+
serialize(xml, model.diagrams)
|
74
|
+
}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def serialize_diagram(xml, diagram)
|
79
|
+
xml.view(
|
80
|
+
remove_nil_values(
|
81
|
+
identifier: identifier(diagram.id),
|
82
|
+
"xsi:type": diagram.type,
|
83
|
+
viewpoint: diagram.viewpoint_type
|
84
|
+
)
|
85
|
+
) do
|
86
|
+
elementbase(xml, diagram)
|
87
|
+
serialize(xml, diagram.nodes)
|
88
|
+
serialize(xml, diagram.connections)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def view_node_attrs(view_node, x_offset = 0, y_offset = 0)
|
93
|
+
attrs = {
|
94
|
+
identifier: identifier(view_node.id),
|
95
|
+
elementRef: nil,
|
96
|
+
"xsi:type" => view_node.type,
|
97
|
+
"x" => view_node.bounds ? (view_node.bounds&.x + x_offset).round : nil,
|
98
|
+
"y" => view_node.bounds ? (view_node.bounds&.y + y_offset).round : nil,
|
99
|
+
"w" => view_node.bounds&.width&.round,
|
100
|
+
"h" => view_node.bounds&.height&.round
|
101
|
+
}
|
102
|
+
if view_node.archimate_element
|
103
|
+
attrs[:elementRef] = identifier(view_node.archimate_element)
|
104
|
+
elsif view_node.model
|
105
|
+
# Since it doesn't seem to be forbidden, we just assume we can use
|
106
|
+
# the elementref for views in views
|
107
|
+
attrs[:elementRef] = view_node.model
|
108
|
+
attrs[:type] = "model"
|
109
|
+
end
|
110
|
+
remove_nil_values(attrs)
|
111
|
+
end
|
112
|
+
|
113
|
+
def serialize_view_node(xml, view_node, x_offset = 0, y_offset = 0)
|
114
|
+
attrs = view_node_attrs(view_node, x_offset, y_offset)
|
115
|
+
xml.node(attrs) do
|
116
|
+
serialize_label(xml, view_node.name, :label)
|
117
|
+
serialize(xml, view_node.style) if view_node.style
|
118
|
+
view_node.nodes.each do |c|
|
119
|
+
serialize_view_node(xml, c) # , view_node_attrs[:x].to_f, view_node_attrs[:y].to_f)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def font_style_string(font)
|
125
|
+
case font&.style
|
126
|
+
when 1
|
127
|
+
"italic"
|
128
|
+
when 2
|
129
|
+
"bold"
|
130
|
+
when 3
|
131
|
+
"bold italic"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def serialize_connection(xml, sc)
|
136
|
+
xml.connection(
|
137
|
+
identifier: identifier(sc.id),
|
138
|
+
relationshipRef: identifier(sc.relationship),
|
139
|
+
"xsi:type": sc.type,
|
140
|
+
source: identifier(sc.source),
|
141
|
+
target: identifier(sc.target)
|
142
|
+
) do
|
143
|
+
serialize(xml, sc.style)
|
144
|
+
serialize(xml, sc.bendpoints)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def meff_type(el_type)
|
149
|
+
el_type.sub(/^/, "")
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'archimate/file_formats/model_exchange_file/xml_lang_string'
|
4
|
+
|
5
|
+
module Archimate
|
6
|
+
module FileFormats
|
7
|
+
class Writer
|
8
|
+
attr_reader :model
|
9
|
+
|
10
|
+
def self.write(model, output_io)
|
11
|
+
writer = new(model)
|
12
|
+
writer.write(output_io)
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(model)
|
16
|
+
@model = model
|
17
|
+
end
|
18
|
+
|
19
|
+
def serialize(xml, collection)
|
20
|
+
Array(collection).each do |item|
|
21
|
+
case item
|
22
|
+
when DataModel::Location
|
23
|
+
serialize_location(xml, item)
|
24
|
+
when DataModel::Bounds
|
25
|
+
serialize_bounds(xml, item)
|
26
|
+
when DataModel::ViewNode
|
27
|
+
serialize_view_node(xml, item)
|
28
|
+
when DataModel::Diagram
|
29
|
+
serialize_diagram(xml, item)
|
30
|
+
when DataModel::Documentation
|
31
|
+
ModelExchangeFile::XmlLangString.new(item, :documentation).serialize(xml)
|
32
|
+
when DataModel::Element
|
33
|
+
serialize_element(xml, item)
|
34
|
+
when DataModel::Organization
|
35
|
+
serialize_organization(xml, item)
|
36
|
+
when DataModel::Property
|
37
|
+
serialize_property(xml, item)
|
38
|
+
when DataModel::Relationship
|
39
|
+
serialize_relationship(xml, item)
|
40
|
+
when DataModel::Connection
|
41
|
+
serialize_connection(xml, item)
|
42
|
+
when DataModel::Style
|
43
|
+
serialize_style(xml, item)
|
44
|
+
else
|
45
|
+
raise TypeError, "Unexpected item type #{item.class}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def remove_nil_values(h)
|
51
|
+
h.delete_if { |_k, v| v.nil? }
|
52
|
+
h
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module Archimate
|
2
|
+
module Lint
|
3
|
+
STOP_WORDS = %w(
|
4
|
+
a able about above according accordingly across actually after afterwards again against all allow allows
|
5
|
+
almost alone along already also although always am among amongst amoungst amount an and another any anybody
|
6
|
+
anyhow anyone anything anyway anyways anywhere apart appear appreciate appropriate are around as aside ask
|
7
|
+
asking associated at available away awfully back be became because become becomes becoming been before
|
8
|
+
beforehand behind being believe below beside besides best better between beyond bill both bottom brief but
|
9
|
+
by call came can can't cannot cant cause causes certain certainly changes clearly co com come comes computer
|
10
|
+
con concerning consequently consider considering contain containing contains corresponding could couldn't
|
11
|
+
couldnt course cry currently de dear definitely describe described despite detail did didn't different do
|
12
|
+
does doesn't doing don't done down downwards due during each edu eg eight either eleven else elsewhere empty
|
13
|
+
enough entirely especially et etc even ever every everybody everyone everything everywhere ex exactly example
|
14
|
+
except far few fifteen fifth fify fill find fire first five followed following follows for former formerly
|
15
|
+
forth forty found four from front full further furthermore get gets getting give given gives go goes going
|
16
|
+
gone got gotten greetings had hadn't happens hardly has hasn't hasnt have haven't having he he's hello help
|
17
|
+
hence her here here's hereafter hereby herein hereupon hers herself hi him himself his hither hopefully how
|
18
|
+
howbeit however hundred i i'd i'll i'm i've ie if ignored immediate in inasmuch inc indeed indicate indicated
|
19
|
+
indicates inner insofar instead interest into inward is isn't it it'd it'll it's its itself just keep keeps
|
20
|
+
kept know known knows last lately later latter latterly least less lest let let's like liked likely little
|
21
|
+
look looking looks ltd made mainly many may maybe me mean meanwhile merely might mill mine more moreover most
|
22
|
+
mostly move much must my myself name namely nd near nearly necessary need needs neither never nevertheless
|
23
|
+
new next nine no nobody non none noone nor normally not nothing novel now nowhere obviously of off often oh
|
24
|
+
ok okay old on once one ones only onto or other others otherwise ought our ours ourselves out outside over
|
25
|
+
overall own part particular particularly per perhaps placed please plus possible presumably probably provides
|
26
|
+
put que quite qv rather rd re really reasonably regarding regardless regards relatively respectively right
|
27
|
+
said same saw say saying says second secondly see seeing seem seemed seeming seems seen self selves sensible
|
28
|
+
sent serious seriously seven several shall she should shouldn't show side since sincere six sixty so some
|
29
|
+
somebody somehow someone something sometime sometimes somewhat somewhere soon sorry specified specify
|
30
|
+
specifying still sub such sup sure system take taken tell ten tends th than thank thanks thanx that that's
|
31
|
+
thats the their theirs them themselves then thence there there's thereafter thereby therefore therein theres
|
32
|
+
thereupon these they they'd they'll they're they've thick thin think third this thorough thoroughly those
|
33
|
+
though three through throughout thru thus tis to together too took top toward towards tried tries truly try
|
34
|
+
trying twas twelve twenty twice two un under unfortunately unless unlikely until unto up upon us use used
|
35
|
+
useful uses using usually value various very via viz vs want wants was wasn't way we we'd we'll we're we've
|
36
|
+
welcome well went were weren't what what's whatever when whence whenever where where's whereafter whereas
|
37
|
+
whereby wherein whereupon wherever whether which while whither who who's whoever whole whom whose why will
|
38
|
+
willing wish with within without won't wonder would wouldn't yes yet you you'd you'll you're you've your
|
39
|
+
yours yourself yourselves zero).freeze
|
40
|
+
|
41
|
+
class DuplicateEntities
|
42
|
+
attr_reader :word_count
|
43
|
+
# TODO: Add option to permit additional project specific stop words
|
44
|
+
# TODO: Do relationships after elements are merged
|
45
|
+
def initialize(model)
|
46
|
+
@model = model
|
47
|
+
@dupes = nil
|
48
|
+
@count = nil
|
49
|
+
@word_count = {}
|
50
|
+
@ignored_entity_types = %w(Junction AndJunction OrJunction)
|
51
|
+
dupe_list
|
52
|
+
end
|
53
|
+
|
54
|
+
def count
|
55
|
+
@dupes.reduce(0) { |total, (_tag, ary)| total + ary.size }
|
56
|
+
end
|
57
|
+
|
58
|
+
def empty?
|
59
|
+
count.zero?
|
60
|
+
end
|
61
|
+
|
62
|
+
def each(&block)
|
63
|
+
@dupes.keys.sort.each do |name|
|
64
|
+
ary = @dupes[name]
|
65
|
+
element_type = ary.first.type
|
66
|
+
block.call(element_type, name, ary)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
protected
|
71
|
+
def candidate_entities
|
72
|
+
@model.entities.select do |entity|
|
73
|
+
(entity.is_a?(DataModel::Element) || entity.is_a?(DataModel::Relationship)) &&
|
74
|
+
!@ignored_entity_types.include?(entity.type)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def dupe_list
|
79
|
+
@dupes = candidate_entities.each_with_object({}) do |entity, hash|
|
80
|
+
tag = entity_hash_name(entity)
|
81
|
+
hash[tag] = hash.fetch(tag, []) << entity
|
82
|
+
end
|
83
|
+
@dupes.delete_if { |_tag, entities| entities.size <= 1 }
|
84
|
+
# @word_count.sort_by(&:last).reverse.each { |ak, av| puts "#{ak}: #{av}" }
|
85
|
+
@dupes
|
86
|
+
end
|
87
|
+
|
88
|
+
def entity_hash_name(entity)
|
89
|
+
layer = DataModel::Constants::ELEMENT_LAYER.fetch(entity.type, nil)
|
90
|
+
layer_sort_order = layer ? DataModel::Constants::LAYER_ELEMENTS.keys.index(layer) : 9
|
91
|
+
[
|
92
|
+
entity.class.name, # Taking advantage of Element being before Relationship
|
93
|
+
layer_sort_order.to_s,
|
94
|
+
entity.type,
|
95
|
+
simplify(entity)
|
96
|
+
].join("/")
|
97
|
+
end
|
98
|
+
|
99
|
+
# This method takes an entity name and simplifies it for duplicate determination
|
100
|
+
# This might be configurable in the future
|
101
|
+
# 1. names are explicitly identical
|
102
|
+
# 2. names differ only in case
|
103
|
+
# 3. names differ only in whitespace
|
104
|
+
# 4. names differ only in punctuation
|
105
|
+
# 5. names differ only by stop-words (list of words such as "the", "api", etc.)
|
106
|
+
def simplify(entity)
|
107
|
+
name = entity.name&.dup || ""
|
108
|
+
name.sub!("(copy)", "") # (copy) is a special case inserted by the Archi tool
|
109
|
+
name.downcase!
|
110
|
+
name.gsub!(/[[:punct:]]/, "") unless entity.is_a?(DataModel::Relationship)
|
111
|
+
name.strip!
|
112
|
+
words = name.split(/\s/)
|
113
|
+
words.each { |word| @word_count[word] = @word_count.fetch(word, 0) + 1 }
|
114
|
+
name = words.reject { |word| STOP_WORDS.include?(word) }.join("")
|
115
|
+
name.delete!(" \t\n\r")
|
116
|
+
name = "#{name}:#{entity.source}:#{entity.target}" if entity.is_a?(DataModel::Relationship)
|
117
|
+
name
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Archimate
|
3
|
+
module Lint
|
4
|
+
# lint notes
|
5
|
+
#
|
6
|
+
# [x] Unused element (not used in a view)
|
7
|
+
# [x] Unused relation (not used in a view)
|
8
|
+
# [x] Object in a Viewpoint (invalid object for viewpoint)
|
9
|
+
# [x] Duplicate same name for type
|
10
|
+
# [x] empty view
|
11
|
+
# [?] visual nesting without relationship
|
12
|
+
# [ ] Warn about sketch model
|
13
|
+
# [x] warn about names with (copy)
|
14
|
+
# [x] blank element names
|
15
|
+
class Linter
|
16
|
+
include FileFormats::ArchimateV2
|
17
|
+
|
18
|
+
attr_reader :model
|
19
|
+
|
20
|
+
def initialize(model)
|
21
|
+
@model = model
|
22
|
+
@indent = "\n" + " " * 8
|
23
|
+
end
|
24
|
+
|
25
|
+
# TODO: consider a means to sort lint issues by entity instead of lint category
|
26
|
+
# this would point out the particularly problematic items that could be
|
27
|
+
# dealt with appropriately.
|
28
|
+
def report(output_io)
|
29
|
+
[
|
30
|
+
[unused_elements, "Unused Element"],
|
31
|
+
[duplicate_elements, "Duplicate Items"],
|
32
|
+
[entity_naming_rules, "Naming Rules"],
|
33
|
+
[unused_relationships, "Unused Relationship"],
|
34
|
+
[duplicate_relationships, "Duplicate Relationships"],
|
35
|
+
[empty_views, "Empty View"],
|
36
|
+
[invalid_for_viewpoint, "Invalid Type for Viewpoint"],
|
37
|
+
[nesting_without_relation, "Visual Nesting"]
|
38
|
+
]
|
39
|
+
.map { |issues, title| issues.map { |issue| "#{title}: #{format_issue(issue)}" } }
|
40
|
+
.tap { |issues| report_subsection(issues, output_io) }
|
41
|
+
.tap { |issues| output_io.puts("Total Issues: #{issues.flatten.size}") }
|
42
|
+
end
|
43
|
+
|
44
|
+
def format_issue(issue)
|
45
|
+
ary = Array(issue)
|
46
|
+
return issue if ary.size == 1
|
47
|
+
"#{@indent}#{ary.join(@indent)}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def report_subsection(issues, output_io)
|
51
|
+
issues.each do |sub_issues|
|
52
|
+
output_io.puts(sub_issues)
|
53
|
+
output_io.puts("Sub Total: #{sub_issues.size}")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def unused_elements
|
58
|
+
referenced_elements = diagram_referenced_ids
|
59
|
+
model.elements.reject { |el| referenced_elements.include?(el.id) }
|
60
|
+
end
|
61
|
+
|
62
|
+
def unused_relationships
|
63
|
+
referenced_ids = diagram_referenced_ids
|
64
|
+
model.relationships.reject { |el| referenced_ids.include?(el.id) }
|
65
|
+
end
|
66
|
+
|
67
|
+
def empty_views
|
68
|
+
model.diagrams.select { |diagram| diagram.nodes.empty? }
|
69
|
+
end
|
70
|
+
|
71
|
+
def duplicate_elements
|
72
|
+
duplicates(model.elements, ->(el) { [el.type, name_for_comparison(el.name)] })
|
73
|
+
end
|
74
|
+
|
75
|
+
def duplicate_relationships
|
76
|
+
duplicates(model.relationships, ->(el) { [el.type, el.source, el.target, name_for_comparison(el.name)] })
|
77
|
+
end
|
78
|
+
|
79
|
+
def name_for_comparison(name)
|
80
|
+
name&.strip&.downcase
|
81
|
+
end
|
82
|
+
|
83
|
+
def duplicates(array, group_by_proc)
|
84
|
+
array
|
85
|
+
.group_by { |el| group_by_proc.call(el) }
|
86
|
+
.each_with_object([]) do |(_key, ary), dupes|
|
87
|
+
dupes << ary.map(&:to_s) if ary.size > 1
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def diagram_referenced_ids
|
92
|
+
@ref_ids ||= model.diagrams.inject([]) { |memo, dia| memo.concat(dia.referenced_identified_nodes) }.uniq
|
93
|
+
end
|
94
|
+
|
95
|
+
def invalid_for_viewpoint
|
96
|
+
model.diagrams.each_with_object([]) do |diagram, errors|
|
97
|
+
next if diagram.total_viewpoint?
|
98
|
+
valid_entity_types = VIEWPOINTS[diagram.viewpoint][:entities]
|
99
|
+
valid_relation_types = VIEWPOINTS[diagram.viewpoint][:relations]
|
100
|
+
invalid_elements = diagram.all_nodes.reject do |child|
|
101
|
+
child.element&.type.nil? || valid_entity_types.include?(child.element&.type)
|
102
|
+
end
|
103
|
+
invalid_relations = diagram.connections.reject do |sc|
|
104
|
+
sc.element&.type.nil? || valid_relation_types.include?(sc.element&.type)
|
105
|
+
end
|
106
|
+
next unless !invalid_elements.empty? || !invalid_relations.empty?
|
107
|
+
errors << format(
|
108
|
+
"%s viewpoint %s#{@indent}%s",
|
109
|
+
diagram,
|
110
|
+
diagram.viewpoint,
|
111
|
+
(invalid_elements + invalid_relations).map(&:element).map(&:to_s).join(@indent)
|
112
|
+
)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Nesting is valid for relations:
|
117
|
+
# * CompositionRelationship
|
118
|
+
# * AggregationRelationship
|
119
|
+
# * AssignmentRelationship
|
120
|
+
def nesting_without_relation
|
121
|
+
model.find_by_class(DataModel::ViewNode).each_with_object([]) do |parent, errors|
|
122
|
+
missing_relations = parent.nodes.reject do |child|
|
123
|
+
model.relationships.any? do |rel|
|
124
|
+
parent.archimate_element.nil? ||
|
125
|
+
child.archimate_element.nil? ||
|
126
|
+
(rel.source == parent.archimate_element && rel.target == child.archimate_element)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
errors.concat(missing_relations.map { |child| "#{child.element} should not nest in #{parent.element} without valid relationship" })
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def entity_naming_rules
|
134
|
+
model.elements.each_with_object([]) do |entity, errors|
|
135
|
+
if entity.name.nil? || entity.name.empty?
|
136
|
+
errors << "#{entity} name is empty"
|
137
|
+
elsif entity.name.size < 2
|
138
|
+
errors << "#{entity} name #{entity.name.inspect} is too short"
|
139
|
+
elsif entity.name.include?("(copy)")
|
140
|
+
errors << "#{entity} name #{entity.name.inspect} contains '(copy)'"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Archimate
|
4
|
+
# This is a helper module to make logging calls a little less clunky
|
5
|
+
module Logging
|
6
|
+
def update(sym, val)
|
7
|
+
@logger = val if sym == :logger
|
8
|
+
end
|
9
|
+
|
10
|
+
def logger
|
11
|
+
unless defined?(@logger)
|
12
|
+
config = Archimate::Config.instance
|
13
|
+
config.add_observer(self)
|
14
|
+
@logger = config.logger
|
15
|
+
end
|
16
|
+
@logger
|
17
|
+
end
|
18
|
+
|
19
|
+
def debug(progname = nil, &block)
|
20
|
+
logger.debug(progname, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def error(progname = nil, &block)
|
24
|
+
logger.error(progname, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
def fatal(progname = nil, &block)
|
28
|
+
logger.fatal(progname, &block)
|
29
|
+
end
|
30
|
+
|
31
|
+
def info(progname = nil, &block)
|
32
|
+
logger.info(progname, &block)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.logger
|
36
|
+
Archimate::Config.instance.logger
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.debug(progname = nil, &block)
|
40
|
+
logger.debug(progname, &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.error(progname = nil, &block)
|
44
|
+
logger.error(progname, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.fatal(progname = nil, &block)
|
48
|
+
logger.fatal(progname, &block)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.info(progname = nil, &block)
|
52
|
+
logger.info(progname, &block)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|