metanorma-plugin-lutaml 0.7.53 → 0.7.55.pre.alpha.1
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 +0 -25
- data/Gemfile +19 -0
- data/Gemfile.devel +3 -3
- data/docs/usages/enterprise_architect.adoc +18 -2
- data/lib/metanorma/plugin/lutaml/config/guidance.rb +13 -0
- data/lib/metanorma/plugin/lutaml/gc_budget.rb +22 -0
- data/lib/metanorma/plugin/lutaml/liquid_templates/_klass_table.liquid +8 -3
- data/lib/metanorma/plugin/lutaml/lutaml_data_preprocessor.rb +215 -0
- data/lib/metanorma/plugin/lutaml/lutaml_gml_dictionary_base.rb +11 -1
- data/lib/metanorma/plugin/lutaml/lutaml_klass_table_block_macro.rb +3 -2
- data/lib/metanorma/plugin/lutaml/version.rb +1 -1
- data/lib/metanorma/plugin/lutaml/xmi_cache.rb +84 -28
- data/lib/metanorma/plugin/lutaml/xmi_parse_cache.rb +30 -26
- data/lib/metanorma/plugin/lutaml/xmi_partial_load_registry.rb +148 -0
- data/lib/metanorma/plugin/lutaml/xmi_renderer.rb +5 -0
- data/lib/metanorma-plugin-lutaml.rb +6 -0
- data/metanorma-plugin-lutaml.gemspec +3 -5
- metadata +13 -24
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d08e2206e64a9c020c1059501939d9a44cfa5e0412368b84e9702442ed38e5ca
|
|
4
|
+
data.tar.gz: 3d1bc9fbb60c1a750ab70d2ffcd98e61257e4a7d21f44886cb485456b56af81c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8777cde7a2a1379e9cabb417192d3bc026786cb04739e10578c2eede1764bdffe2b113be22837f376957c7ba6525ba831fd78192c1c381fc5c70a0ec0151d661
|
|
7
|
+
data.tar.gz: 6ac5da62726d19874eceeb0c39710ad034e890e78402f41f516d1f00b5954aed441b9176ec403c97cd228d7537e6e8e3cd710495e2bee3c2927ae598d39d84a1
|
data/.github/workflows/rake.yml
CHANGED
|
@@ -20,30 +20,5 @@ jobs:
|
|
|
20
20
|
setup-tools: graphviz
|
|
21
21
|
submodules: true
|
|
22
22
|
choco-cache: true
|
|
23
|
-
# Build the expressir Rust binding for the vendored gem: without
|
|
24
|
-
# it the pure-Ruby parser path makes the heavy suites exceed the
|
|
25
|
-
# runner memory ceiling on ruby 3.3 (#304).
|
|
26
|
-
after-setup-ruby: |
|
|
27
|
-
case "$(uname -s)" in
|
|
28
|
-
*MINGW*|*MSYS*)
|
|
29
|
-
echo "windows: ruby is mingw-built; the binding needs the
|
|
30
|
-
gnu toolchain - skipping (windows passes without it)"
|
|
31
|
-
exit 0
|
|
32
|
-
;;
|
|
33
|
-
esac
|
|
34
|
-
if ! command -v cargo >/dev/null 2>&1; then
|
|
35
|
-
echo "cargo not available; skipping expressir binding build"
|
|
36
|
-
exit 0
|
|
37
|
-
fi
|
|
38
|
-
gem install rb_sys --no-document
|
|
39
|
-
gem_path=$(bundle info expressir --path)
|
|
40
|
-
ext_dir="$gem_path/ext/expressir_core"
|
|
41
|
-
if [ -f "$ext_dir/extconf.rb" ]; then
|
|
42
|
-
(cd "$ext_dir" && ruby extconf.rb && make)
|
|
43
|
-
bundle_path="$ext_dir/expressir_core.bundle"
|
|
44
|
-
if [ "$(uname)" = "Darwin" ] && [ -f "$bundle_path" ]; then
|
|
45
|
-
codesign -f -s - "$bundle_path"
|
|
46
|
-
fi
|
|
47
|
-
fi
|
|
48
23
|
secrets:
|
|
49
24
|
pat_token: ${{ secrets.METANORMA_CI_PAT_TOKEN }}
|
data/Gemfile
CHANGED
|
@@ -24,3 +24,22 @@ gem "simplecov"
|
|
|
24
24
|
gem "timecop"
|
|
25
25
|
gem "vcr"
|
|
26
26
|
gem "webmock"
|
|
27
|
+
|
|
28
|
+
# leptris 1.9.367.0 is the highest match for standoc's '~> 1.9.361' but
|
|
29
|
+
# publishes only linux prebuilds plus a ruby gem with no vendored
|
|
30
|
+
# libleptris; windows-latest falls back to that ruby gem and dies on
|
|
31
|
+
# require "metanorma-standoc". 1.9.361.1 is the latest that still ships
|
|
32
|
+
# x64-mingw-ucrt (and darwin) binaries. Lift once upstream packs Windows
|
|
33
|
+
# again.
|
|
34
|
+
gem "leptris", "~> 1.9.361.1"
|
|
35
|
+
|
|
36
|
+
# pre-release line pins (see metanorma release wave)
|
|
37
|
+
gem "isodoc", github: "metanorma/isodoc", branch: "main"
|
|
38
|
+
gem "metanorma-standoc", github: "metanorma/metanorma-standoc", branch: "main"
|
|
39
|
+
gem "suma", github: "metanorma/suma", branch: "main"
|
|
40
|
+
# standoc main's block_attributes reference
|
|
41
|
+
# Metanorma::Document::Components::AncillaryBlocks::SvgmapElement, which
|
|
42
|
+
# the released metanorma-document 0.5.1 predates; ref-pinned to the
|
|
43
|
+
# document main tree the suite is green against
|
|
44
|
+
gem "metanorma-document", github: "metanorma/metanorma-document",
|
|
45
|
+
ref: "ca4eb4b26f7ab0d2994a4710d0cf158607a832b4"
|
data/Gemfile.devel
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
gem "metanorma-standoc", github: "metanorma/metanorma-standoc", ref: "5ca49c85bbcc1422e48c4b625a66f7f026dc6832"
|
|
1
|
+
# gem "metanorma-standoc", github: "metanorma/metanorma-standoc", ref: "5ca49c85bbcc1422e48c4b625a66f7f026dc6832"
|
|
2
2
|
gem "metanorma", github: "metanorma/metanorma", ref: "a899a9a6fc933dca0a53166d6633b609311b14e6"
|
|
3
3
|
# relaton v3 prerelease line (rubyzip ~> 3.4, matching lutaml-model);
|
|
4
4
|
# relaton-cli's v2line branch allows relaton 3 while keeping version
|
|
5
5
|
# 2.1.2 for metanorma-standoc's constraint; the metanorma/standoc
|
|
6
6
|
# refs are the known-good pair (newer standoc@main needs unreleased
|
|
7
7
|
# metanorma-document components)
|
|
8
|
-
gem "relaton",
|
|
9
|
-
gem "relaton-cli",
|
|
8
|
+
gem "relaton", "~> 3.0.0.pre.alpha"
|
|
9
|
+
gem "relaton-cli", "~> 3.0.0.pre.alpha"
|
|
10
10
|
|
|
11
11
|
# lutaml-lml 0.1.5 adds Lutaml::Lml.parse + Formatter::Graphviz used by
|
|
12
12
|
# the lutaml_diagram renderer; 0.1.1 (previously resolved) lacks them
|
|
@@ -208,11 +208,19 @@ classes:
|
|
|
208
208
|
used: false
|
|
209
209
|
guidance: |
|
|
210
210
|
Drop guidance message here.
|
|
211
|
+
data_types:
|
|
212
|
+
- name: Name Of Datatype
|
|
213
|
+
attributes:
|
|
214
|
+
- name: Name Of Attribute (e.g. Root:value)
|
|
215
|
+
used: false
|
|
216
|
+
guidance: |
|
|
217
|
+
Drop guidance message here.
|
|
211
218
|
...
|
|
212
219
|
----
|
|
213
220
|
|
|
214
221
|
If you want to define the guidance, you can define the `name` of the class
|
|
215
|
-
under `classes
|
|
222
|
+
under `classes` (or the datatype under `data_types`). Then define which
|
|
223
|
+
`attributes` you want to add guidance by the
|
|
216
224
|
`name`. Set `used` to show the attribute is used or not. Drop the message of
|
|
217
225
|
guidance in `guidance`.
|
|
218
226
|
|
|
@@ -311,11 +319,19 @@ classes:
|
|
|
311
319
|
used: false
|
|
312
320
|
guidance: |
|
|
313
321
|
Drop guidance message here.
|
|
322
|
+
data_types:
|
|
323
|
+
- name: "NameOfDatatype"
|
|
324
|
+
attributes:
|
|
325
|
+
- name: Name Of Attribute (e.g. Root:value)
|
|
326
|
+
used: false
|
|
327
|
+
guidance: |
|
|
328
|
+
Drop guidance message here.
|
|
314
329
|
...
|
|
315
330
|
----
|
|
316
331
|
|
|
317
332
|
If you want to define the guidance, you can define the `name` of the class
|
|
318
|
-
under `classes
|
|
333
|
+
under `classes` (or the datatype under `data_types`). Then define which
|
|
334
|
+
`attributes` you want to add guidance by the
|
|
319
335
|
`name`. Set `used` to show the attribute is used or not. Drop the message of
|
|
320
336
|
guidance in `guidance`.
|
|
321
337
|
|
|
@@ -7,9 +7,22 @@ module Metanorma
|
|
|
7
7
|
class Guidance < ::Lutaml::Model::Serializable
|
|
8
8
|
attribute :classes, GuidanceKlass, collection: true,
|
|
9
9
|
initialize_empty: true
|
|
10
|
+
attribute :data_types, GuidanceKlass, collection: true,
|
|
11
|
+
initialize_empty: true
|
|
10
12
|
|
|
11
13
|
yaml do
|
|
12
14
|
map "classes", to: :classes
|
|
15
|
+
map "data_types", to: :data_types
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Drops index into both keys (KlassDrop reads ["classes"],
|
|
19
|
+
# DataTypeDrop reads ["data_types"]); empty collections are
|
|
20
|
+
# omitted from as_yaml, so pin both keys here.
|
|
21
|
+
def to_yaml_hash
|
|
22
|
+
super.tap do |hash|
|
|
23
|
+
hash["classes"] ||= []
|
|
24
|
+
hash["data_types"] ||= []
|
|
25
|
+
end
|
|
13
26
|
end
|
|
14
27
|
end
|
|
15
28
|
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Metanorma
|
|
4
|
+
module Plugin
|
|
5
|
+
module Lutaml
|
|
6
|
+
# The lutaml macro family churns transients of hundreds of MB per
|
|
7
|
+
# invocation on top of a multi-GB live parsed-XMI set. The churn is
|
|
8
|
+
# malloc-side (libxml/moxml/liquid), so the GC's heap-growth
|
|
9
|
+
# heuristics fire too late under memory caps; collect at macro
|
|
10
|
+
# boundaries whenever uncollected malloc has exceeded the budget.
|
|
11
|
+
module GcBudget
|
|
12
|
+
BUDGET_BYTES = 512 * (1 << 20)
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
def gc_when_bloated!
|
|
16
|
+
GC.start if GC.stat(:malloc_increase_bytes) > BUDGET_BYTES
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
{
|
|
1
|
+
{%- comment -%}
|
|
2
|
+
parentless types (e.g. Union-stereotyped data types) carry no
|
|
3
|
+
generalization: render the drop itself so members are not lost
|
|
4
|
+
{%- endcomment -%}
|
|
5
|
+
{%- assign root = klass.generalization | default: klass -%}
|
|
2
6
|
|
|
3
7
|
{%- capture upper_klass_name -%}
|
|
4
8
|
{{ root.general.upper_klass }}:{{ root.general.name }}
|
|
@@ -35,7 +39,8 @@ h| Property Name h| Property Type and Multiplicity h| Definition
|
|
|
35
39
|
|
|
36
40
|
3+h| Self-defined Properties
|
|
37
41
|
h| Property Name h| Property Type and Multiplicity h| Definition
|
|
38
|
-
{
|
|
42
|
+
{%- assign self_props = root.owned_props | default: root.owned_attributes -%}
|
|
43
|
+
{% for attr in self_props %}
|
|
39
44
|
{%- unless attr.has_association? -%}
|
|
40
45
|
{%- capture name_col -%}
|
|
41
46
|
{{ attr.name_ns }}:{{ attr.name }}
|
|
@@ -74,4 +79,4 @@ h| Property Name h| Property Type and Multiplicity h| Definition
|
|
|
74
79
|
| {{ attr.definition }}
|
|
75
80
|
{%- endif -%}
|
|
76
81
|
{% endfor %}
|
|
77
|
-
|===
|
|
82
|
+
|===
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Metanorma
|
|
4
|
+
module Plugin
|
|
5
|
+
module Lutaml
|
|
6
|
+
# Renders LutaML data instances through a Liquid template.
|
|
7
|
+
#
|
|
8
|
+
# Data definitions and instances in separate files:
|
|
9
|
+
#
|
|
10
|
+
# [lutaml_data,<definitions.lml>,<instances.lml|yaml|json>,<context>]
|
|
11
|
+
# ----
|
|
12
|
+
# {% for check in context.S158Checks.checks %}
|
|
13
|
+
# {{ check.dev_id }}
|
|
14
|
+
# {% endfor %}
|
|
15
|
+
# ----
|
|
16
|
+
#
|
|
17
|
+
# Data definitions and instances in the same file:
|
|
18
|
+
#
|
|
19
|
+
# [lutaml_data,<definitions.lml>,<context>]
|
|
20
|
+
#
|
|
21
|
+
class LutamlDataPreprocessor < BasePreprocessor
|
|
22
|
+
DATA_FILE_EXTENSIONS = %w[.lml .yaml .yml .json].freeze
|
|
23
|
+
DEFAULT_CONTEXT_NAME = "lutaml_data"
|
|
24
|
+
|
|
25
|
+
DATA_BLOCK_REGEX = %r{
|
|
26
|
+
^
|
|
27
|
+
\[
|
|
28
|
+
\blutaml_data\b
|
|
29
|
+
,(?<definition_file>[^,\[\]]+)
|
|
30
|
+
(?<rest>.*)
|
|
31
|
+
\]
|
|
32
|
+
}x
|
|
33
|
+
|
|
34
|
+
protected
|
|
35
|
+
|
|
36
|
+
def lutaml_liquid?(line)
|
|
37
|
+
line.match(DATA_BLOCK_REGEX)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def index_type_name
|
|
41
|
+
"LutaML data"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def load_lutaml_file(_document, file_path, _options)
|
|
45
|
+
::Lutaml::Lml.parse_document(File.new(file_path, encoding: "UTF-8"))
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def process_text_blocks(document, input_lines, _express_indexes)
|
|
51
|
+
line = input_lines.next
|
|
52
|
+
block_header_match = lutaml_liquid?(line)
|
|
53
|
+
return [line] unless block_header_match
|
|
54
|
+
|
|
55
|
+
definition_file, instance_file, context_name, options =
|
|
56
|
+
parse_header(block_header_match)
|
|
57
|
+
|
|
58
|
+
end_mark = input_lines.next
|
|
59
|
+
lines = extract_block_lines(input_lines, end_mark)
|
|
60
|
+
|
|
61
|
+
render_data_template(
|
|
62
|
+
document: document,
|
|
63
|
+
lines: lines,
|
|
64
|
+
definition_file: definition_file,
|
|
65
|
+
instance_file: instance_file,
|
|
66
|
+
context_name: context_name,
|
|
67
|
+
options: options,
|
|
68
|
+
)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def parse_header(match)
|
|
72
|
+
definition_file = match[:definition_file].strip
|
|
73
|
+
segments = match[:rest].split(",").map(&:strip)
|
|
74
|
+
options, segments = split_options(segments)
|
|
75
|
+
|
|
76
|
+
data_segments, name_segments = segments
|
|
77
|
+
.reject(&:empty?).partition { |segment| data_file?(segment) }
|
|
78
|
+
|
|
79
|
+
[definition_file, data_segments.last,
|
|
80
|
+
name_segments.last || DEFAULT_CONTEXT_NAME, options]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def split_options(segments)
|
|
84
|
+
options_start = segments.index { |segment| segment.include?("=") }
|
|
85
|
+
return [{}, segments] unless options_start
|
|
86
|
+
|
|
87
|
+
options = parse_options(",#{segments[options_start..].join(',')}")
|
|
88
|
+
[options, segments[0...options_start]]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def data_file?(segment)
|
|
92
|
+
DATA_FILE_EXTENSIONS.include?(File.extname(segment))
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def render_data_template(document:, lines:, # rubocop:disable Metrics/ParameterLists
|
|
96
|
+
definition_file:, instance_file:,
|
|
97
|
+
context_name:, options:)
|
|
98
|
+
definition_path, instances_path = resolve_data_paths(
|
|
99
|
+
document, definition_file, instance_file
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
compiler = ::Lutaml::Lml::ModelCompiler.new
|
|
103
|
+
compiler.compile(File.new(definition_path, encoding: "UTF-8"))
|
|
104
|
+
instances = load_instances(instances_path, compiler)
|
|
105
|
+
|
|
106
|
+
[render_liquid(lines, document, options, context_name, instances)]
|
|
107
|
+
rescue StandardError => e
|
|
108
|
+
::Metanorma::Util.log(
|
|
109
|
+
"[#{self.class.name}] Failed to parse LutaML data block: " \
|
|
110
|
+
"#{e.message}",
|
|
111
|
+
:error,
|
|
112
|
+
)
|
|
113
|
+
raise e
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def render_liquid(lines, document, options, context_name, instances)
|
|
117
|
+
parsed_template = template(lines)
|
|
118
|
+
parsed_template.registers[:file_system] =
|
|
119
|
+
build_file_system(document, options)
|
|
120
|
+
parsed_template.render(context_name => deep_stringify(instances.to_h))
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Liquid resolves variable lookups by string keys; the compiled
|
|
124
|
+
# LML models hash with symbols
|
|
125
|
+
def deep_stringify(value)
|
|
126
|
+
case value
|
|
127
|
+
when Hash
|
|
128
|
+
value.transform_keys(&:to_s)
|
|
129
|
+
.transform_values { |v| deep_stringify(v) }
|
|
130
|
+
when Array
|
|
131
|
+
value.map { |v| deep_stringify(v) }
|
|
132
|
+
else
|
|
133
|
+
value
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def resolve_data_paths(document, definition_file, instance_file)
|
|
138
|
+
definition_path = Utils.relative_file_path(document, definition_file)
|
|
139
|
+
unless File.file?(definition_path)
|
|
140
|
+
raise StandardError, index_missing_message(definition_file)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
instances_path = instance_file &&
|
|
144
|
+
Utils.relative_file_path(document, instance_file)
|
|
145
|
+
if instances_path && !File.file?(instances_path)
|
|
146
|
+
raise StandardError, index_missing_message(instance_file)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
[definition_path, instances_path || definition_path]
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def load_instances(path, compiler)
|
|
153
|
+
case File.extname(path)
|
|
154
|
+
when ".lml" then load_lml_instances(path, compiler)
|
|
155
|
+
when ".json" then load_structured_instances(path, compiler,
|
|
156
|
+
:parse_json_data)
|
|
157
|
+
else load_structured_instances(path, compiler, :parse_yaml_data)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def load_lml_instances(path, compiler)
|
|
162
|
+
doc = load_lutaml_file(nil, path, {})
|
|
163
|
+
root = doc.instance
|
|
164
|
+
return [] unless root
|
|
165
|
+
|
|
166
|
+
[[root.type.to_s, compiler.hydrate(doc)]]
|
|
167
|
+
rescue StandardError => e
|
|
168
|
+
raise StandardError, "Failed to parse LutaML instances in " \
|
|
169
|
+
"`#{path}`: #{e.message}"
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def load_structured_instances(path, compiler, parser)
|
|
173
|
+
data = send(parser, path)
|
|
174
|
+
entries = data.is_a?(Array) ? data : [data]
|
|
175
|
+
entries.map { |entry| build_structured_entry(path, compiler, entry) }
|
|
176
|
+
rescue StandardError => e
|
|
177
|
+
raise e if e.message.start_with?("Instance", "Unknown type")
|
|
178
|
+
|
|
179
|
+
raise StandardError, "Failed to load data instances in " \
|
|
180
|
+
"`#{path}`: #{e.message}"
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def build_structured_entry(path, compiler, entry)
|
|
184
|
+
type = entry.delete("type")
|
|
185
|
+
unless type
|
|
186
|
+
raise StandardError, "Instance in `#{path}` is missing the " \
|
|
187
|
+
"`type` key"
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
klass = compiler.compiled_classes[demodulize(type)]
|
|
191
|
+
unless klass
|
|
192
|
+
raise StandardError,
|
|
193
|
+
"Unknown type `#{type}` in `#{path}`"
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
[demodulize(type), klass.from_hash(entry)]
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def parse_yaml_data(path)
|
|
200
|
+
require "yaml"
|
|
201
|
+
YAML.safe_load(File.read(path, encoding: "UTF-8"))
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def parse_json_data(path)
|
|
205
|
+
require "json"
|
|
206
|
+
JSON.parse(File.read(path, encoding: "UTF-8"))
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def demodulize(name)
|
|
210
|
+
name.to_s.split("::").last
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
require "ogc/gml"
|
|
4
4
|
require "liquid"
|
|
5
5
|
|
|
6
|
+
require "metanorma/plugin/lutaml/gc_budget"
|
|
7
|
+
|
|
6
8
|
module Metanorma
|
|
7
9
|
module Plugin
|
|
8
10
|
module Lutaml
|
|
@@ -10,6 +12,7 @@ module Metanorma
|
|
|
10
12
|
private
|
|
11
13
|
|
|
12
14
|
def render(tmpl, parent, attrs, orig_gml_path)
|
|
15
|
+
GcBudget.gc_when_bloated!
|
|
13
16
|
dict = get_gml_dictionary(parent, orig_gml_path)
|
|
14
17
|
tmpl.assigns[attrs["context"]] = GmlDictionaryDrop.new(dict)
|
|
15
18
|
rendered_tmpl = tmpl.render
|
|
@@ -17,12 +20,19 @@ module Metanorma
|
|
|
17
20
|
parse_content(block, rendered_tmpl, attrs)
|
|
18
21
|
end
|
|
19
22
|
|
|
23
|
+
# A document-scale compile resolves the same dictionary files many
|
|
24
|
+
# times (the plateau corpus cites codelists up to 34 times each);
|
|
25
|
+
# re-reading and re-parsing per macro was pure duplicate work.
|
|
26
|
+
GML_DICTIONARY_CACHE = CacheStore.new(max_size: 512)
|
|
27
|
+
|
|
20
28
|
def get_gml_dictionary(parent, orig_gml_path)
|
|
21
29
|
gml_path = Utils.relative_file_path(
|
|
22
30
|
parent.document, orig_gml_path
|
|
23
31
|
)
|
|
24
32
|
|
|
25
|
-
|
|
33
|
+
GML_DICTIONARY_CACHE.fetch_or_store(gml_path) do
|
|
34
|
+
::Ogc::Gml::Dictionary.from_xml(xml_content(gml_path))
|
|
35
|
+
end
|
|
26
36
|
end
|
|
27
37
|
|
|
28
38
|
def xml_content(filepath)
|
|
@@ -28,8 +28,9 @@ module Metanorma
|
|
|
28
28
|
guidance = get_guidance(parent.document, attrs["guidance"])
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
klass =
|
|
32
|
-
|
|
31
|
+
klass = serialize_klass_or_datatype_drop_by_name(
|
|
32
|
+
xmi_path, path, parent.document, guidance
|
|
33
|
+
)
|
|
33
34
|
|
|
34
35
|
render_table(klass, CONTEXT_NAME, parent, attrs)
|
|
35
36
|
end
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "metanorma/plugin/lutaml/gc_budget"
|
|
4
|
+
|
|
3
5
|
module Metanorma
|
|
4
6
|
module Plugin
|
|
5
7
|
module Lutaml
|
|
6
8
|
module XmiCache
|
|
7
|
-
|
|
9
|
+
# Bounded parse-once cache: every macro touching a source (the
|
|
10
|
+
# full file, or its package slice under lutaml-ea-xmi-load: partial)
|
|
11
|
+
# reuses the one parsed graph; the LRU bound keeps the retained
|
|
12
|
+
# graphs to a few live at once, which the section-ordered
|
|
13
|
+
# macros of a document turn into near-perfect reuse.
|
|
14
|
+
XMI_PARSE_CACHE = XmiParseCache.new(max_size: 4)
|
|
8
15
|
|
|
9
16
|
def lutaml_document_from_file_or_cache(document, file_path, yaml_config,
|
|
10
17
|
yaml_config_path = nil)
|
|
@@ -27,22 +34,6 @@ yaml_config_path = nil)
|
|
|
27
34
|
end
|
|
28
35
|
end
|
|
29
36
|
|
|
30
|
-
def find_class_by_xmi_id(container, xmi_id)
|
|
31
|
-
container.classes.find { |node| node.xmi_id == xmi_id } ||
|
|
32
|
-
container.packages
|
|
33
|
-
.lazy
|
|
34
|
-
.filter_map { |pkg| find_class_by_xmi_id(pkg, xmi_id) }
|
|
35
|
-
.first
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def find_enum_by_xmi_id(container, xmi_id)
|
|
39
|
-
container.enums.find { |node| node.xmi_id == xmi_id } ||
|
|
40
|
-
container.packages
|
|
41
|
-
.lazy
|
|
42
|
-
.filter_map { |pkg| find_enum_by_xmi_id(pkg, xmi_id) }
|
|
43
|
-
.first
|
|
44
|
-
end
|
|
45
|
-
|
|
46
37
|
def find_packaged_klass(index, path, root_model_name: nil)
|
|
47
38
|
segments = path.split("::").reject(&:empty?)
|
|
48
39
|
if root_model_name && segments.first == root_model_name
|
|
@@ -69,6 +60,32 @@ yaml_config_path = nil)
|
|
|
69
60
|
end
|
|
70
61
|
end
|
|
71
62
|
|
|
63
|
+
def find_packaged_datatype(index, path, root_model_name: nil)
|
|
64
|
+
segments = path.split("::").reject(&:empty?)
|
|
65
|
+
if root_model_name && segments.first == root_model_name
|
|
66
|
+
segments.shift
|
|
67
|
+
end
|
|
68
|
+
if segments.one?
|
|
69
|
+
index.find_packaged_by_name_and_types(
|
|
70
|
+
segments.first, ["uml:DataType"]
|
|
71
|
+
)
|
|
72
|
+
else
|
|
73
|
+
find_packaged_datatype_by_path(index, segments)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def find_packaged_datatype_by_path(index, segments)
|
|
78
|
+
datatype_name = segments.pop
|
|
79
|
+
|
|
80
|
+
candidates = ["uml:DataType"]
|
|
81
|
+
.flat_map { |t| index.packaged_elements_of_type(t) }
|
|
82
|
+
.select { |e| e.name == datatype_name }
|
|
83
|
+
|
|
84
|
+
candidates.find do |datatype|
|
|
85
|
+
match_parent_chain?(index, datatype, segments)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
72
89
|
def match_parent_chain?(index, element, parent_segments)
|
|
73
90
|
current = element
|
|
74
91
|
parent_segments.reverse_each do |pkg_name|
|
|
@@ -85,23 +102,55 @@ yaml_config_path = nil)
|
|
|
85
102
|
.find { |e| e.name == name }
|
|
86
103
|
end
|
|
87
104
|
|
|
88
|
-
def
|
|
89
|
-
guidance = nil)
|
|
90
|
-
|
|
105
|
+
def serialize_klass_or_datatype_drop_by_name(xmi_path,
|
|
106
|
+
name, _document = nil, guidance = nil)
|
|
107
|
+
serialize_klass_drop_by_name(xmi_path, name, _document, guidance) ||
|
|
108
|
+
serialize_datatype_drop_by_name(xmi_path, name, _document, guidance)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def serialize_klass_drop_by_name(xmi_path,
|
|
112
|
+
name, _document = nil, guidance = nil)
|
|
113
|
+
GcBudget.gc_when_bloated!
|
|
114
|
+
xmi_path, name, slice = XmiPartialLoadRegistry.rewrite(xmi_path, name)
|
|
115
|
+
parsed = XMI_PARSE_CACHE.fetch(xmi_path, slice: slice)
|
|
91
116
|
klass = resolve_packaged_klass(parsed, name)
|
|
92
|
-
|
|
117
|
+
if klass.nil?
|
|
118
|
+
warn "Class not found for name: #{name}"
|
|
119
|
+
return nil
|
|
120
|
+
end
|
|
121
|
+
|
|
93
122
|
::Ea::Xmi::LiquidDrops::KlassDrop.new(
|
|
94
123
|
klass, guidance, parsed.drop_options
|
|
95
124
|
)
|
|
96
125
|
end
|
|
97
126
|
|
|
127
|
+
def serialize_datatype_drop_by_name(xmi_path, name, _document = nil,
|
|
128
|
+
guidance = nil)
|
|
129
|
+
GcBudget.gc_when_bloated!
|
|
130
|
+
xmi_path, name, slice = XmiPartialLoadRegistry.rewrite(xmi_path, name)
|
|
131
|
+
parsed = XMI_PARSE_CACHE.fetch(xmi_path, slice: slice)
|
|
132
|
+
datatype = resolve_packaged_datatype(parsed, name)
|
|
133
|
+
if datatype.nil?
|
|
134
|
+
warn "Datatype not found for name: #{name}"
|
|
135
|
+
return nil
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
::Ea::Xmi::LiquidDrops::DataTypeDrop.new(
|
|
139
|
+
datatype, guidance, parsed.drop_options
|
|
140
|
+
)
|
|
141
|
+
end
|
|
142
|
+
|
|
98
143
|
def serialize_enum_drop_by_name(xmi_path, name, _document = nil)
|
|
99
|
-
|
|
144
|
+
GcBudget.gc_when_bloated!
|
|
145
|
+
xmi_path, name, slice = XmiPartialLoadRegistry.rewrite(xmi_path, name)
|
|
146
|
+
parsed = XMI_PARSE_CACHE.fetch(xmi_path, slice: slice)
|
|
100
147
|
raw_enum = find_packaged_enum(parsed.parser.xmi_index, name)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
148
|
+
if raw_enum.nil?
|
|
149
|
+
warn "Enumeration not found for name: #{name}"
|
|
150
|
+
return nil
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
enum = parsed.xmi_id_index[raw_enum.id]
|
|
105
154
|
::Ea::Xmi::LiquidDrops::EnumDrop.new(
|
|
106
155
|
enum, parsed.drop_options
|
|
107
156
|
)
|
|
@@ -115,9 +164,16 @@ guidance = nil)
|
|
|
115
164
|
parsed.parser.xmi_index, name,
|
|
116
165
|
root_model_name: root_model_name
|
|
117
166
|
)
|
|
118
|
-
raw_klass &&
|
|
119
|
-
|
|
167
|
+
raw_klass && parsed.xmi_id_index[raw_klass.id]
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def resolve_packaged_datatype(parsed, name)
|
|
171
|
+
root_model_name = parsed.parser.xmi_root_model.model.name
|
|
172
|
+
raw_datatype = find_packaged_datatype(
|
|
173
|
+
parsed.parser.xmi_index, name,
|
|
174
|
+
root_model_name: root_model_name
|
|
120
175
|
)
|
|
176
|
+
raw_datatype && parsed.xmi_id_index[raw_datatype.id]
|
|
121
177
|
end
|
|
122
178
|
end
|
|
123
179
|
end
|
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "stringio"
|
|
3
4
|
require "xmi"
|
|
4
5
|
require "ea/xmi"
|
|
5
6
|
|
|
6
7
|
module Metanorma
|
|
7
8
|
module Plugin
|
|
8
9
|
module Lutaml
|
|
9
|
-
ParsedXmi = Struct.new(:parser, :uml_document, :drop_options,
|
|
10
|
-
keyword_init: true)
|
|
11
|
-
|
|
12
10
|
class XmiParseCache
|
|
13
11
|
def initialize(max_size: 50)
|
|
14
12
|
@parse_cache = CacheStore.new(max_size: max_size)
|
|
15
13
|
@drop_cache = CacheStore.new(max_size: max_size)
|
|
16
14
|
end
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
drop_options: build_drop_options(parser),
|
|
27
|
-
)
|
|
16
|
+
# slice: a XmiPartialLoadRegistry token; when given, the macro parses
|
|
17
|
+
# the package slice prepared for it instead of the whole source
|
|
18
|
+
def fetch(full_path, retain: true, slice: nil)
|
|
19
|
+
key = slice || full_path
|
|
20
|
+
return fetch_unretained(full_path, slice) unless retain
|
|
21
|
+
|
|
22
|
+
@parse_cache.fetch_or_store(key) do
|
|
23
|
+
load_parsed(full_path, slice)
|
|
28
24
|
end
|
|
29
25
|
end
|
|
30
26
|
|
|
31
|
-
def
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
def fetch_unretained(full_path, slice = nil)
|
|
28
|
+
load_parsed(full_path, slice)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def fetch_drop(full_path, guidance: nil, slice: nil)
|
|
32
|
+
parsed = fetch(full_path, slice: slice)
|
|
33
|
+
@drop_cache.fetch_or_store([key_for(full_path, slice), guidance]) do
|
|
34
34
|
::Ea::Xmi::LiquidDrops::RootDrop.new(
|
|
35
35
|
parsed.uml_document, guidance, parsed.drop_options
|
|
36
36
|
)
|
|
@@ -44,16 +44,20 @@ module Metanorma
|
|
|
44
44
|
|
|
45
45
|
private
|
|
46
46
|
|
|
47
|
-
def
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
47
|
+
def key_for(full_path, slice)
|
|
48
|
+
slice || full_path
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# The prepared slice is parsed whole: assembling it already
|
|
52
|
+
# streamed the source once, so nothing re-reads the original
|
|
53
|
+
# export here.
|
|
54
|
+
def load_parsed(full_path, slice)
|
|
55
|
+
if slice
|
|
56
|
+
xml = XmiPartialLoadRegistry.slice_string(slice)
|
|
57
|
+
::Ea::Xmi.load_graph(StringIO.new(xml))
|
|
58
|
+
else
|
|
59
|
+
::Ea::Xmi.load_graph(full_path)
|
|
60
|
+
end
|
|
57
61
|
end
|
|
58
62
|
end
|
|
59
63
|
end
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "pathname"
|
|
4
|
+
require_relative "utils"
|
|
5
|
+
|
|
6
|
+
module Metanorma
|
|
7
|
+
module Plugin
|
|
8
|
+
module Lutaml
|
|
9
|
+
# Loads the XMI sources of table macros partially, through
|
|
10
|
+
# Ea::Xmi.load_graph's partial mode.
|
|
11
|
+
#
|
|
12
|
+
# EA exports of plateau scale reach ~100 MB, more than half of it
|
|
13
|
+
# diagram presentation data, and fully materializing the Xmi tree
|
|
14
|
+
# plus the Ea graph costs 10+ GB of live objects - more than a
|
|
15
|
+
# standard build runner has. With the `lutaml-ea-xmi-load` document
|
|
16
|
+
# attribute set to `partial`, every klass and enum table macro's
|
|
17
|
+
# (package, name) pair seeds a per-package reference closure; one
|
|
18
|
+
# streaming pass per source assembles the closures in memory and
|
|
19
|
+
# each macro parses only its own package's slice. Nothing is
|
|
20
|
+
# written to disk.
|
|
21
|
+
#
|
|
22
|
+
# Without the attribute nothing is preloaded and behavior is
|
|
23
|
+
# byte-for-byte the whole-load path.
|
|
24
|
+
module XmiPartialLoadRegistry
|
|
25
|
+
MACRO_REGEXP = /lutaml_(?:klass|enum)_table::([^\[<]+)\[([^\]]*)\]/
|
|
26
|
+
MIN_SOURCE_BYTES = 2 * 1024 * 1024
|
|
27
|
+
|
|
28
|
+
class << self
|
|
29
|
+
# Rewrites (xmi_path, name_path) to the partial-load form of
|
|
30
|
+
# the macro's class: [path, bare name, slice token]. The
|
|
31
|
+
# token is nil when no slice was prepared, in which case the
|
|
32
|
+
# macro whole-loads the source unchanged.
|
|
33
|
+
def rewrite(xmi_path, name_path)
|
|
34
|
+
return [xmi_path, name_path, nil] unless @registry
|
|
35
|
+
|
|
36
|
+
entry = @registry[xmi_path]
|
|
37
|
+
return [xmi_path, name_path, nil] unless entry
|
|
38
|
+
|
|
39
|
+
group_key = entry[name_path] || entry[bare_name(name_path)]
|
|
40
|
+
return [xmi_path, name_path, nil] unless group_key
|
|
41
|
+
|
|
42
|
+
[xmi_path, bare_name(name_path), [xmi_path, group_key]]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# The prepared slice for a token from #rewrite.
|
|
46
|
+
def slice_string(token)
|
|
47
|
+
@slices[token]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def slice?(xmi_path)
|
|
51
|
+
return false unless @registry
|
|
52
|
+
|
|
53
|
+
entry = @registry[xmi_path]
|
|
54
|
+
!entry.nil? && entry.any?
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def reset!
|
|
58
|
+
@registry = nil
|
|
59
|
+
@slices = nil
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def prepare(document, lines) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
63
|
+
reset!
|
|
64
|
+
# header attributes are parsed after preprocessors run, so
|
|
65
|
+
# the opt-in is also detected in the raw lines
|
|
66
|
+
return unless enabled?(document, lines)
|
|
67
|
+
|
|
68
|
+
groups = collect_groups(document, lines)
|
|
69
|
+
return if groups.empty?
|
|
70
|
+
|
|
71
|
+
@registry = {}
|
|
72
|
+
@slices = {}
|
|
73
|
+
groups.each do |path, entries|
|
|
74
|
+
next unless File.size(path) >= MIN_SOURCE_BYTES
|
|
75
|
+
|
|
76
|
+
slice_groups = {}
|
|
77
|
+
macro_keys = {}
|
|
78
|
+
entries.each do |key, value|
|
|
79
|
+
if value.is_a?(Array) # group_key => wanted pairs
|
|
80
|
+
slice_groups[key] = value
|
|
81
|
+
else # macro key => group_key
|
|
82
|
+
(macro_keys[value] ||= []) << key
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
# one index pass and one write pass over the source; the
|
|
86
|
+
# slices stay in memory for the parse cache to consume,
|
|
87
|
+
# so nothing is written to disk
|
|
88
|
+
::Ea::Xmi::Slicer.slices(path, slice_groups).each do |group_key, xml|
|
|
89
|
+
token = [path, group_key]
|
|
90
|
+
@slices[token] = xml
|
|
91
|
+
macro_keys[group_key]&.each do |k|
|
|
92
|
+
(@registry[path] ||= {})[k] = group_key
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
@registry = nil if @registry.empty?
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
private
|
|
100
|
+
|
|
101
|
+
def enabled?(document, lines)
|
|
102
|
+
document.attributes["lutaml-ea-xmi-load"] == "partial" ||
|
|
103
|
+
lines.any? { |l| l.match?(/\A:lutaml-ea-xmi-load:\s*partial\s*$/) }
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Slices are grouped per package, not per class: the tables
|
|
107
|
+
# of classes in one package share most of their closure
|
|
108
|
+
# (partners, connectors, ancestors), so a package slice
|
|
109
|
+
# carries each shared subtree once instead of once per class.
|
|
110
|
+
def collect_groups(document, lines)
|
|
111
|
+
groups = Hash.new { |h, k| h[k] = {} }
|
|
112
|
+
lines.each do |line|
|
|
113
|
+
MACRO_REGEXP.match(line) do |m|
|
|
114
|
+
path = Utils.relative_file_path(document, m[1].strip)
|
|
115
|
+
package = m[2][/&?(?:^|,)package="([^"]+)"/, 1]
|
|
116
|
+
name = m[2][/&?(?:^|,)name="([^"]+)"/, 1]
|
|
117
|
+
next if name.nil?
|
|
118
|
+
|
|
119
|
+
key = package ? "#{package}::#{name}" : name
|
|
120
|
+
group_key = package || "_"
|
|
121
|
+
(groups[path][group_key] ||= []) << [package, name]
|
|
122
|
+
groups[path][key] = group_key
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
groups
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def bare_name(name_path)
|
|
129
|
+
name_path.to_s.split("::").last
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Scans the fully expanded document source once, before parsing,
|
|
135
|
+
# and prepares the partial-load seeds for every table macro. The
|
|
136
|
+
# lines pass through unchanged; reading them through the incoming
|
|
137
|
+
# reader expands include directives, which is where plateau
|
|
138
|
+
# documents keep their table macros.
|
|
139
|
+
class XmiPartialLoadPreprocessor < ::Asciidoctor::Extensions::Preprocessor
|
|
140
|
+
def process(document, reader)
|
|
141
|
+
input_lines = reader.readlines
|
|
142
|
+
XmiPartialLoadRegistry.prepare(document, input_lines)
|
|
143
|
+
reader.class.new(document, input_lines)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require "liquid"
|
|
4
4
|
|
|
5
|
+
require "metanorma/plugin/lutaml/gc_budget"
|
|
6
|
+
|
|
5
7
|
module Metanorma
|
|
6
8
|
module Plugin
|
|
7
9
|
module Lutaml
|
|
@@ -72,6 +74,9 @@ module Metanorma
|
|
|
72
74
|
end
|
|
73
75
|
|
|
74
76
|
rendered_table = table_tmpl.render
|
|
77
|
+
# The asciidoctor ingestion of a rendered table transiently
|
|
78
|
+
# dwarfs its input; collect the liquid phase's garbage first.
|
|
79
|
+
GcBudget.gc_when_bloated!
|
|
75
80
|
block = create_open_block(parent, "", attrs)
|
|
76
81
|
parse_content(block, rendered_table, attrs)
|
|
77
82
|
end
|
|
@@ -31,6 +31,8 @@ module Metanorma
|
|
|
31
31
|
autoload :LutamlDiagramBase, "metanorma/plugin/lutaml/lutaml_diagram_base"
|
|
32
32
|
autoload :LutamlDiagramBlock,
|
|
33
33
|
"metanorma/plugin/lutaml/lutaml_diagram_block"
|
|
34
|
+
autoload :LutamlDataPreprocessor,
|
|
35
|
+
"metanorma/plugin/lutaml/lutaml_data_preprocessor"
|
|
34
36
|
autoload :LutamlDiagramBlockMacro,
|
|
35
37
|
"metanorma/plugin/lutaml/lutaml_diagram_block_macro"
|
|
36
38
|
autoload :LutamlEaDiagramBlockMacro,
|
|
@@ -65,6 +67,10 @@ module Metanorma
|
|
|
65
67
|
"metanorma/plugin/lutaml/lutaml_xsd_preprocessor"
|
|
66
68
|
autoload :ParseError, "metanorma/plugin/lutaml/parse_error"
|
|
67
69
|
autoload :XmiParseCache, "metanorma/plugin/lutaml/xmi_parse_cache"
|
|
70
|
+
autoload :XmiPartialLoadRegistry,
|
|
71
|
+
"metanorma/plugin/lutaml/xmi_partial_load_registry"
|
|
72
|
+
autoload :XmiPartialLoadPreprocessor,
|
|
73
|
+
"metanorma/plugin/lutaml/xmi_partial_load_registry"
|
|
68
74
|
autoload :SourceExtractor, "metanorma/plugin/lutaml/source_extractor"
|
|
69
75
|
autoload :Utils, "metanorma/plugin/lutaml/utils"
|
|
70
76
|
autoload :Yaml2TextPreprocessor,
|
|
@@ -30,15 +30,13 @@ Gem::Specification.new do |spec|
|
|
|
30
30
|
|
|
31
31
|
spec.add_dependency "asciidoctor"
|
|
32
32
|
spec.add_dependency "coradoc", "~> 1.1.8"
|
|
33
|
-
spec.add_dependency "ea"
|
|
33
|
+
spec.add_dependency "ea", ">= 0.6.41" # Ea::Xmi.load/load_graph (lutaml/ea#86): the partial-load API this gem calls
|
|
34
34
|
spec.add_dependency "expressir", "~> 2.3", ">= 2.3.5"
|
|
35
|
-
spec.add_dependency "isodoc"
|
|
36
|
-
spec.add_dependency "liquid"
|
|
35
|
+
spec.add_dependency "isodoc", ">= 3.5.0"
|
|
36
|
+
spec.add_dependency "liquid", "~> 5"
|
|
37
37
|
spec.add_dependency "lutaml-lml"
|
|
38
38
|
spec.add_dependency "lutaml-model", "~> 0.8.4"
|
|
39
39
|
spec.add_dependency "lutaml-uml", ">= 0.5", "< 2"
|
|
40
40
|
spec.add_dependency "ogc-gml", "~> 1.1"
|
|
41
|
-
spec.add_dependency "relaton-cli"
|
|
42
|
-
|
|
43
41
|
spec.metadata["rubygems_mfa_required"] = "true"
|
|
44
42
|
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.7.
|
|
4
|
+
version: 0.7.55.pre.alpha.1
|
|
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-
|
|
11
|
+
date: 2026-10-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: asciidoctor
|
|
@@ -44,14 +44,14 @@ dependencies:
|
|
|
44
44
|
requirements:
|
|
45
45
|
- - ">="
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version:
|
|
47
|
+
version: 0.6.41
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - ">="
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version:
|
|
54
|
+
version: 0.6.41
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: expressir
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -78,28 +78,28 @@ dependencies:
|
|
|
78
78
|
requirements:
|
|
79
79
|
- - ">="
|
|
80
80
|
- !ruby/object:Gem::Version
|
|
81
|
-
version:
|
|
81
|
+
version: 3.5.0
|
|
82
82
|
type: :runtime
|
|
83
83
|
prerelease: false
|
|
84
84
|
version_requirements: !ruby/object:Gem::Requirement
|
|
85
85
|
requirements:
|
|
86
86
|
- - ">="
|
|
87
87
|
- !ruby/object:Gem::Version
|
|
88
|
-
version:
|
|
88
|
+
version: 3.5.0
|
|
89
89
|
- !ruby/object:Gem::Dependency
|
|
90
90
|
name: liquid
|
|
91
91
|
requirement: !ruby/object:Gem::Requirement
|
|
92
92
|
requirements:
|
|
93
|
-
- - "
|
|
93
|
+
- - "~>"
|
|
94
94
|
- !ruby/object:Gem::Version
|
|
95
|
-
version: '
|
|
95
|
+
version: '5'
|
|
96
96
|
type: :runtime
|
|
97
97
|
prerelease: false
|
|
98
98
|
version_requirements: !ruby/object:Gem::Requirement
|
|
99
99
|
requirements:
|
|
100
|
-
- - "
|
|
100
|
+
- - "~>"
|
|
101
101
|
- !ruby/object:Gem::Version
|
|
102
|
-
version: '
|
|
102
|
+
version: '5'
|
|
103
103
|
- !ruby/object:Gem::Dependency
|
|
104
104
|
name: lutaml-lml
|
|
105
105
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -162,20 +162,6 @@ dependencies:
|
|
|
162
162
|
- - "~>"
|
|
163
163
|
- !ruby/object:Gem::Version
|
|
164
164
|
version: '1.1'
|
|
165
|
-
- !ruby/object:Gem::Dependency
|
|
166
|
-
name: relaton-cli
|
|
167
|
-
requirement: !ruby/object:Gem::Requirement
|
|
168
|
-
requirements:
|
|
169
|
-
- - ">="
|
|
170
|
-
- !ruby/object:Gem::Version
|
|
171
|
-
version: '0'
|
|
172
|
-
type: :runtime
|
|
173
|
-
prerelease: false
|
|
174
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
175
|
-
requirements:
|
|
176
|
-
- - ">="
|
|
177
|
-
- !ruby/object:Gem::Version
|
|
178
|
-
version: '0'
|
|
179
165
|
description: Metanorma plugin for LutaML
|
|
180
166
|
email:
|
|
181
167
|
- open.source@ribose.com
|
|
@@ -224,6 +210,7 @@ files:
|
|
|
224
210
|
- lib/metanorma/plugin/lutaml/express_remark_adapter.rb
|
|
225
211
|
- lib/metanorma/plugin/lutaml/express_remarks_decorator.rb
|
|
226
212
|
- lib/metanorma/plugin/lutaml/file_not_found_error.rb
|
|
213
|
+
- lib/metanorma/plugin/lutaml/gc_budget.rb
|
|
227
214
|
- lib/metanorma/plugin/lutaml/json2_text_preprocessor.rb
|
|
228
215
|
- lib/metanorma/plugin/lutaml/liquid.rb
|
|
229
216
|
- lib/metanorma/plugin/lutaml/liquid/custom_blocks.rb
|
|
@@ -250,6 +237,7 @@ files:
|
|
|
250
237
|
- lib/metanorma/plugin/lutaml/liquid_templates/_packages_entity_list_class.liquid
|
|
251
238
|
- lib/metanorma/plugin/lutaml/liquid_templates/_packages_entity_list_classes.liquid
|
|
252
239
|
- lib/metanorma/plugin/lutaml/liquid_templates/_packages_enum.liquid
|
|
240
|
+
- lib/metanorma/plugin/lutaml/lutaml_data_preprocessor.rb
|
|
253
241
|
- lib/metanorma/plugin/lutaml/lutaml_diagram_base.rb
|
|
254
242
|
- lib/metanorma/plugin/lutaml/lutaml_diagram_block.rb
|
|
255
243
|
- lib/metanorma/plugin/lutaml/lutaml_diagram_block_macro.rb
|
|
@@ -277,6 +265,7 @@ files:
|
|
|
277
265
|
- lib/metanorma/plugin/lutaml/xmi_context_builder.rb
|
|
278
266
|
- lib/metanorma/plugin/lutaml/xmi_package_filter.rb
|
|
279
267
|
- lib/metanorma/plugin/lutaml/xmi_parse_cache.rb
|
|
268
|
+
- lib/metanorma/plugin/lutaml/xmi_partial_load_registry.rb
|
|
280
269
|
- lib/metanorma/plugin/lutaml/xmi_renderer.rb
|
|
281
270
|
- lib/metanorma/plugin/lutaml/yaml2_text_preprocessor.rb
|
|
282
271
|
- metanorma-plugin-lutaml.gemspec
|