metanorma-plugin-lutaml 0.4.2 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,188 @@
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 "metanorma/plugin/lutaml/utils"
9
+
10
+ module Metanorma
11
+ module Plugin
12
+ module Lutaml
13
+ # Macro for quick rendering of datamodel attributes/values table
14
+ # @example [lutaml_uml_attributes_table,path/to/lutaml,EntityName]
15
+ class LutamlUmlDatamodelDescriptionPreprocessor <
16
+ Asciidoctor::Extensions::Preprocessor
17
+ MARCO_REGEXP =
18
+ /\[lutaml_uml_datamodel_description,([^,]+),?(.+)?\]/
19
+ LIQUID_INCLUDE_PATH = File.join(
20
+ Gem.loaded_specs["metanorma-plugin-lutaml"].full_gem_path,
21
+ "lib", "metanorma", "plugin", "lutaml", "liquid_templates"
22
+ )
23
+ DEFAULT_RENDER_INCLUDE = 'packages'.freeze
24
+ RENDER_STYLES_INCLUDES = {
25
+ 'default' => 'packages',
26
+ 'entity_list' => 'packages_entity_list',
27
+ 'data_dictionary' => 'packages_data_dictionary'
28
+ }.freeze
29
+ SUPPORTED_NESTED_MACRO = %w[
30
+ before diagram_include_block after include_block].freeze
31
+ # search document for block `lutaml_uml_datamodel_description`
32
+ # read include derectives that goes after that in block and transform
33
+ # into yaml2text blocks
34
+ def process(document, reader)
35
+ input_lines = reader.readlines.to_enum
36
+ Asciidoctor::Reader.new(processed_lines(document, input_lines))
37
+ end
38
+
39
+ private
40
+
41
+ def lutaml_document_from_file(document, file_path)
42
+ ::Lutaml::Parser
43
+ .parse(File.new(Utils.relative_file_path(document, file_path),
44
+ encoding: "UTF-8"))
45
+ .first
46
+ end
47
+
48
+ def parse_yaml_config_file(document, file_path)
49
+ return {} if file_path.nil?
50
+
51
+ relative_file_path = Utils.relative_file_path(document, file_path)
52
+ YAML.load(File.read(relative_file_path, encoding: "UTF-8"))
53
+ end
54
+
55
+ def processed_lines(document, input_lines)
56
+ result = []
57
+ loop do
58
+ result.push(*process_text_blocks(document, input_lines))
59
+ end
60
+ result
61
+ end
62
+
63
+ def process_text_blocks(document, input_lines)
64
+ line = input_lines.next
65
+ block_match = line.match(MARCO_REGEXP)
66
+ return [line] if block_match.nil?
67
+
68
+ lutaml_document = lutaml_document_from_file(document, block_match[1])
69
+ fill_in_diagrams_attributes(document, lutaml_document)
70
+ model_representation(
71
+ lutaml_document,
72
+ document,
73
+ collect_additional_context(input_lines, input_lines.next),
74
+ parse_yaml_config_file(document, block_match[2]))
75
+ end
76
+
77
+ def fill_in_diagrams_attributes(document, lutaml_document_wrapper)
78
+ lutaml_document = lutaml_document_wrapper.original_document
79
+ package_flat_diagrams = lambda do |pks|
80
+ pks.each_with_object({}) do |package, res|
81
+ package.diagrams.map { |diag| res["#{package.name}:#{diag.name}"] = diag.xmi_id }
82
+ end
83
+ end
84
+ children_pks_daigs = package_flat_diagrams.call(lutaml_document.packages.map(&:children_packages).flatten)
85
+ document.attributes['lutaml_figure_id'] = package_flat_diagrams.call(lutaml_document.packages)
86
+ .merge(children_pks_daigs)
87
+ end
88
+
89
+ def collect_additional_context(input_lines, end_mark)
90
+ additional_context = Hash.new { |hash, key| hash[key] = [] }
91
+ block_lines = []
92
+ while (block_line = input_lines.next) != end_mark
93
+ block_lines.push(block_line)
94
+ end
95
+ block_document = (Asciidoctor::Document.new(block_lines, {})).parse
96
+ block_document.blocks.each do |block|
97
+ next unless SUPPORTED_NESTED_MACRO.include?(block.attributes['role'])
98
+
99
+ attrs = block.attributes
100
+ name = attrs.delete('role')
101
+ package = attrs.delete('package')
102
+ macro_keyword = [name, package].compact.join(";")
103
+ block_text = block.lines.length > 0 ? block.lines[1..-2].join("\n") : ''
104
+ additional_context[macro_keyword].push({ 'text' => block_text }.merge(attrs))
105
+ end
106
+ additional_context
107
+ end
108
+
109
+ def package_level(lutaml_document, level)
110
+ return lutaml_document if level <= 0
111
+
112
+ package_level(lutaml_document['packages'].first, level - 1)
113
+ end
114
+
115
+ def create_context_object(lutaml_document, additional_context, options)
116
+ root_package = package_level(lutaml_document.to_liquid, options['package_root_level'] || 1)
117
+ if options.length.zero? || options['packages'].nil?
118
+ return {
119
+ 'render_nested_packages' => true,
120
+ "packages" => root_package['packages'],
121
+ "additional_context" => additional_context
122
+ }
123
+ end
124
+
125
+ all_packages = [root_package, *root_package['children_packages']]
126
+ {
127
+ "packages" => sort_and_filter_out_packages(all_packages, options),
128
+ "additional_context" => additional_context
129
+ }
130
+ end
131
+
132
+ def sort_and_filter_out_packages(all_packages, options)
133
+ return all_packages if options['packages'].nil?
134
+
135
+ result = []
136
+ # Step one - filter out all skipped packages
137
+ options['packages']
138
+ .find_all { |entity| entity.is_a?(Hash) && entity['skip'] }
139
+ .each do |entity|
140
+ entity_regexp = config_entity_regexp(entity['skip'])
141
+ all_packages
142
+ .delete_if {|package| package['name'] =~ entity_regexp }
143
+ end
144
+ # Step two - select supplied packages by pattern
145
+ options['packages']
146
+ .find_all { |entity| entity.is_a?(String) }
147
+ .each do |entity|
148
+ entity_regexp = config_entity_regexp(entity)
149
+ all_packages.each.with_index do |package|
150
+ if package['name'] =~ entity_regexp
151
+ result.push(package)
152
+ all_packages
153
+ .delete_if {|nest_package| nest_package['name'] == package['name'] }
154
+ end
155
+ end
156
+ end
157
+ result
158
+ end
159
+
160
+ def config_entity_regexp(entity)
161
+ additional_sym = '.*' if entity =~ /\*$/
162
+ %r{^#{Regexp.escape(entity.gsub('*', ''))}#{additional_sym}$}
163
+ end
164
+
165
+ def model_representation(lutaml_document, document, additional_context, options)
166
+ render_result, errors = Utils.render_liquid_string(
167
+ template_string: table_template(options['section_depth'] || 2, options['render_style']),
168
+ context_items: create_context_object(lutaml_document,
169
+ additional_context,
170
+ options),
171
+ context_name: "context",
172
+ document: document,
173
+ include_path: LIQUID_INCLUDE_PATH
174
+ )
175
+ Utils.notify_render_errors(document, errors)
176
+ render_result.split("\n")
177
+ end
178
+
179
+ def table_template(section_depth, render_style)
180
+ include_name = RENDER_STYLES_INCLUDES.fetch(render_style, DEFAULT_RENDER_INCLUDE)
181
+ <<~LIQUID
182
+ {% include "#{include_name}", depth: #{section_depth}, context: context, additional_context: context.additional_context, render_nested_packages: context.render_nested_packages %}
183
+ LIQUID
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
@@ -1,5 +1,6 @@
1
1
  require "expressir/express/cache"
2
2
  require "metanorma/plugin/lutaml/liquid/custom_filters"
3
+ require "metanorma/plugin/lutaml/liquid/multiply_local_file_system"
3
4
 
4
5
  ::Liquid::Template.register_filter(Metanorma::Plugin::Lutaml::Liquid::CustomFilters)
5
6
 
@@ -22,10 +23,11 @@ module Metanorma
22
23
  end
23
24
 
24
25
  def render_liquid_string(template_string:, context_items:,
25
- context_name:, document:)
26
+ context_name:, document:, include_path: nil)
26
27
  liquid_template = ::Liquid::Template.parse(template_string)
27
28
  # Allow includes for the template
28
- liquid_template.registers[:file_system] = ::Liquid::LocalFileSystem.new(Utils.relative_file_path(document, ""))
29
+ include_paths = [Utils.relative_file_path(document, ""), include_path].compact
30
+ liquid_template.registers[:file_system] = ::Metanorma::Plugin::Lutaml::Liquid::LocalFileSystem.new(include_paths, ["_%s.liquid", "_%s.adoc"])
29
31
  rendered_string = liquid_template
30
32
  .render(context_name => context_items,
31
33
  strict_variables: true,
@@ -1,7 +1,7 @@
1
1
  module Metanorma
2
2
  module Plugin
3
3
  module Lutaml
4
- VERSION = "0.4.2".freeze
4
+ VERSION = "0.4.6".freeze
5
5
  end
6
6
  end
7
7
  end
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.4.2
4
+ version: 0.4.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-16 00:00:00.000000000 Z
11
+ date: 2021-08-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liquid
@@ -257,9 +257,22 @@ files:
257
257
  - lib/metanorma-plugin-lutaml.rb
258
258
  - lib/metanorma/plugin/lutaml/express_remarks_decorator.rb
259
259
  - lib/metanorma/plugin/lutaml/liquid/custom_filters.rb
260
+ - lib/metanorma/plugin/lutaml/liquid/multiply_local_file_system.rb
261
+ - lib/metanorma/plugin/lutaml/liquid_templates/_diagrams_block.liquid
262
+ - lib/metanorma/plugin/lutaml/liquid_templates/_packages.liquid
263
+ - lib/metanorma/plugin/lutaml/liquid_templates/_packages_class.liquid
264
+ - lib/metanorma/plugin/lutaml/liquid_templates/_packages_data_dictionary.liquid
265
+ - lib/metanorma/plugin/lutaml/liquid_templates/_packages_data_dictionary_classes.liquid
266
+ - lib/metanorma/plugin/lutaml/liquid_templates/_packages_data_type.liquid
267
+ - lib/metanorma/plugin/lutaml/liquid_templates/_packages_entity_list.liquid
268
+ - lib/metanorma/plugin/lutaml/liquid_templates/_packages_enum.liquid
269
+ - lib/metanorma/plugin/lutaml/lutaml_diagram_base.rb
260
270
  - lib/metanorma/plugin/lutaml/lutaml_diagram_block.rb
271
+ - lib/metanorma/plugin/lutaml/lutaml_diagram_block_macro.rb
272
+ - lib/metanorma/plugin/lutaml/lutaml_figure_inline_macro.rb
261
273
  - lib/metanorma/plugin/lutaml/lutaml_preprocessor.rb
262
274
  - lib/metanorma/plugin/lutaml/lutaml_uml_attributes_table_preprocessor.rb
275
+ - lib/metanorma/plugin/lutaml/lutaml_uml_datamodel_description_preprocessor.rb
263
276
  - lib/metanorma/plugin/lutaml/utils.rb
264
277
  - lib/metanorma/plugin/lutaml/version.rb
265
278
  - metanorma-plugin-lutaml.gemspec