metanorma-plugin-lutaml 0.7.46 → 0.7.49

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a35215ee0b1f56e7a7b8896e512da9fb7aa190244988efa0b173bf72ed84202c
4
- data.tar.gz: ee445b71760e111e26896f30559e35d4b8ea86a03cc20c0c000aebd7c43debb7
3
+ metadata.gz: 7f35e27d23b6509b4a0ddb778d7e5706782a8f6b3a8a3d08de0488b2ff74aea6
4
+ data.tar.gz: 9d72a1aa1bc17a5375e15fa9d1575e21409714a28d6a5a2ca3516426a510ad95
5
5
  SHA512:
6
- metadata.gz: 9ff29f6c04bd2483e359b5bb3bc3e0e9bfbb1254df12aed87453ab05b7e6f329583d80be38113dedc9aa6e18e71871a1869fc74e85c0b236bf069176e81de886
7
- data.tar.gz: 9027e9b86616da94c0cd7144858f6ae01de440fc20a18aeb4d2e2a600a19ac37464d1d8fae2a1244e398e96f0502a876e9e306334e0598c0b0e3d53160cc40b5
6
+ metadata.gz: 1eea2b10a5361287562e4c082fa96b2f94cafc97e54dcdb47e758ff4b0973fae4270a2d6099720eb7d98d85dd8da92b74f4137891924fa39ef89737ce702ffab
7
+ data.tar.gz: ffb1271076d8dab3211f552d123aad3bb76e908230fdcacb40b28e1ded86075f0b1f7b744d8ec3769030c8f2f04094f6c0f5687ba4dbfbb165261792bf194cbf
@@ -19,6 +19,9 @@ jobs:
19
19
  uses: metanorma/ci/.github/workflows/rubygems-release.yml@main
20
20
  with:
21
21
  next_version: ${{ github.event.inputs.next_version }}
22
+ release_command: |
23
+ bundle install
24
+ bundle exec rake release
22
25
  secrets:
23
26
  rubygems-api-key: ${{ secrets.METANORMA_CI_RUBYGEMS_API_KEY }}
24
27
  pat_token: ${{ secrets.METANORMA_CI_PAT_TOKEN }}
data/README.adoc CHANGED
@@ -12,6 +12,8 @@ within a Metanorma document:
12
12
  * EXPRESS files (`*.exp`)
13
13
  * LutaML-UML files (`*.lutaml`)
14
14
  * Enterprise Architect exported UML files in XMI format (`*.xmi`)
15
+ * Enterprise Architect QEA files (`*.qea`)
16
+ * Enterprise Architect LUR files (`*.lur`)
15
17
  * LutaML GML Dictionary files (`*.xml`)
16
18
  * JSON or YAML files (`*.json|*.yml|*.yaml`)
17
19
  * XML Schema files (`*.xsd`)
@@ -31,6 +33,8 @@ link:docs/usages/lutaml-uml.adoc[Usage with LutaML files by lutaml_diagram]
31
33
 
32
34
  link:docs/usages/enterprise_architect.adoc[Usage with Enterprise Architect XMI files by lutaml_ea_xmi, lutaml_ea_diagram, lutaml_klass_table or lutaml_enum_table]
33
35
 
36
+ link:docs/usages/enterprise_architect_uml.adoc[Usage with Enterprise Architect UML files (XMI, QEA, LUR) by lutaml_ea_uml]
37
+
34
38
  link:docs/usages/lutaml-gml.adoc[Usage with LutaML GML Dictionary by lutaml_gml_dictionary]
35
39
 
36
40
  link:docs/usages/json_yaml.adoc[Usage with JSON or YAML files by data2text, yaml2text or json2text]
@@ -0,0 +1,173 @@
1
+
2
+ == Usage with Enterprise Architect UML files (XMI, QEA, LUR) by lutaml_ea_uml
3
+
4
+ === General
5
+
6
+ The `lutaml_ea_uml` command renders UML data models from Enterprise Architect
7
+ files using custom Liquid templates. It supports three file formats:
8
+
9
+ * XMI (`*.xmi`) -- Enterprise Architect XML Metadata Interchange export
10
+ * QEA (`*.qea`) -- Enterprise Architect native database format
11
+ * LUR (`*.lur`) -- Enterprise Architect model exchange format
12
+
13
+ The command parses the file into a Liquid template context, allowing full
14
+ control over the rendered output through custom Liquid templates.
15
+
16
+
17
+ === Basic usage
18
+
19
+ [source,adoc]
20
+ ----
21
+ [lutaml_ea_uml,path/to/example.xmi]
22
+ --
23
+ Name of the Lutaml UML Document: {{ context.name }}
24
+
25
+ Number of packages: {{ context.packages | size }}
26
+ --
27
+ ----
28
+
29
+ Where:
30
+
31
+ * `path/to/example.xmi` -- path to the XMI, QEA, or LUR file to render.
32
+
33
+ The content between `--` delimiters is a Liquid template. The parsed UML
34
+ document is available as `context` by default.
35
+
36
+
37
+ === Usage with a configuration file
38
+
39
+ [source,adoc]
40
+ ----
41
+ [lutaml_ea_uml,path/to/example.xmi,path/to/config.yml]
42
+ --
43
+ Name of the Lutaml UML Document: {{ my_uml_document.name }}
44
+
45
+ Number of packages: {{ my_uml_document.packages | size }}
46
+
47
+ {% render "package", package: my_uml_document.packages.first %}
48
+ --
49
+ ----
50
+
51
+ Where:
52
+
53
+ * `path/to/example.xmi` -- path to the XMI, QEA, or LUR file.
54
+ * `path/to/config.yml` -- path to the YAML configuration file.
55
+
56
+
57
+ === Configuration file format
58
+
59
+ [source,yaml]
60
+ ----
61
+ ---
62
+ ea_extension:
63
+ - "CityGML_MDG_Technology.xml"
64
+ - "ISO19103MDG v1.0.0-beta.xml"
65
+ context_name: my_uml_document
66
+ template_path: "path/to/liquid/templates"
67
+ guidance: "path/to/guidance.yml"
68
+ ----
69
+
70
+ Where:
71
+
72
+ * `ea_extension` -- optional, list of EA extension XML files to load. Some
73
+ XMI/QEA/LUR files contain elements that cannot be resolved by default (e.g.
74
+ CityGML elements). Load their definitions here. Paths are relative to the
75
+ config YAML file.
76
+
77
+ * `context_name` -- optional, the Liquid context variable name for the parsed
78
+ document. Defaults to `context`. When set, the document is accessible as
79
+ `{{ my_uml_document }}` instead of `{{ context }}`.
80
+
81
+ * `template_path` -- optional, path to a directory containing custom Liquid
82
+ templates. When specified, `render` tags in the block content will use
83
+ templates from this directory.
84
+
85
+ * `guidance` -- optional, path to a YAML guidance file for adding annotations
86
+ to rendered output.
87
+
88
+
89
+ === Usage with document index
90
+
91
+ You can define an XMI/QEA/LUR file index at the document level and reference
92
+ it by name:
93
+
94
+ [source,adoc]
95
+ ----
96
+ :lutaml-xmi-index: my-model; /path/to/example.qea
97
+
98
+ [lutaml_ea_uml,index=my-model]
99
+ --
100
+ Name: {{ context.name }}
101
+ --
102
+ ----
103
+
104
+ Syntax for the index attribute:
105
+
106
+ [source,adoc]
107
+ ----
108
+ :lutaml-xmi-index: index_name; file_path[; config=config_path]
109
+ ----
110
+
111
+ Where:
112
+
113
+ * `index_name` -- name to reference later with `index=`.
114
+ * `file_path` -- path to the XMI, QEA, or LUR file.
115
+ * `config_path` -- optional, path to the configuration YAML file.
116
+
117
+
118
+ === Liquid template context
119
+
120
+ The parsed UML document is exposed to Liquid templates with the following
121
+ structure:
122
+
123
+ * `context.name` -- name of the root UML model.
124
+ * `context.packages` -- array of packages in the model.
125
+ * `context.packages.first.name` -- name of a package.
126
+ * `context.packages.first.packages` -- nested sub-packages.
127
+ * `context.packages.first.classes` -- array of classes in a package.
128
+ * `context.packages.first.classes.first.name` -- name of a class.
129
+ * `context.packages.first.classes.first.attributes` -- array of attributes.
130
+ * `context.packages.first.classes.first.associations` -- array of associations.
131
+
132
+ When `context_name` is set in the configuration, replace `context` with the
133
+ configured name (e.g. `my_uml_document`).
134
+
135
+
136
+ === Example: rendering class tables with a custom template
137
+
138
+ Given a custom template at `templates/_klass.liquid`:
139
+
140
+ [source,liquid]
141
+ ----
142
+ {% for package in context.packages %}
143
+ == {{ package.name }}
144
+
145
+ {% for klass in package.classes %}
146
+ === {{ klass.name }}
147
+
148
+ {{ klass.definition | html2adoc }}
149
+
150
+ [cols="a,a"]
151
+ |===
152
+ | Attribute | Type
153
+
154
+ {% for attr in klass.owned_props %}
155
+ | {{ attr.name }} | {{ attr.type }}
156
+ {% endfor %}
157
+
158
+ |===
159
+ {% endfor %}
160
+ {% endfor %}
161
+ ----
162
+
163
+ The AsciiDoc block would be:
164
+
165
+ [source,adoc]
166
+ ----
167
+ [lutaml_ea_uml,path/to/example.xmi,path/to/config.yml]
168
+ --
169
+ {% render "klass", context: context %}
170
+ --
171
+ ----
172
+
173
+ Where the config specifies `template_path` pointing to the templates directory.
@@ -171,7 +171,7 @@ module Metanorma
171
171
  )
172
172
  parsed_template.assigns["schemas_order"] =
173
173
  options["selected_schemas"]
174
- parsed_template.render.split("\n", -1)
174
+ parsed_template.render
175
175
  end.flatten
176
176
  rescue StandardError => e
177
177
  ::Metanorma::Util.log(
@@ -33,7 +33,7 @@ module Metanorma
33
33
  )
34
34
  end
35
35
 
36
- def get_original_document(parent, index = nil)
36
+ def get_original_document(parent, index = nil) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
37
37
  path = get_path_from_index(parent, index) if index
38
38
 
39
39
  if index && path
@@ -43,11 +43,27 @@ module Metanorma
43
43
  )
44
44
  end
45
45
 
46
- first_path = parent.document.attributes["lutaml_xmi_paths"]&.first
47
- return unless first_path
46
+ # get the first document from lutaml_xmi_cache
47
+ first_path = parent
48
+ .document.attributes["lutaml_xmi_cache"]&.keys&.first
49
+ if first_path
50
+ return lutaml_document_from_file_or_cache(
51
+ parent.document, first_path,
52
+ Metanorma::Plugin::Lutaml::Config::Root.new
53
+ )
54
+ end
55
+
56
+ # get the first document from the first lutaml_xmi_index
57
+ first_index = parent
58
+ .document.attributes["lutaml_xmi_index"]&.keys&.first
59
+
60
+ return unless first_index
61
+
62
+ path_from_index = get_path_from_index(parent, first_index)
63
+ return unless path_from_index
48
64
 
49
65
  lutaml_document_from_file_or_cache(
50
- parent.document, first_path,
66
+ parent.document, path_from_index,
51
67
  Metanorma::Plugin::Lutaml::Config::Root.new
52
68
  )
53
69
  end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "liquid"
4
+ require "asciidoctor"
5
+ require "asciidoctor/reader"
6
+ require "lutaml"
7
+ require_relative "utils"
8
+ require "metanorma/plugin/lutaml/asciidoctor/preprocessor"
9
+ require "metanorma/plugin/lutaml/lutaml_ea_xmi_base"
10
+
11
+ module Metanorma
12
+ module Plugin
13
+ module Lutaml
14
+ # Macro for rendering Lutaml::Uml models which are parsing from
15
+ # XMI/QEA/LUR file
16
+ class LutamlEaUmlPreprocessor < ::Asciidoctor::Extensions::Preprocessor
17
+ include LutamlEaXmiBase
18
+
19
+ MACRO_REGEXP = /\[lutaml_ea_uml,([^,]+),?(.+)?\]/
20
+
21
+ private
22
+
23
+ def parse_result_document(full_path, _guidance)
24
+ case File.extname(full_path).downcase
25
+ when ".xmi"
26
+ ::Lutaml::Xmi::Parsers::Xml.parse(full_path)
27
+ when ".qea"
28
+ ::Lutaml::Qea.parse(full_path)
29
+ when ".lur"
30
+ repo = ::Lutaml::UmlRepository::Repository.from_file(full_path)
31
+ repo.document
32
+ end
33
+ end
34
+
35
+ def process_text_blocks(document, input_lines) # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
36
+ line = input_lines.next
37
+
38
+ process_xmi_index_lines(document, line)
39
+ block_match = line.match(get_macro_regexp)
40
+
41
+ return [line] if block_match.nil?
42
+
43
+ config_yaml_path = block_match[2]&.strip
44
+ filepath_or_index = block_match[1]&.strip
45
+
46
+ lutaml_document, yaml_config = load_lutaml_doc_and_config(
47
+ document,
48
+ filepath_or_index,
49
+ config_yaml_path,
50
+ )
51
+
52
+ block_lines = collect_block_lines(input_lines, input_lines.next)
53
+
54
+ render_result, errors = Utils.render_liquid_string(
55
+ template_string: block_lines.join("\n"),
56
+ contexts: create_default_context_object(
57
+ lutaml_document, yaml_config
58
+ ),
59
+ document: document,
60
+ include_path: template_path(document, yaml_config.template_path),
61
+ )
62
+ Utils.notify_render_errors(document, errors)
63
+
64
+ render_result.split("\n")
65
+ end
66
+
67
+ def create_default_context_object(uml_document, options)
68
+ context_name = "context"
69
+ if options.context_name
70
+ context_name = options.context_name
71
+ end
72
+ contexts = {}
73
+ contexts[context_name] = uml_document.to_liquid
74
+ contexts
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -39,6 +39,61 @@ module Metanorma
39
39
 
40
40
  private
41
41
 
42
+ def lutaml_document_from_file_or_cache(document, file_path, yaml_config, yaml_config_path = nil) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Metrics/CyclomaticComplexity,Layout/LineLength,Metrics/PerceivedComplexity
43
+ full_path = Utils.relative_file_path(document, file_path)
44
+ if document.attributes["lutaml_xmi_cache"] &&
45
+ document.attributes["lutaml_xmi_cache"][full_path]
46
+ return document.attributes["lutaml_xmi_cache"][full_path]
47
+ end
48
+
49
+ guidance = get_guidance(document, yaml_config.guidance)
50
+ result_document = parse_result_document(full_path, guidance)
51
+
52
+ # load EA extensions for Xmi::EaRoot
53
+ yaml_config.ea_extension&.each do |ea_extension_path|
54
+ # resolve paths of ea extensions based on the location of
55
+ # config yaml file
56
+ ea_extension_full_path = File.expand_path(
57
+ ea_extension_path, File.dirname(yaml_config_path)
58
+ )
59
+
60
+ # unload the extension if it is already loaded
61
+ xmi_doc = Nokogiri::XML(File.read(ea_extension_full_path))
62
+ extension_id = Xmi::EaRoot.get_module_name(xmi_doc)
63
+ if Xmi::EaRoot.extension_loaded?(extension_id)
64
+ Xmi::EaRoot.unload_extension(extension_id)
65
+ end
66
+
67
+ Xmi::EaRoot.load_extension(ea_extension_full_path)
68
+ end
69
+
70
+ # store in document.attributes as cache
71
+ document.attributes["lutaml_xmi_cache"] ||= {}
72
+ document.attributes["lutaml_xmi_cache"][full_path] = result_document
73
+
74
+ result_document
75
+ end
76
+
77
+ def get_guidance(document, guidance_config)
78
+ return unless guidance_config
79
+
80
+ guidance_yaml = Utils.relative_file_path(document, guidance_config)
81
+ guidance = Metanorma::Plugin::Lutaml::Config::Guidance.from_yaml(
82
+ File.read(guidance_yaml, encoding: "UTF-8"),
83
+ )
84
+ guidance.to_yaml_hash
85
+ end
86
+
87
+ def parse_yaml_config_file(document, file_path)
88
+ return Metanorma::Plugin::Lutaml::Config::Root.new if file_path.nil?
89
+
90
+ relative_file_path = Utils.relative_file_path(document, file_path)
91
+
92
+ Metanorma::Plugin::Lutaml::Config::Root.from_yaml(
93
+ File.read(relative_file_path, encoding: "UTF-8"),
94
+ )
95
+ end
96
+
42
97
  def get_xmi_path(parent, target, attrs)
43
98
  return get_path_from_index(parent, attrs["index"]) if attrs["index"]
44
99
 
@@ -106,8 +161,8 @@ module Metanorma
106
161
  )
107
162
  end
108
163
 
109
- def load_lutaml_doc_and_config(document, xmi_or_index, config_yaml_path) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
110
- index = xmi_or_index.match(/index=(.*)/)
164
+ def load_lutaml_doc_and_config(document, filepath_or_index, config_yaml_path) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Layout/LineLength
165
+ index = filepath_or_index.match(/index=(.*)/)
111
166
 
112
167
  if index
113
168
  index_name = index[1]
@@ -121,7 +176,7 @@ module Metanorma
121
176
  )
122
177
  end
123
178
 
124
- xmi_or_index = document
179
+ filepath_or_index = document
125
180
  .attributes["lutaml_xmi_index"][index_name][:path]
126
181
  config_yaml_path = document
127
182
  .attributes["lutaml_xmi_index"][index_name][:config]
@@ -130,7 +185,7 @@ module Metanorma
130
185
  yaml_config = parse_yaml_config_file(document, config_yaml_path)
131
186
  lutaml_document = lutaml_document_from_file_or_cache(
132
187
  document,
133
- xmi_or_index,
188
+ filepath_or_index,
134
189
  yaml_config,
135
190
  Utils.relative_file_path(document, config_yaml_path),
136
191
  )
@@ -1,7 +1,7 @@
1
1
  module Metanorma
2
2
  module Plugin
3
3
  module Lutaml
4
- VERSION = "0.7.46".freeze
4
+ VERSION = "0.7.49".freeze
5
5
  end
6
6
  end
7
7
  end
@@ -55,6 +55,8 @@ module Metanorma
55
55
  "lutaml_uml_datamodel_description_preprocessor"
56
56
  autoload :LutamlXmiUmlPreprocessor,
57
57
  "metanorma/plugin/lutaml/lutaml_xmi_uml_preprocessor"
58
+ autoload :LutamlEaUmlPreprocessor,
59
+ "metanorma/plugin/lutaml/lutaml_ea_uml_preprocessor"
58
60
  autoload :LutamlXsdPreprocessor,
59
61
  "metanorma/plugin/lutaml/lutaml_xsd_preprocessor"
60
62
  autoload :ParseError, "metanorma/plugin/lutaml/parse_error"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metanorma-plugin-lutaml
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.46
4
+ version: 0.7.49
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-05-20 00:00:00.000000000 Z
11
+ date: 2026-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciidoctor
@@ -170,6 +170,7 @@ files:
170
170
  - bin/console
171
171
  - bin/setup
172
172
  - docs/usages/enterprise_architect.adoc
173
+ - docs/usages/enterprise_architect_uml.adoc
173
174
  - docs/usages/express.adoc
174
175
  - docs/usages/json_yaml.adoc
175
176
  - docs/usages/lutaml-gml.adoc
@@ -225,6 +226,7 @@ files:
225
226
  - lib/metanorma/plugin/lutaml/lutaml_diagram_block.rb
226
227
  - lib/metanorma/plugin/lutaml/lutaml_diagram_block_macro.rb
227
228
  - lib/metanorma/plugin/lutaml/lutaml_ea_diagram_block_macro.rb
229
+ - lib/metanorma/plugin/lutaml/lutaml_ea_uml_preprocessor.rb
228
230
  - lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb
229
231
  - lib/metanorma/plugin/lutaml/lutaml_ea_xmi_preprocessor.rb
230
232
  - lib/metanorma/plugin/lutaml/lutaml_enum_table_block_macro.rb