metanorma-plugin-lutaml 0.7.37 → 0.7.39
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/.github/workflows/rake.yml +5 -1
- data/.gitignore +2 -1
- data/.rubocop.yml +11 -2
- data/.rubocop_todo.yml +238 -0
- data/CLAUDE.md +78 -0
- data/Gemfile +8 -12
- data/Gemfile.devel +2 -0
- data/Rakefile +17 -0
- data/docs/usages/enterprise_architect.adoc +17 -0
- data/docs/usages/express.adoc +55 -0
- data/lib/metanorma/plugin/lutaml/base_structured_text_preprocessor.rb +6 -6
- data/lib/metanorma/plugin/lutaml/data2_text_preprocessor.rb +1 -0
- data/lib/metanorma/plugin/lutaml/express_remarks_decorator.rb +2 -2
- data/lib/metanorma/plugin/lutaml/json2_text_preprocessor.rb +1 -0
- data/lib/metanorma/plugin/lutaml/liquid/multiply_local_file_system.rb +2 -2
- data/lib/metanorma/plugin/lutaml/liquid_templates/_klass_table.liquid +6 -6
- data/lib/metanorma/plugin/lutaml/lutaml_ea_diagram_block_macro.rb +1 -1
- data/lib/metanorma/plugin/lutaml/lutaml_ea_xmi_base.rb +164 -15
- data/lib/metanorma/plugin/lutaml/lutaml_ea_xmi_preprocessor.rb +2 -2
- data/lib/metanorma/plugin/lutaml/lutaml_enum_table_block_macro.rb +8 -42
- data/lib/metanorma/plugin/lutaml/lutaml_gml_dictionary_block.rb +1 -0
- data/lib/metanorma/plugin/lutaml/lutaml_klass_table_block_macro.rb +9 -42
- data/lib/metanorma/plugin/lutaml/lutaml_preprocessor.rb +8 -6
- data/lib/metanorma/plugin/lutaml/lutaml_table_inline_macro.rb +1 -0
- data/lib/metanorma/plugin/lutaml/lutaml_uml_datamodel_description_preprocessor.rb +2 -2
- data/lib/metanorma/plugin/lutaml/lutaml_xmi_uml_preprocessor.rb +2 -2
- data/lib/metanorma/plugin/lutaml/source_extractor.rb +3 -3
- data/lib/metanorma/plugin/lutaml/utils.rb +52 -8
- data/lib/metanorma/plugin/lutaml/version.rb +1 -1
- data/lib/metanorma/plugin/lutaml/yaml2_text_preprocessor.rb +1 -0
- data/metanorma-plugin-lutaml.gemspec +4 -4
- metadata +25 -11
- data/.hound.yml +0 -5
|
@@ -40,7 +40,7 @@ module Metanorma
|
|
|
40
40
|
(?<config_path>.+) # Capture config path
|
|
41
41
|
)? # End of optional group
|
|
42
42
|
$ # End of the pattern
|
|
43
|
-
}x
|
|
43
|
+
}x
|
|
44
44
|
|
|
45
45
|
# search document for block `lutaml_ea_xmi`
|
|
46
46
|
# or `lutaml_uml_datamodel_description`
|
|
@@ -63,16 +63,22 @@ module Metanorma
|
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
yaml_config.ea_extension&.each do |ea_extension_path|
|
|
66
|
-
# resolve paths of ea extensions based on the location of
|
|
67
|
-
# config yaml file
|
|
68
66
|
ea_extension_full_path = File.expand_path(
|
|
69
67
|
ea_extension_path, File.dirname(yaml_config_path)
|
|
70
68
|
)
|
|
71
|
-
Xmi::EaRoot.
|
|
69
|
+
unless Xmi::EaRoot.loaded_extensions.value?(ea_extension_full_path)
|
|
70
|
+
Xmi::EaRoot.load_extension(ea_extension_full_path)
|
|
71
|
+
end
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
guidance = get_guidance(document, yaml_config.guidance)
|
|
75
|
-
|
|
75
|
+
cache_key = [full_path, guidance]
|
|
76
|
+
|
|
77
|
+
@@lutaml_doc_cache ||= {}
|
|
78
|
+
result_document = @@lutaml_doc_cache[cache_key] ||= parse_result_document(
|
|
79
|
+
full_path, guidance
|
|
80
|
+
)
|
|
81
|
+
|
|
76
82
|
document.attributes["lutaml_xmi_cache"] ||= {}
|
|
77
83
|
document.attributes["lutaml_xmi_cache"][full_path] = result_document
|
|
78
84
|
result_document
|
|
@@ -203,8 +209,8 @@ module Metanorma
|
|
|
203
209
|
all_children_packages = lutaml_document.packages
|
|
204
210
|
.map(&:children_packages).flatten
|
|
205
211
|
package_flat_packages = lambda do |pks|
|
|
206
|
-
pks.
|
|
207
|
-
|
|
212
|
+
pks.to_h do |package|
|
|
213
|
+
[package.name, package.xmi_id]
|
|
208
214
|
end
|
|
209
215
|
end
|
|
210
216
|
children_pks = package_flat_packages.call(all_children_packages)
|
|
@@ -292,7 +298,7 @@ module Metanorma
|
|
|
292
298
|
def package_level(lutaml_document, level)
|
|
293
299
|
return lutaml_document if level <= 0
|
|
294
300
|
|
|
295
|
-
package_level(lutaml_document
|
|
301
|
+
package_level(lutaml_document.packages.first, level - 1)
|
|
296
302
|
end
|
|
297
303
|
|
|
298
304
|
def create_context_object( # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
@@ -307,12 +313,12 @@ module Metanorma
|
|
|
307
313
|
|
|
308
314
|
if options.packages.nil?
|
|
309
315
|
contexts[context_name]["render_nested_packages"] = true
|
|
310
|
-
contexts[context_name]["packages"] = root_package
|
|
316
|
+
contexts[context_name]["packages"] = root_package.packages
|
|
311
317
|
|
|
312
318
|
return contexts
|
|
313
319
|
end
|
|
314
320
|
|
|
315
|
-
all_packages = [root_package, *root_package
|
|
321
|
+
all_packages = [root_package, *root_package.children_packages]
|
|
316
322
|
contexts[context_name].merge!(
|
|
317
323
|
{
|
|
318
324
|
"packages" => sort_and_filter_out_packages(all_packages, options),
|
|
@@ -330,7 +336,7 @@ module Metanorma
|
|
|
330
336
|
)
|
|
331
337
|
contexts = {}
|
|
332
338
|
contexts[context_name] = {
|
|
333
|
-
"name" => root_package
|
|
339
|
+
"name" => root_package.name,
|
|
334
340
|
"root_packages" => [root_package],
|
|
335
341
|
"additional_context" => additional_context
|
|
336
342
|
.merge("external_classes" => options.external_classes),
|
|
@@ -346,7 +352,7 @@ module Metanorma
|
|
|
346
352
|
result = {}
|
|
347
353
|
packages = options.packages.reject { |p| p.send(key.to_sym).nil? }
|
|
348
354
|
packages.each do |p|
|
|
349
|
-
result[p.name] = p.send(key.to_sym).
|
|
355
|
+
result[p.name] = p.send(key.to_sym).to_h { |n| [n, true] }
|
|
350
356
|
end
|
|
351
357
|
result
|
|
352
358
|
end
|
|
@@ -370,7 +376,7 @@ module Metanorma
|
|
|
370
376
|
options.skip.each do |skip_package|
|
|
371
377
|
entity_regexp = config_entity_regexp(skip_package)
|
|
372
378
|
all_packages.delete_if do |package|
|
|
373
|
-
package
|
|
379
|
+
package.name =~ entity_regexp
|
|
374
380
|
end
|
|
375
381
|
end
|
|
376
382
|
|
|
@@ -381,10 +387,10 @@ module Metanorma
|
|
|
381
387
|
options.packages.each do |package|
|
|
382
388
|
entity_regexp = config_entity_regexp(package.name)
|
|
383
389
|
all_packages.each do |p|
|
|
384
|
-
if p
|
|
390
|
+
if p.name&.match?(entity_regexp)
|
|
385
391
|
result.push(p)
|
|
386
392
|
all_packages.delete_if do |nest_package|
|
|
387
|
-
nest_package
|
|
393
|
+
nest_package.name == p.name
|
|
388
394
|
end
|
|
389
395
|
end
|
|
390
396
|
end
|
|
@@ -434,6 +440,149 @@ module Metanorma
|
|
|
434
440
|
{% include "#{include_name}", depth: #{section_depth}, package_skip_sections: context.package_skip_sections, package_entities: context.package_entities, context: context, additional_context: context.additional_context, render_nested_packages: context.render_nested_packages %}
|
|
435
441
|
LIQUID
|
|
436
442
|
end
|
|
443
|
+
|
|
444
|
+
def render_table(context, context_name, parent, attrs) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
445
|
+
table_tmpl = get_template(parent.document, attrs)
|
|
446
|
+
table_tmpl.assigns[context_name] = context
|
|
447
|
+
|
|
448
|
+
if attrs["external_data"]
|
|
449
|
+
data_array = attrs["external_data"].split(";")
|
|
450
|
+
data_array.each do |data_item|
|
|
451
|
+
context_name, external_data_path = data_item.split(":")
|
|
452
|
+
external_data = content_from_file(
|
|
453
|
+
parent.document, external_data_path.strip
|
|
454
|
+
)
|
|
455
|
+
table_tmpl.assigns[context_name.strip] = external_data
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
rendered_table = table_tmpl.render
|
|
460
|
+
block = create_open_block(parent, "", attrs)
|
|
461
|
+
parse_content(block, rendered_table, attrs)
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
def get_template(document, attrs)
|
|
465
|
+
template = get_default_template
|
|
466
|
+
template = attrs["template"] if attrs["template"]
|
|
467
|
+
|
|
468
|
+
rel_tmpl_path = Utils.relative_file_path(
|
|
469
|
+
document, template
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
::Liquid::Template.parse(File.read(rel_tmpl_path))
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
def get_name_path(attrs)
|
|
476
|
+
return attrs["path"] if attrs["path"]
|
|
477
|
+
|
|
478
|
+
return "#{attrs['package']}::#{attrs['name']}" if attrs["package"]
|
|
479
|
+
|
|
480
|
+
attrs["name"]
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
# The class methods `serialize_generalization_by_name` and
|
|
484
|
+
# `serialize_enumeration_by_name` were removed from
|
|
485
|
+
# `Lutaml::Xmi::Parsers::Xml` in lutaml 0.10. The replacements below
|
|
486
|
+
# rebuild the same shape of result by reusing the still-available
|
|
487
|
+
# path-aware finders on the parser instance and the new
|
|
488
|
+
# `XmiLookupService`, then bridging to the UML object that the
|
|
489
|
+
# current `KlassDrop` / `EnumDrop` constructors expect.
|
|
490
|
+
def serialize_klass_drop_by_name(xmi_path, name, document = nil,
|
|
491
|
+
guidance = nil)
|
|
492
|
+
parser, uml_doc = build_uml_document(xmi_path, document)
|
|
493
|
+
raw_klass = find_packaged_klass(parser.xmi_index, name)
|
|
494
|
+
warn "Class not found for name: #{name}" if raw_klass.nil?
|
|
495
|
+
klass = raw_klass && find_uml_node_by_xmi_id(
|
|
496
|
+
uml_doc, raw_klass.id, :classes
|
|
497
|
+
)
|
|
498
|
+
::Lutaml::Xmi::LiquidDrops::KlassDrop.new(
|
|
499
|
+
klass, guidance, build_drop_options(parser)
|
|
500
|
+
)
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
def serialize_enum_drop_by_name(xmi_path, name, document = nil)
|
|
504
|
+
parser, uml_doc = build_uml_document(xmi_path, document)
|
|
505
|
+
raw_enum = find_packaged_enum(parser.xmi_index, name)
|
|
506
|
+
warn "Enumeration not found for name: #{name}" if raw_enum.nil?
|
|
507
|
+
enum = raw_enum && find_uml_node_by_xmi_id(
|
|
508
|
+
uml_doc, raw_enum.id, :enums
|
|
509
|
+
)
|
|
510
|
+
::Lutaml::Xmi::LiquidDrops::EnumDrop.new(
|
|
511
|
+
enum, build_drop_options(parser)
|
|
512
|
+
)
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
def build_uml_document(xmi_path, _document = nil)
|
|
516
|
+
@@uml_doc_cache ||= {}
|
|
517
|
+
if @@uml_doc_cache[xmi_path]
|
|
518
|
+
return @@uml_doc_cache[xmi_path]
|
|
519
|
+
end
|
|
520
|
+
|
|
521
|
+
xmi_model = ::Xmi::Sparx::Root.parse_xml(File.read(xmi_path))
|
|
522
|
+
parser = ::Lutaml::Xmi::Parsers::Xml.new
|
|
523
|
+
result = [parser, parser.parse(xmi_model)]
|
|
524
|
+
@@uml_doc_cache[xmi_path] = result
|
|
525
|
+
result
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
def build_drop_options(parser)
|
|
529
|
+
lookup = ::Lutaml::Xmi::XmiLookupService.new(
|
|
530
|
+
parser.xmi_root_model, parser.id_name_mapping
|
|
531
|
+
)
|
|
532
|
+
{
|
|
533
|
+
xmi_root_model: parser.xmi_root_model,
|
|
534
|
+
id_name_mapping: parser.id_name_mapping,
|
|
535
|
+
lookup: lookup,
|
|
536
|
+
with_gen: true,
|
|
537
|
+
with_absolute_path: true,
|
|
538
|
+
}
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
def find_uml_node_by_xmi_id(container, xmi_id, collection)
|
|
542
|
+
found = container.public_send(collection)
|
|
543
|
+
.find { |node| node.xmi_id == xmi_id }
|
|
544
|
+
return found if found
|
|
545
|
+
|
|
546
|
+
container.packages.each do |pkg|
|
|
547
|
+
nested = find_uml_node_by_xmi_id(pkg, xmi_id, collection)
|
|
548
|
+
return nested if nested
|
|
549
|
+
end
|
|
550
|
+
nil
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
def find_packaged_klass(index, path)
|
|
554
|
+
segments = path.split("::")
|
|
555
|
+
if segments.one?
|
|
556
|
+
index.find_packaged_by_name_and_types(
|
|
557
|
+
path, ["uml:Class", "uml:AssociationClass"]
|
|
558
|
+
)
|
|
559
|
+
else
|
|
560
|
+
find_packaged_klass_by_path(index, segments)
|
|
561
|
+
end
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
def find_packaged_klass_by_path(index, segments)
|
|
565
|
+
klass_name = segments.pop
|
|
566
|
+
klass = index.find_packaged_by_name_and_types(
|
|
567
|
+
klass_name, ["uml:Class", "uml:AssociationClass"]
|
|
568
|
+
)
|
|
569
|
+
return unless klass
|
|
570
|
+
|
|
571
|
+
# Verify the path by walking up the parent chain
|
|
572
|
+
current = klass
|
|
573
|
+
segments.reverse_each do |pkg_name|
|
|
574
|
+
parent = index.find_parent(current.id)
|
|
575
|
+
return unless parent && parent.name == pkg_name
|
|
576
|
+
|
|
577
|
+
current = parent
|
|
578
|
+
end
|
|
579
|
+
klass
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
def find_packaged_enum(index, name)
|
|
583
|
+
index.packaged_elements_of_type("uml:Enumeration")
|
|
584
|
+
.find { |e| e.name == name }
|
|
585
|
+
end
|
|
437
586
|
end
|
|
438
587
|
end
|
|
439
588
|
end
|
|
@@ -20,12 +20,12 @@ module Metanorma
|
|
|
20
20
|
include LutamlEaXmiBase
|
|
21
21
|
|
|
22
22
|
MACRO_REGEXP =
|
|
23
|
-
/\[lutaml_ea_xmi,([^,]+),?(.+)?\]
|
|
23
|
+
/\[lutaml_ea_xmi,([^,]+),?(.+)?\]/
|
|
24
24
|
|
|
25
25
|
private
|
|
26
26
|
|
|
27
27
|
def parse_result_document(full_path, guidance)
|
|
28
|
-
::Lutaml::
|
|
28
|
+
::Lutaml::Xmi::Parsers::Xml.serialize_xmi_to_liquid(
|
|
29
29
|
File.new(full_path, encoding: "UTF-8"),
|
|
30
30
|
guidance,
|
|
31
31
|
)
|
|
@@ -6,6 +6,7 @@ module Metanorma
|
|
|
6
6
|
class LutamlEnumTableBlockMacro <
|
|
7
7
|
::Asciidoctor::Extensions::BlockMacroProcessor
|
|
8
8
|
include LutamlEaXmiBase
|
|
9
|
+
include Content
|
|
9
10
|
|
|
10
11
|
DEFAULT_TEMPLATE = File.join(
|
|
11
12
|
Gem::Specification.find_by_name("metanorma-plugin-lutaml").gem_dir,
|
|
@@ -13,59 +14,24 @@ module Metanorma
|
|
|
13
14
|
"_enum_table.liquid"
|
|
14
15
|
)
|
|
15
16
|
|
|
17
|
+
CONTEXT_NAME = "enum"
|
|
18
|
+
|
|
16
19
|
use_dsl
|
|
17
20
|
named :lutaml_enum_table
|
|
18
21
|
|
|
19
22
|
def process(parent, target, attrs) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
20
23
|
xmi_path = get_xmi_path(parent, target, attrs)
|
|
24
|
+
path = get_name_path(attrs)
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
attrs["template"] = Utils.relative_file_path(
|
|
24
|
-
parent.document, attrs["template"]
|
|
25
|
-
)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
path = if !attrs["path"].nil?
|
|
29
|
-
attrs["path"]
|
|
30
|
-
elsif !attrs["package"].nil? && !attrs["name"].nil?
|
|
31
|
-
"#{attrs['package']}::#{attrs['name']}"
|
|
32
|
-
else
|
|
33
|
-
attrs["name"]
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
enum = ::Lutaml::XMI::Parsers::XML.serialize_enumeration_by_name(
|
|
37
|
-
xmi_path, path
|
|
38
|
-
)
|
|
26
|
+
enum = serialize_enum_drop_by_name(xmi_path, path, parent.document)
|
|
39
27
|
|
|
40
|
-
|
|
28
|
+
render_table(enum, CONTEXT_NAME, parent, attrs)
|
|
41
29
|
end
|
|
42
30
|
|
|
43
31
|
private
|
|
44
32
|
|
|
45
|
-
def
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
block = create_open_block(parent, "", attrs)
|
|
49
|
-
parse_content(block, rendered_table, attrs)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def render_table(enum, parent, attrs)
|
|
53
|
-
table_tmpl = get_template(parent.document, attrs)
|
|
54
|
-
table_tmpl.assigns["enum"] = enum
|
|
55
|
-
table_tmpl.render
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def get_template(document, attrs)
|
|
59
|
-
template = DEFAULT_TEMPLATE
|
|
60
|
-
if attrs["template"]
|
|
61
|
-
template = attrs["template"]
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
rel_tmpl_path = Utils.relative_file_path(
|
|
65
|
-
document, template
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
::Liquid::Template.parse(File.read(rel_tmpl_path))
|
|
33
|
+
def get_default_template
|
|
34
|
+
DEFAULT_TEMPLATE
|
|
69
35
|
end
|
|
70
36
|
end
|
|
71
37
|
end
|
|
@@ -6,6 +6,7 @@ module Metanorma
|
|
|
6
6
|
class LutamlKlassTableBlockMacro <
|
|
7
7
|
::Asciidoctor::Extensions::BlockMacroProcessor
|
|
8
8
|
include LutamlEaXmiBase
|
|
9
|
+
include Content
|
|
9
10
|
|
|
10
11
|
DEFAULT_TEMPLATE = File.join(
|
|
11
12
|
Gem::Specification.find_by_name("metanorma-plugin-lutaml").gem_dir,
|
|
@@ -13,64 +14,30 @@ module Metanorma
|
|
|
13
14
|
"_klass_table.liquid"
|
|
14
15
|
)
|
|
15
16
|
|
|
17
|
+
CONTEXT_NAME = "klass"
|
|
18
|
+
|
|
16
19
|
use_dsl
|
|
17
20
|
named :lutaml_klass_table
|
|
18
21
|
|
|
19
22
|
def process(parent, target, attrs) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
20
23
|
xmi_path = get_xmi_path(parent, target, attrs)
|
|
21
|
-
|
|
22
|
-
if attrs["template"]
|
|
23
|
-
attrs["template"] = Utils.relative_file_path(
|
|
24
|
-
parent.document, attrs["template"]
|
|
25
|
-
)
|
|
26
|
-
end
|
|
24
|
+
path = get_name_path(attrs)
|
|
27
25
|
|
|
28
26
|
guidance = nil
|
|
29
27
|
if attrs["guidance"]
|
|
30
28
|
guidance = get_guidance(parent.document, attrs["guidance"])
|
|
31
29
|
end
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
elsif !attrs["package"].nil? && !attrs["name"].nil?
|
|
36
|
-
"#{attrs['package']}::#{attrs['name']}"
|
|
37
|
-
else
|
|
38
|
-
attrs["name"]
|
|
39
|
-
end
|
|
31
|
+
klass = serialize_klass_drop_by_name(xmi_path, path, parent.document,
|
|
32
|
+
guidance)
|
|
40
33
|
|
|
41
|
-
klass
|
|
42
|
-
xmi_path, path, guidance
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
render(klass, parent, attrs)
|
|
34
|
+
render_table(klass, CONTEXT_NAME, parent, attrs)
|
|
46
35
|
end
|
|
47
36
|
|
|
48
37
|
private
|
|
49
38
|
|
|
50
|
-
def
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
block = create_open_block(parent, "", attrs)
|
|
54
|
-
parse_content(block, rendered_table, attrs)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def render_table(klass, parent, attrs)
|
|
58
|
-
table_tmpl = get_template(parent.document, attrs)
|
|
59
|
-
table_tmpl.assigns["klass"] = klass
|
|
60
|
-
table_tmpl.render
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def get_template(document, attrs)
|
|
64
|
-
template = DEFAULT_TEMPLATE
|
|
65
|
-
if attrs["template"]
|
|
66
|
-
template = attrs["template"]
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
rel_tmpl_path = Utils.relative_file_path(
|
|
70
|
-
document, template
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
::Liquid::Template.parse(File.read(rel_tmpl_path))
|
|
39
|
+
def get_default_template
|
|
40
|
+
DEFAULT_TEMPLATE
|
|
74
41
|
end
|
|
75
42
|
end
|
|
76
43
|
end
|
|
@@ -13,6 +13,8 @@ module Metanorma
|
|
|
13
13
|
module Lutaml
|
|
14
14
|
# Class for processing Lutaml files
|
|
15
15
|
class LutamlPreprocessor < ::Asciidoctor::Extensions::Preprocessor
|
|
16
|
+
include Utils
|
|
17
|
+
|
|
16
18
|
REMARKS_ATTRIBUTE = "remarks"
|
|
17
19
|
EXPRESS_PREPROCESSOR_REGEX = %r{
|
|
18
20
|
^ # Start of line
|
|
@@ -26,7 +28,7 @@ module Metanorma
|
|
|
26
28
|
(?<context_name>[^,]+)? # Optional context name
|
|
27
29
|
(?<options>,.*)? # Optional options
|
|
28
30
|
\] # Closing bracket
|
|
29
|
-
}x
|
|
31
|
+
}x
|
|
30
32
|
|
|
31
33
|
def process(document, reader) # rubocop:disable Metrics/MethodLength
|
|
32
34
|
r = Asciidoctor::PreprocessorNoIfdefsReader.new(document,
|
|
@@ -83,8 +85,8 @@ module Metanorma
|
|
|
83
85
|
index_names = block_header_match[:index_names].split(";").map(&:strip)
|
|
84
86
|
context_name = block_header_match[:context_name].strip
|
|
85
87
|
|
|
86
|
-
options = block_header_match[:options] &&
|
|
87
|
-
parse_options(block_header_match[:options].to_s.strip) || {}
|
|
88
|
+
options = (block_header_match[:options] &&
|
|
89
|
+
parse_options(block_header_match[:options].to_s.strip)) || {}
|
|
88
90
|
|
|
89
91
|
end_mark = input_lines.next
|
|
90
92
|
|
|
@@ -225,7 +227,8 @@ module Metanorma
|
|
|
225
227
|
.new(include_paths, ["%s.liquid", "_%s.liquid", "_%s.adoc"])
|
|
226
228
|
|
|
227
229
|
# Parse template once outside the loop
|
|
228
|
-
template = ::Liquid::Template
|
|
230
|
+
template = ::Liquid::Template
|
|
231
|
+
.parse(lines.join("\n"), environment: create_liquid_environment)
|
|
229
232
|
template.registers[:file_system] = file_system
|
|
230
233
|
|
|
231
234
|
# Render for each item
|
|
@@ -274,8 +277,7 @@ module Metanorma
|
|
|
274
277
|
options_string
|
|
275
278
|
.to_s
|
|
276
279
|
.scan(/,\s*([^=]+?)=(\s*[^,]+)/)
|
|
277
|
-
.
|
|
278
|
-
.to_h
|
|
280
|
+
.to_h { |elem| elem.map(&:strip) }
|
|
279
281
|
end
|
|
280
282
|
end
|
|
281
283
|
end
|
|
@@ -20,12 +20,12 @@ module Metanorma
|
|
|
20
20
|
include LutamlEaXmiBase
|
|
21
21
|
|
|
22
22
|
MACRO_REGEXP =
|
|
23
|
-
/\[lutaml_uml_datamodel_description,([^,]+),?(.+)?\]
|
|
23
|
+
/\[lutaml_uml_datamodel_description,([^,]+),?(.+)?\]/
|
|
24
24
|
|
|
25
25
|
private
|
|
26
26
|
|
|
27
27
|
def parse_result_document(full_path, guidance)
|
|
28
|
-
::Lutaml::
|
|
28
|
+
::Lutaml::Xmi::Parsers::Xml.serialize_xmi_to_liquid(
|
|
29
29
|
File.new(full_path, encoding: "UTF-8"),
|
|
30
30
|
guidance,
|
|
31
31
|
)
|
|
@@ -15,12 +15,12 @@ module Metanorma
|
|
|
15
15
|
class LutamlXmiUmlPreprocessor < ::Asciidoctor::Extensions::Preprocessor
|
|
16
16
|
include LutamlEaXmiBase
|
|
17
17
|
|
|
18
|
-
MACRO_REGEXP = /\[lutaml_xmi_uml,([^,]+),?(.+)?\]
|
|
18
|
+
MACRO_REGEXP = /\[lutaml_xmi_uml,([^,]+),?(.+)?\]/
|
|
19
19
|
|
|
20
20
|
private
|
|
21
21
|
|
|
22
22
|
def parse_result_document(full_path, _guidance)
|
|
23
|
-
::Lutaml::
|
|
23
|
+
::Lutaml::Xmi::Parsers::Xml.parse(
|
|
24
24
|
File.new(full_path, encoding: "UTF-8"),
|
|
25
25
|
)
|
|
26
26
|
end
|
|
@@ -10,17 +10,17 @@ module Metanorma
|
|
|
10
10
|
|
|
11
11
|
# example:
|
|
12
12
|
# - [[abc]]
|
|
13
|
-
ANCHOR_REGEX_1 = /^\[\[(?<id>[^\]]*)\]\]\s
|
|
13
|
+
ANCHOR_REGEX_1 = /^\[\[(?<id>[^\]]*)\]\]\s*$/
|
|
14
14
|
|
|
15
15
|
# examples:
|
|
16
16
|
# - [#abc]
|
|
17
17
|
# - [source#abc,ruby]
|
|
18
|
-
ANCHOR_REGEX_2 = /^\[[^#,]*#(?<id>[^,\]]*)[,\]]
|
|
18
|
+
ANCHOR_REGEX_2 = /^\[[^#,]*#(?<id>[^,\]]*)[,\]]/
|
|
19
19
|
|
|
20
20
|
# examples:
|
|
21
21
|
# - [id=abc]
|
|
22
22
|
# - [source,id="abc"]
|
|
23
|
-
ANCHOR_REGEX_3 = /^\[(?:.+,)?id=['"]?(?<id>[^,\]'"]*)['"]?[,\]]
|
|
23
|
+
ANCHOR_REGEX_3 = /^\[(?:.+,)?id=['"]?(?<id>[^,\]'"]*)['"]?[,\]]/
|
|
24
24
|
|
|
25
25
|
def initialize(document, input_lines)
|
|
26
26
|
@document = document
|
|
@@ -14,6 +14,24 @@ module Metanorma
|
|
|
14
14
|
module Lutaml
|
|
15
15
|
# Helpers for lutaml macros
|
|
16
16
|
module Utils
|
|
17
|
+
# Prepended to Liquid::Context to preserve the original exception
|
|
18
|
+
# that Liquid 5.x wraps as InternalError (discarding the cause).
|
|
19
|
+
module LiquidErrorCapturer
|
|
20
|
+
def handle_error(e, line_number = nil)
|
|
21
|
+
if e.is_a?(::Liquid::Error)
|
|
22
|
+
super
|
|
23
|
+
else
|
|
24
|
+
ie = ::Liquid::InternalError.new("internal")
|
|
25
|
+
ie.set_backtrace(e.backtrace)
|
|
26
|
+
ie.define_singleton_method(:original_error) { e }
|
|
27
|
+
ie.template_name ||= template_name
|
|
28
|
+
ie.line_number ||= line_number
|
|
29
|
+
errors.push(ie)
|
|
30
|
+
exception_renderer.call(ie).to_s
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
17
35
|
LUTAML_EXP_IDX_TAG = %r{
|
|
18
36
|
^:lutaml-express-index: # Start of the pattern
|
|
19
37
|
(?<index_name>.+?) # Capture index name
|
|
@@ -25,7 +43,7 @@ module Metanorma
|
|
|
25
43
|
(?<cache_path>.+) # Capture cache path
|
|
26
44
|
)? # End of optional group
|
|
27
45
|
$ # End of the pattern
|
|
28
|
-
}x
|
|
46
|
+
}x
|
|
29
47
|
|
|
30
48
|
module_function
|
|
31
49
|
|
|
@@ -42,6 +60,10 @@ module Metanorma
|
|
|
42
60
|
contexts:, document:,
|
|
43
61
|
template_string: nil, include_path: nil, template_path: nil
|
|
44
62
|
)
|
|
63
|
+
unless ::Liquid::Context <= LiquidErrorCapturer
|
|
64
|
+
::Liquid::Context.prepend(LiquidErrorCapturer)
|
|
65
|
+
end
|
|
66
|
+
|
|
45
67
|
# Allow includes for the template
|
|
46
68
|
include_paths = [
|
|
47
69
|
Utils.relative_file_path(document, ""),
|
|
@@ -85,16 +107,38 @@ module Metanorma
|
|
|
85
107
|
result
|
|
86
108
|
end
|
|
87
109
|
|
|
110
|
+
@seen_liquid_errors = Set.new
|
|
111
|
+
|
|
88
112
|
def notify_render_errors(_document, errors)
|
|
89
|
-
errors.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
)
|
|
113
|
+
return if errors.empty?
|
|
114
|
+
|
|
115
|
+
grouped = errors.group_by { |e| error_signature(e) }
|
|
116
|
+
grouped.each do |sig, errs|
|
|
117
|
+
total = errs.size
|
|
118
|
+
already_seen = @seen_liquid_errors.include?(sig)
|
|
119
|
+
@seen_liquid_errors << sig
|
|
120
|
+
next if already_seen
|
|
121
|
+
|
|
122
|
+
err = errs.first
|
|
123
|
+
backtrace = err.backtrace&.first(3)&.join("\n").to_s
|
|
124
|
+
count_label = total > 1 ? " (#{total}x)" : ""
|
|
125
|
+
parts = ["[metanorma-plugin-lutaml] Liquid render error#{count_label}:"]
|
|
126
|
+
parts << " #{err.class}: #{err.message}"
|
|
127
|
+
if err.respond_to?(:original_error) && err.original_error
|
|
128
|
+
orig = err.original_error
|
|
129
|
+
parts << " Caused by: #{orig.class}: #{orig.message}"
|
|
130
|
+
end
|
|
131
|
+
parts << backtrace unless backtrace.empty?
|
|
132
|
+
::Metanorma::Util.log(parts.join("\n"), :error)
|
|
95
133
|
end
|
|
96
134
|
end
|
|
97
135
|
|
|
136
|
+
def error_signature(err)
|
|
137
|
+
orig = err.respond_to?(:original_error) && err.original_error
|
|
138
|
+
base = "#{err.class}: #{err.message}"
|
|
139
|
+
orig ? "#{base} (#{orig.class}: #{orig.message})" : base
|
|
140
|
+
end
|
|
141
|
+
|
|
98
142
|
def load_express_repositories( # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
|
|
99
143
|
path:, cache_path:, document:, force_read: false
|
|
100
144
|
)
|
|
@@ -166,7 +210,7 @@ module Metanorma
|
|
|
166
210
|
|
|
167
211
|
# TODO: Refactor this using Suma::SchemaConfig
|
|
168
212
|
def load_express_from_index(_document, path) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
169
|
-
yaml_content = YAML.
|
|
213
|
+
yaml_content = YAML.safe_load_file(path)
|
|
170
214
|
schema_yaml_base_path = Pathname.new(File.dirname(path))
|
|
171
215
|
|
|
172
216
|
# If there is a global root path set, all subsequent paths are
|