metanorma-plugin-lutaml 0.4.2 → 0.4.6
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/README.adoc +312 -10
- data/lib/metanorma-plugin-lutaml.rb +3 -0
- data/lib/metanorma/plugin/lutaml/liquid/multiply_local_file_system.rb +53 -0
- data/lib/metanorma/plugin/lutaml/liquid_templates/_diagrams_block.liquid +11 -0
- data/lib/metanorma/plugin/lutaml/liquid_templates/_packages.liquid +133 -0
- data/lib/metanorma/plugin/lutaml/liquid_templates/_packages_class.liquid +81 -0
- data/lib/metanorma/plugin/lutaml/liquid_templates/_packages_data_dictionary.liquid +177 -0
- data/lib/metanorma/plugin/lutaml/liquid_templates/_packages_data_dictionary_classes.liquid +43 -0
- data/lib/metanorma/plugin/lutaml/liquid_templates/_packages_data_type.liquid +63 -0
- data/lib/metanorma/plugin/lutaml/liquid_templates/_packages_entity_list.liquid +113 -0
- data/lib/metanorma/plugin/lutaml/liquid_templates/_packages_enum.liquid +63 -0
- data/lib/metanorma/plugin/lutaml/lutaml_diagram_base.rb +81 -0
- data/lib/metanorma/plugin/lutaml/lutaml_diagram_block.rb +5 -60
- data/lib/metanorma/plugin/lutaml/lutaml_diagram_block_macro.rb +20 -0
- data/lib/metanorma/plugin/lutaml/lutaml_figure_inline_macro.rb +23 -0
- data/lib/metanorma/plugin/lutaml/lutaml_uml_attributes_table_preprocessor.rb +11 -10
- data/lib/metanorma/plugin/lutaml/lutaml_uml_datamodel_description_preprocessor.rb +188 -0
- data/lib/metanorma/plugin/lutaml/utils.rb +4 -2
- data/lib/metanorma/plugin/lutaml/version.rb +1 -1
- metadata +15 -2
@@ -0,0 +1,113 @@
|
|
1
|
+
{% for package in context.packages %}
|
2
|
+
{% assign package_name = package.name | downcase | replace: ":", "" | replace: " ", "_" %}
|
3
|
+
{% if additional_context.before and additional_context.before.size > 0 %}
|
4
|
+
{% for before in additional_context.before %}
|
5
|
+
{{ before.text }}
|
6
|
+
{% endfor %}
|
7
|
+
{% endif %}
|
8
|
+
{% capture equalsigns %}{% for count in (1..depth) %}={% endfor %}{% endcapture %}{{equalsigns}} {{ package.name }}
|
9
|
+
[[rc_{{ package_name }}-model_section]]
|
10
|
+
{{equalsigns}}= {{ package.name }}
|
11
|
+
|
12
|
+
{% assign before_package_key = 'before;' | append: package.name %}
|
13
|
+
{% if additional_context[before_package_key] and additional_context[before_package_key].size > 0 %}
|
14
|
+
{% for before in additional_context[before_package_key] %}
|
15
|
+
{{ before.text }}
|
16
|
+
{% endfor %}
|
17
|
+
{% endif %}
|
18
|
+
{% if additional_context.diagram_include_block %}
|
19
|
+
{% for diagram_include_block in additional_context.diagram_include_block %}
|
20
|
+
{% include "diagrams_block", package_name: package_name, image_base_path: diagram_include_block.base_path, text: diagram_include_block.text %}
|
21
|
+
{% endfor %}
|
22
|
+
{% endif %}
|
23
|
+
|
24
|
+
{% if additional_context.include_block and additional_context.include_block.size > 0 %}
|
25
|
+
{% for block in additional_context.include_block %}
|
26
|
+
{% capture block_filename %}{{ block.base_path }}{{ package_name }}{% endcapture %}
|
27
|
+
{% capture block_content %}{% include block_filename %}{% endcapture %}
|
28
|
+
{% unless block_content contains "Liquid error" %}
|
29
|
+
{% if block.text %}
|
30
|
+
{{ block.text }}
|
31
|
+
{% endif %}
|
32
|
+
{{ block_content }}
|
33
|
+
{% endunless %}
|
34
|
+
{% endfor %}
|
35
|
+
{% endif %}
|
36
|
+
|
37
|
+
{% assign include_block_package_key = 'include_block;' | append: package.name %}
|
38
|
+
{% if additional_context[include_block_package_key] and additional_context[include_block_package_key].size > 0 %}
|
39
|
+
{% for block in additional_context[include_block_package_key] %}
|
40
|
+
{% capture block_filename %}{{ block.base_path }}{{ package_name }}{% endcapture %}
|
41
|
+
{% capture block_content %}{% include block_filename %}{% endcapture %}
|
42
|
+
{% unless block_content contains "Liquid error" %}
|
43
|
+
{% if block.text %}
|
44
|
+
{{ block.text }}
|
45
|
+
{% endif %}
|
46
|
+
{{ block_content }}
|
47
|
+
{% endunless %}
|
48
|
+
{% endfor %}
|
49
|
+
{% endif %}
|
50
|
+
|
51
|
+
{{equalsigns}}= Class Definitions
|
52
|
+
{% if package.classes.size > 0 %}
|
53
|
+
.Classes used in {{ package.name }}
|
54
|
+
[cols="2a,6a",options="header"]
|
55
|
+
|===
|
56
|
+
|Class |Description
|
57
|
+
|
58
|
+
{% for klass in package.classes %}
|
59
|
+
|<<{{ klass.name }}-section,{{ klass.name }}>>
|
60
|
+
«{{ klass.stereotype }}»
|
61
|
+
|{{ klass.definition }}
|
62
|
+
|
63
|
+
{% endfor %}
|
64
|
+
|===
|
65
|
+
{% endif %}
|
66
|
+
|
67
|
+
{% if package.data_types.size > 0 %}
|
68
|
+
.Data Types used in {{ package.name }}
|
69
|
+
[cols="2,6",options="header"]
|
70
|
+
|===
|
71
|
+
|Name |Description
|
72
|
+
|
73
|
+
{% for klass in package.data_types %}
|
74
|
+
|<<{{ klass.name }}-section,{{ klass.name }}>>
|
75
|
+
|{{ klass.definition }}
|
76
|
+
|
77
|
+
{% endfor %}
|
78
|
+
|
79
|
+
|===
|
80
|
+
{% endif %}
|
81
|
+
|
82
|
+
{% if package.enums.size > 0 %}
|
83
|
+
.Enumerated Classes used in {{ package.name }}
|
84
|
+
[cols="2a,6a",options="header"]
|
85
|
+
|===
|
86
|
+
|Name |Description
|
87
|
+
|
88
|
+
{% for klass in package.enums %}
|
89
|
+
|<<{{ klass.name }}-section,{{ klass.name }}>>
|
90
|
+
|{{ klass.definition }}
|
91
|
+
|
92
|
+
{% endfor %}
|
93
|
+
|
94
|
+
|===
|
95
|
+
{% endif %}
|
96
|
+
|
97
|
+
{% assign after_package_key = 'after;' | append: package.name %}
|
98
|
+
{% if additional_context[after_package_key] %}
|
99
|
+
{{equalsigns}}= Additional Information
|
100
|
+
{% for after in additional_context[after_package_key] %}
|
101
|
+
{{ after.text }}
|
102
|
+
{% endfor %}
|
103
|
+
{% endif %}
|
104
|
+
{% if package.packages.size > 0 and render_nested_packages %}
|
105
|
+
{% assign nested_depth = depth | plus: 1 %}{% include "packages_entity_list", depth: nested_depth, context: package %}
|
106
|
+
{% endif %}
|
107
|
+
{% endfor %}
|
108
|
+
|
109
|
+
{% if additional_context.after and additional_context.after.size > 0 %}
|
110
|
+
{% for after in additional_context.after %}
|
111
|
+
{{ after.text }}
|
112
|
+
{% endfor %}
|
113
|
+
{% endif %}
|
@@ -0,0 +1,63 @@
|
|
1
|
+
{% assign is_klass_spare = klass.name | slice: 0,5 %}
|
2
|
+
{% if is_klass_spare == 'old: ' %}{% continue %}
|
3
|
+
{% elsif is_klass_spare == 'Spare' %}{% continue %}
|
4
|
+
{% endif %}
|
5
|
+
{% assign klass_name = klass.name | downcase | replace: ':', '' | replace: ' ', '_' %}
|
6
|
+
[[tab-P-{{ package_name }}-E-{{ klass_name }}]]
|
7
|
+
.Elements of {{ package.name }}::{{ klass.name }}
|
8
|
+
[width="100%",cols="a,a,a,a,a,a,a,a"]
|
9
|
+
|===
|
10
|
+
|
11
|
+
h|Name: 7+| {{ klass.name }}
|
12
|
+
|
13
|
+
h|Definition: 7+| {{ klass.definition | html2adoc }}
|
14
|
+
|
15
|
+
h|Stereotype: 7+| {{ klass.stereotype | default: 'interface' }}
|
16
|
+
|
17
|
+
{% assign inherited = klass.associations | where: "member_end_type", "inheritance" %}
|
18
|
+
{% if inherited.size > 0 %}
|
19
|
+
h|Inheritance from: 7+| {{ inherited | map: 'member_end' | join: ", " }}
|
20
|
+
{% endif %}
|
21
|
+
|
22
|
+
{% assign generalizations = klass.associations | where: "member_end_type", "generalization" %}
|
23
|
+
{% if generalizations.size > 0 %}
|
24
|
+
h|Generalization of: 7+| {{ generalizations | map: 'member_end' | join: ", " }}
|
25
|
+
{% endif %}
|
26
|
+
|
27
|
+
h|Abstract: 7+| {{ klass.is_abstract }}
|
28
|
+
{% assign aggregations = klass.associations | where: "member_end_type", "aggregation" %}
|
29
|
+
{% if aggregations.size > 0 %}
|
30
|
+
.{{aggregations.size | plus: 1}}+h|Associations:
|
31
|
+
4+|_Association with:_
|
32
|
+
|_Obligation_
|
33
|
+
| _Maximum occurrence_
|
34
|
+
|_Provides:_
|
35
|
+
|
36
|
+
{% for assoc in aggregations %}
|
37
|
+
4+| {{assoc.member_end}}
|
38
|
+
| {% if assoc.member_end_cardinality %}{{ assoc.member_end_cardinality.min }}{% endif %}
|
39
|
+
| {% if assoc.member_end_cardinality %}{{ assoc.member_end_cardinality.max }}{% endif %}
|
40
|
+
| {{ assoc.member_end_attribute_name }}
|
41
|
+
|
42
|
+
{% endfor %}
|
43
|
+
{% else %}
|
44
|
+
|
45
|
+
.1+h|Associations: 7+| (none)
|
46
|
+
{% endif %}
|
47
|
+
{% if klass.values.size > 0 %}
|
48
|
+
.{{klass.values.size | plus: 1}}+h|Values:
|
49
|
+
| _Name_
|
50
|
+
6+| _Definition_
|
51
|
+
|
52
|
+
{% for value in klass.values %}
|
53
|
+
| {{value.name}}
|
54
|
+
6+| {{ value.definition | html2adoc }}
|
55
|
+
|
56
|
+
{% endfor %}
|
57
|
+
{% else %}
|
58
|
+
.1+h|Values:
|
59
|
+
7+| (none)
|
60
|
+
{% endif %}
|
61
|
+
|
62
|
+
|
63
|
+
|===
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "liquid"
|
4
|
+
require "asciidoctor"
|
5
|
+
require "asciidoctor/reader"
|
6
|
+
require "lutaml"
|
7
|
+
require "lutaml/uml"
|
8
|
+
require "lutaml/formatter"
|
9
|
+
require "metanorma/plugin/lutaml/utils"
|
10
|
+
|
11
|
+
module Metanorma
|
12
|
+
module Plugin
|
13
|
+
module Lutaml
|
14
|
+
module LutamlDiagramBase
|
15
|
+
def process(parent, reader, attrs)
|
16
|
+
uml_document = ::Lutaml::Uml::Parsers::Dsl.parse(lutaml_file(parent.document, reader))
|
17
|
+
filename = generate_file(parent, reader, uml_document)
|
18
|
+
through_attrs = generate_attrs(attrs)
|
19
|
+
through_attrs["target"] = filename
|
20
|
+
through_attrs["title"] = uml_document.caption
|
21
|
+
create_image_block(parent, through_attrs)
|
22
|
+
rescue StandardError => e
|
23
|
+
abort(parent, reader, attrs, e.message)
|
24
|
+
end
|
25
|
+
|
26
|
+
def lutaml_file(reader)
|
27
|
+
raise 'Implement me!'
|
28
|
+
end
|
29
|
+
|
30
|
+
protected
|
31
|
+
|
32
|
+
def abort(parent, reader, attrs, msg)
|
33
|
+
warn(msg)
|
34
|
+
attrs["language"] = "lutaml"
|
35
|
+
source = reader.respond_to?(:source) ? reader.source : reader
|
36
|
+
create_listing_block(
|
37
|
+
parent,
|
38
|
+
source,
|
39
|
+
attrs.reject { |k, _v| k == 1 }
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
# if no :imagesdir: leave image file in lutaml
|
44
|
+
def generate_file(parent, _reader, uml_document)
|
45
|
+
formatter = ::Lutaml::Formatter::Graphviz.new
|
46
|
+
formatter.type = :png
|
47
|
+
|
48
|
+
imagesdir = if parent.document.attr("imagesdir")
|
49
|
+
File.join(parent.document.attr("imagesdir"), "lutaml")
|
50
|
+
else
|
51
|
+
"lutaml"
|
52
|
+
end
|
53
|
+
result_path = Utils.relative_file_path(parent.document, imagesdir)
|
54
|
+
result_pathname = Pathname.new(result_path)
|
55
|
+
result_pathname.mkpath
|
56
|
+
File.writable?(result_pathname) || raise("Destination path #{result_path} not writable for Lutaml!")
|
57
|
+
|
58
|
+
outfile = Tempfile.new(["lutaml", ".png"])
|
59
|
+
outfile.binmode
|
60
|
+
outfile.puts(formatter.format(uml_document))
|
61
|
+
|
62
|
+
# Warning: metanorma/metanorma-standoc#187
|
63
|
+
# Windows Ruby 2.4 will crash if a Tempfile is "mv"ed.
|
64
|
+
# This is why we need to copy and then unlink.
|
65
|
+
filename = File.basename(outfile.path)
|
66
|
+
FileUtils.cp(outfile, result_pathname) && outfile.unlink
|
67
|
+
|
68
|
+
File.join(result_pathname, filename)
|
69
|
+
end
|
70
|
+
|
71
|
+
def generate_attrs(attrs)
|
72
|
+
%w(id align float title role width height alt)
|
73
|
+
.reduce({}) do |memo, key|
|
74
|
+
memo[key] = attrs[key] if attrs.has_key? key
|
75
|
+
memo
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -1,40 +1,21 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
4
|
-
require "asciidoctor"
|
5
|
-
require "asciidoctor/reader"
|
6
|
-
require "lutaml"
|
7
|
-
require "lutaml/uml"
|
8
|
-
require "metanorma/plugin/lutaml/utils"
|
3
|
+
require "metanorma/plugin/lutaml/lutaml_diagram_base"
|
9
4
|
|
10
5
|
module Metanorma
|
11
6
|
module Plugin
|
12
7
|
module Lutaml
|
13
8
|
class LutamlDiagramBlock < Asciidoctor::Extensions::BlockProcessor
|
9
|
+
include LutamlDiagramBase
|
10
|
+
|
14
11
|
use_dsl
|
15
12
|
named :lutaml_diagram
|
16
13
|
on_context :literal
|
17
14
|
parse_content_as :raw
|
18
15
|
|
19
|
-
def
|
20
|
-
warn(msg)
|
21
|
-
attrs["language"] = "lutaml"
|
22
|
-
create_listing_block(
|
23
|
-
parent,
|
24
|
-
reader.source,
|
25
|
-
attrs.reject { |k, _v| k == 1 }
|
26
|
-
)
|
27
|
-
end
|
16
|
+
def lutaml_file(document, reader)
|
28
17
|
|
29
|
-
|
30
|
-
uml_document = ::Lutaml::Uml::Parsers::Dsl.parse(lutaml_temp(parent.document, reader))
|
31
|
-
filename = generate_file(parent, reader, uml_document)
|
32
|
-
through_attrs = generate_attrs(attrs)
|
33
|
-
through_attrs["target"] = filename
|
34
|
-
through_attrs["title"] = uml_document.caption
|
35
|
-
create_image_block(parent, through_attrs)
|
36
|
-
rescue StandardError => e
|
37
|
-
abort(parent, reader, attrs, e.message)
|
18
|
+
lutaml_temp(document, reader)
|
38
19
|
end
|
39
20
|
|
40
21
|
private
|
@@ -45,42 +26,6 @@ module Metanorma
|
|
45
26
|
temp_file.rewind
|
46
27
|
temp_file
|
47
28
|
end
|
48
|
-
|
49
|
-
# if no :imagesdir: leave image file in lutaml
|
50
|
-
def generate_file(parent, _reader, uml_document)
|
51
|
-
formatter = ::Lutaml::Uml::Formatter::Graphviz.new
|
52
|
-
formatter.type = :png
|
53
|
-
|
54
|
-
imagesdir = if parent.document.attr("imagesdir")
|
55
|
-
File.join(parent.document.attr("imagesdir"), "lutaml")
|
56
|
-
else
|
57
|
-
"lutaml"
|
58
|
-
end
|
59
|
-
result_path = Utils.relative_file_path(parent.document, imagesdir)
|
60
|
-
result_pathname = Pathname.new(result_path)
|
61
|
-
result_pathname.mkpath
|
62
|
-
File.writable?(result_pathname) || raise("Destination path #{result_path} not writable for Lutaml!")
|
63
|
-
|
64
|
-
outfile = Tempfile.new(["lutaml", ".png"])
|
65
|
-
outfile.binmode
|
66
|
-
outfile.puts(formatter.format(uml_document))
|
67
|
-
|
68
|
-
# Warning: metanorma/metanorma-standoc#187
|
69
|
-
# Windows Ruby 2.4 will crash if a Tempfile is "mv"ed.
|
70
|
-
# This is why we need to copy and then unlink.
|
71
|
-
filename = File.basename(outfile.path)
|
72
|
-
FileUtils.cp(outfile, result_pathname) && outfile.unlink
|
73
|
-
|
74
|
-
File.join(result_pathname, filename)
|
75
|
-
end
|
76
|
-
|
77
|
-
def generate_attrs(attrs)
|
78
|
-
%w(id align float title role width height alt)
|
79
|
-
.reduce({}) do |memo, key|
|
80
|
-
memo[key] = attrs[key] if attrs.has_key? key
|
81
|
-
memo
|
82
|
-
end
|
83
|
-
end
|
84
29
|
end
|
85
30
|
end
|
86
31
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "metanorma/plugin/lutaml/lutaml_diagram_base"
|
4
|
+
|
5
|
+
module Metanorma
|
6
|
+
module Plugin
|
7
|
+
module Lutaml
|
8
|
+
class LutamlDiagramBlockMacro < Asciidoctor::Extensions::BlockMacroProcessor
|
9
|
+
include LutamlDiagramBase
|
10
|
+
|
11
|
+
use_dsl
|
12
|
+
named :lutaml_diagram
|
13
|
+
|
14
|
+
def lutaml_file(document, file_path)
|
15
|
+
File.new(Utils.relative_file_path(document, file_path))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Metanorma
|
4
|
+
module Plugin
|
5
|
+
module Lutaml
|
6
|
+
class LutamlFigureInlineMacro < Asciidoctor::Extensions::InlineMacroProcessor
|
7
|
+
include LutamlDiagramBase
|
8
|
+
|
9
|
+
use_dsl
|
10
|
+
named :lutaml_figure
|
11
|
+
|
12
|
+
def process(parent, _target, attrs)
|
13
|
+
diagram_key = [attrs["package"], attrs["name"]].compact.join(":")
|
14
|
+
return if parent.document.attributes['lutaml_figure_id'].nil?
|
15
|
+
xmi_id = parent.document.attributes['lutaml_figure_id'][diagram_key]
|
16
|
+
return unless xmi_id
|
17
|
+
|
18
|
+
%Q(<xref target="figure-#{xmi_id}"></xref>)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -14,7 +14,7 @@ module Metanorma
|
|
14
14
|
# @example [lutaml_uml_attributes_table,path/to/lutaml,EntityName]
|
15
15
|
class LutamlUmlAttributesTablePreprocessor < Asciidoctor::Extensions::Preprocessor
|
16
16
|
MARCO_REGEXP =
|
17
|
-
/\[lutaml_uml_attributes_table,([^,]+),?(
|
17
|
+
/\[lutaml_uml_attributes_table,([^,]+),?([^,]+),?(.+?)?\]/
|
18
18
|
# search document for block `datamodel_attributes_table`
|
19
19
|
# read include derectives that goes after that in block and transform
|
20
20
|
# into yaml2text blocks
|
@@ -36,15 +36,16 @@ module Metanorma
|
|
36
36
|
input_lines.each_with_object([]) do |line, result|
|
37
37
|
if match = line.match(MARCO_REGEXP)
|
38
38
|
lutaml_path = match[1]
|
39
|
-
entity_name = match[
|
40
|
-
|
39
|
+
entity_name = match[2]
|
40
|
+
skip_headers = match[3]
|
41
|
+
result.push(*parse_marco(lutaml_path, entity_name, document, skip_headers))
|
41
42
|
else
|
42
43
|
result.push(line)
|
43
44
|
end
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
47
|
-
def parse_marco(lutaml_path, entity_name, document)
|
48
|
+
def parse_marco(lutaml_path, entity_name, document, skip_headers)
|
48
49
|
lutaml_document = lutaml_document_from_file(document, lutaml_path)
|
49
50
|
.serialized_document
|
50
51
|
entities = [lutaml_document["classes"], lutaml_document["enums"]]
|
@@ -53,12 +54,12 @@ module Metanorma
|
|
53
54
|
entity_definition = entities.detect do |klass|
|
54
55
|
klass["name"] == entity_name.strip
|
55
56
|
end
|
56
|
-
model_representation(entity_definition, document)
|
57
|
+
model_representation(entity_definition, document, skip_headers)
|
57
58
|
end
|
58
59
|
|
59
|
-
def model_representation(entity_definition, document)
|
60
|
+
def model_representation(entity_definition, document, skip_headers)
|
60
61
|
render_result, errors = Utils.render_liquid_string(
|
61
|
-
template_string: table_template,
|
62
|
+
template_string: table_template(skip_headers),
|
62
63
|
context_items: entity_definition,
|
63
64
|
context_name: "definition",
|
64
65
|
document: document
|
@@ -68,9 +69,9 @@ module Metanorma
|
|
68
69
|
end
|
69
70
|
|
70
71
|
# rubocop:disable Layout/IndentHeredoc
|
71
|
-
def table_template
|
72
|
+
def table_template(skip_headers)
|
72
73
|
<<~TEMPLATE
|
73
|
-
=== {{ definition.name }}
|
74
|
+
#{"=== {{ definition.name }}" unless skip_headers}
|
74
75
|
{{ definition.definition }}
|
75
76
|
|
76
77
|
{% if definition.attributes %}
|
@@ -89,7 +90,7 @@ module Metanorma
|
|
89
90
|
|Name |Definition |Mandatory/ Optional/ Conditional |Max Occur |Data Type
|
90
91
|
|
91
92
|
{% for item in definition.attributes %}
|
92
|
-
|{{ item.name }} |{% if item.definition %}{{ item.definition }}{%
|
93
|
+
|{{ item.name }} |{% if item.definition %}{{ item.definition }}{% endif %} |{% if item.cardinality.min == "0" %}O{% else %}M{% endif %} |{% if item.cardinality.max == "*" %}N{% else %}1{% endif %} |{% if item.origin %}<<{{ item.origin }}>>{% endif %} `{{ item.type }}`
|
93
94
|
{% endfor %}
|
94
95
|
|===
|
95
96
|
{% endif %}
|