suma 0.2.6 → 0.3.0
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/.gitignore +10 -1
- data/.rubocop_todo.yml +170 -13
- data/CLAUDE.md +37 -11
- data/Gemfile +3 -3
- data/README.adoc +57 -1
- data/exe/suma +1 -1
- data/lib/suma/cli/build.rb +0 -5
- data/lib/suma/cli/check_svg_quality.rb +0 -6
- data/lib/suma/cli/compare.rb +0 -1
- data/lib/suma/cli/convert_jsdai.rb +0 -2
- data/lib/suma/cli/core.rb +119 -0
- data/lib/suma/cli/export.rb +0 -3
- data/lib/suma/cli/extract_terms.rb +5 -8
- data/lib/suma/cli/generate_register.rb +34 -0
- data/lib/suma/cli/generate_schemas.rb +0 -2
- data/lib/suma/cli/reformat.rb +0 -1
- data/lib/suma/cli/validate.rb +0 -2
- data/lib/suma/cli/validate_links.rb +0 -2
- data/lib/suma/cli.rb +12 -141
- data/lib/suma/collection_config.rb +0 -2
- data/lib/suma/collection_manifest.rb +7 -110
- data/lib/suma/eengine/wrapper.rb +0 -1
- data/lib/suma/eengine.rb +8 -0
- data/lib/suma/express_schema.rb +0 -1
- data/lib/suma/jsdai/figure.rb +0 -3
- data/lib/suma/jsdai.rb +5 -2
- data/lib/suma/link_validator.rb +15 -7
- data/lib/suma/manifest_traverser.rb +92 -0
- data/lib/suma/processor.rb +5 -8
- data/lib/suma/register_manifest_generator.rb +163 -0
- data/lib/suma/schema_category.rb +83 -0
- data/lib/suma/schema_collection.rb +29 -33
- data/lib/suma/schema_comparer.rb +4 -3
- data/lib/suma/schema_compiler.rb +86 -0
- data/lib/suma/schema_discovery.rb +75 -0
- data/lib/suma/schema_exporter.rb +2 -18
- data/lib/suma/schema_manifest_generator.rb +14 -6
- data/lib/suma/schema_naming.rb +111 -0
- data/lib/suma/schema_template/document.rb +141 -0
- data/lib/suma/schema_template/plain.rb +46 -0
- data/lib/suma/schema_template.rb +19 -0
- data/lib/suma/svg_quality/batch_report.rb +0 -2
- data/lib/suma/svg_quality/formatters.rb +12 -0
- data/lib/suma/svg_quality.rb +3 -1
- data/lib/suma/term_extractor.rb +119 -46
- data/lib/suma/urn.rb +61 -0
- data/lib/suma/version.rb +1 -1
- data/lib/suma.rb +31 -3
- data/suma.gemspec +1 -1
- metadata +24 -6
- data/lib/suma/schema_attachment.rb +0 -103
- data/lib/suma/schema_document.rb +0 -118
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Suma
|
|
4
|
+
# Converts EXPRESS schema identifiers into human-readable display names.
|
|
5
|
+
#
|
|
6
|
+
# Naming is model-driven: the schema type (resource/module) and suffix
|
|
7
|
+
# determine how the identifier is formatted. Acronyms and numeric
|
|
8
|
+
# prefixes are preserved to match ISO 10303 conventions.
|
|
9
|
+
#
|
|
10
|
+
# @example
|
|
11
|
+
# SchemaNaming.display_name("topology_schema")
|
|
12
|
+
# # => "Topology"
|
|
13
|
+
# SchemaNaming.display_name("Activity_method_assignment_mim")
|
|
14
|
+
# # => "Activity Method Assignment (MIM)"
|
|
15
|
+
# SchemaNaming.display_name("aic_advanced_brep")
|
|
16
|
+
# # => "AIC Advanced Brep"
|
|
17
|
+
module SchemaNaming
|
|
18
|
+
# Acronyms preserved as uppercase during title-casing.
|
|
19
|
+
# Source: ISO 10303 naming conventions.
|
|
20
|
+
ACRONYMS = %w[
|
|
21
|
+
aic aec apu bom csg edraw id ifc pdf pld
|
|
22
|
+
xml xpdl 2d 3d
|
|
23
|
+
].freeze
|
|
24
|
+
|
|
25
|
+
# Lowercase function words (ISO title-case convention).
|
|
26
|
+
LOWERCASE_WORDS = %w[a an and as for in of on or the to].freeze
|
|
27
|
+
|
|
28
|
+
# Suffixes stripped from the schema name before title-casing,
|
|
29
|
+
# mapped to the parenthesised label appended to the display name.
|
|
30
|
+
# A +nil+ label means the suffix is stripped silently.
|
|
31
|
+
SUFFIXES = {
|
|
32
|
+
"_arm" => "ARM",
|
|
33
|
+
"_mim" => "MIM",
|
|
34
|
+
"_bom" => "BOM",
|
|
35
|
+
"_schema" => nil,
|
|
36
|
+
}.freeze
|
|
37
|
+
|
|
38
|
+
class << self
|
|
39
|
+
# Produce a human-readable display name from a schema identifier.
|
|
40
|
+
#
|
|
41
|
+
# @param schema_id [String] the EXPRESS schema identifier
|
|
42
|
+
# @return [String] human-readable name
|
|
43
|
+
def display_name(schema_id)
|
|
44
|
+
base, label = decompose(schema_id)
|
|
45
|
+
title_cased = title_case(base)
|
|
46
|
+
label ? "#{title_cased} (#{label})" : title_cased
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Produce a prefixed display name with the schema category.
|
|
50
|
+
#
|
|
51
|
+
# @param schema_id [String] the EXPRESS schema identifier
|
|
52
|
+
# @param path [String, Pathname] the schema file path (for classification)
|
|
53
|
+
# @return [String] e.g. "Resource: Topology" or "Module: Activity (ARM)"
|
|
54
|
+
def prefixed_name(schema_id, path: nil)
|
|
55
|
+
type = ExpressSchema::Type.classify(id: schema_id, path: path)
|
|
56
|
+
prefix = category_prefix(type)
|
|
57
|
+
"#{prefix}: #{display_name(schema_id)}"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Determine the category prefix for a schema type.
|
|
61
|
+
#
|
|
62
|
+
# @param type [Symbol] one of ExpressSchema::Type constants
|
|
63
|
+
# @return [String]
|
|
64
|
+
def category_prefix(type)
|
|
65
|
+
SchemaCategory.for_type(type).prefix
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
# Split a schema ID into (base_without_suffix, suffix_label_or_nil).
|
|
71
|
+
#
|
|
72
|
+
# @return [(String, String, nil)]
|
|
73
|
+
def decompose(schema_id)
|
|
74
|
+
SUFFIXES.each do |suffix, label|
|
|
75
|
+
if schema_id.end_with?(suffix)
|
|
76
|
+
return [schema_id.delete_suffix(suffix),
|
|
77
|
+
label]
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
[schema_id, nil]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Title-case a snake_case identifier, preserving acronyms.
|
|
84
|
+
# The +tr+ collapses runs of underscores (leading, trailing, and
|
|
85
|
+
# consecutive) into spaces, which +split+ then treats as a single
|
|
86
|
+
# separator.
|
|
87
|
+
#
|
|
88
|
+
# @param name [String] snake_case identifier
|
|
89
|
+
# @return [String] title-cased name
|
|
90
|
+
def title_case(name)
|
|
91
|
+
words = name.tr("_", " ").split
|
|
92
|
+
words.each_with_index.map do |word, i|
|
|
93
|
+
capitalize_word(word, first: i.zero?)
|
|
94
|
+
end.join(" ")
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Capitalise a single word, preserving acronyms and
|
|
98
|
+
# lowercasing function words (except when first in the name).
|
|
99
|
+
#
|
|
100
|
+
# @param word [String]
|
|
101
|
+
# @param first [Boolean] whether this is the first word
|
|
102
|
+
# @return [String]
|
|
103
|
+
def capitalize_word(word, first: false)
|
|
104
|
+
return word.upcase if ACRONYMS.include?(word.downcase)
|
|
105
|
+
return word.downcase if LOWERCASE_WORDS.include?(word.downcase) && !first
|
|
106
|
+
|
|
107
|
+
word.capitalize
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Suma
|
|
4
|
+
module SchemaTemplate
|
|
5
|
+
# Emits an AsciiDoc body with cross-reference anchors for every
|
|
6
|
+
# schema element so other documents can deep-link into the compiled
|
|
7
|
+
# HTML. Only XML is produced — the anchors only resolve against the
|
|
8
|
+
# XML output, not the HTML rendering.
|
|
9
|
+
class Document
|
|
10
|
+
EXTENSIONS = "xml"
|
|
11
|
+
|
|
12
|
+
attr_reader :schema_id
|
|
13
|
+
|
|
14
|
+
def initialize(schema_id)
|
|
15
|
+
@schema_id = schema_id
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def extensions
|
|
19
|
+
EXTENSIONS
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def render(path_to_schema_yaml)
|
|
23
|
+
<<~ADOC
|
|
24
|
+
= #{schema_id}
|
|
25
|
+
:lutaml-express-index: schemas; #{path_to_schema_yaml};
|
|
26
|
+
:bare: true
|
|
27
|
+
:mn-document-class: iso
|
|
28
|
+
:mn-output-extensions: #{extensions}
|
|
29
|
+
|
|
30
|
+
[lutaml_express_liquid,schemas,context]
|
|
31
|
+
----
|
|
32
|
+
{% for schema in context.schemas %}
|
|
33
|
+
|
|
34
|
+
[[#{schema_id}]]
|
|
35
|
+
[%unnumbered,type=express]
|
|
36
|
+
== #{schema_id} #{rendered_anchors}
|
|
37
|
+
|
|
38
|
+
[source%unnumbered]
|
|
39
|
+
--
|
|
40
|
+
{{ schema.formatted }}
|
|
41
|
+
--
|
|
42
|
+
{% endfor %}
|
|
43
|
+
----
|
|
44
|
+
|
|
45
|
+
ADOC
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
# The raw anchor block contains Liquid comments and newlines that
|
|
51
|
+
# are illegal on the section header line; strip them before
|
|
52
|
+
# interpolating.
|
|
53
|
+
def rendered_anchors
|
|
54
|
+
schema_anchors.gsub(%r{//[^\r\n]+}, "").gsub(/[\n\r]+/, "").gsub(
|
|
55
|
+
/^[\n\r]/, ""
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def schema_anchors
|
|
60
|
+
<<~HEREDOC
|
|
61
|
+
// _fund_cons.liquid
|
|
62
|
+
[[#{schema_id}_funds]]
|
|
63
|
+
|
|
64
|
+
// _constants.liquid
|
|
65
|
+
{% if schema.constants.size > 0 %}
|
|
66
|
+
#{bookmark('constants')}
|
|
67
|
+
{% for thing in schema.constants %}
|
|
68
|
+
#{bookmark('{{thing.id}}')}
|
|
69
|
+
{% endfor %}
|
|
70
|
+
{% endif %}
|
|
71
|
+
|
|
72
|
+
// _types.liquid
|
|
73
|
+
{% if schema.types.size > 0 %}
|
|
74
|
+
#{bookmark('types')}
|
|
75
|
+
// _type.liquid
|
|
76
|
+
{% for thing in schema.types %}
|
|
77
|
+
#{bookmark('{{thing.id}}')}
|
|
78
|
+
{% if thing.items.size > 0 %}
|
|
79
|
+
// _type_items.liquid
|
|
80
|
+
#{bookmark('{{thing.id}}.items')}
|
|
81
|
+
{% for item in thing.items %}
|
|
82
|
+
#{bookmark('{{thing.id}}.items.{{item.id}}')}
|
|
83
|
+
{% endfor %}
|
|
84
|
+
{% endif %}
|
|
85
|
+
{% endfor %}
|
|
86
|
+
{% endif %}
|
|
87
|
+
|
|
88
|
+
// _entities.liquid
|
|
89
|
+
{% if schema.entities.size > 0 %}
|
|
90
|
+
#{bookmark('entities')}
|
|
91
|
+
{% for thing in schema.entities %}
|
|
92
|
+
// _entity.liquid
|
|
93
|
+
#{bookmark('{{thing.id}}')}
|
|
94
|
+
{% endfor %}
|
|
95
|
+
{% endif %}
|
|
96
|
+
|
|
97
|
+
// _subtype_constraints.liquid
|
|
98
|
+
{% if schema.subtype_constraints.size > 0 %}
|
|
99
|
+
#{bookmark('subtype_constraints')}
|
|
100
|
+
// _subtype_constraint.liquid
|
|
101
|
+
{% for thing in schema.subtype_constraints %}
|
|
102
|
+
#{bookmark('{{thing.id}}')}
|
|
103
|
+
{% endfor %}
|
|
104
|
+
{% endif %}
|
|
105
|
+
|
|
106
|
+
// _functions.liquid
|
|
107
|
+
{% if schema.functions.size > 0 %}
|
|
108
|
+
#{bookmark('functions')}
|
|
109
|
+
// _function.liquid
|
|
110
|
+
{% for thing in schema.functions %}
|
|
111
|
+
#{bookmark('{{thing.id}}')}
|
|
112
|
+
{% endfor %}
|
|
113
|
+
{% endif %}
|
|
114
|
+
|
|
115
|
+
// _procedures.liquid
|
|
116
|
+
{% if schema.procedures.size > 0 %}
|
|
117
|
+
#{bookmark('procedures')}
|
|
118
|
+
// _procedure.liquid
|
|
119
|
+
{% for thing in schema.procedures %}
|
|
120
|
+
#{bookmark('{{thing.id}}')}
|
|
121
|
+
{% endfor %}
|
|
122
|
+
{% endif %}
|
|
123
|
+
|
|
124
|
+
// _rules.liquid
|
|
125
|
+
{% if schema.rules.size > 0 %}
|
|
126
|
+
#{bookmark('rules')}
|
|
127
|
+
// _rule.liquid
|
|
128
|
+
{% for thing in schema.rules %}
|
|
129
|
+
#{bookmark('{{thing.id}}')}
|
|
130
|
+
{% endfor %}
|
|
131
|
+
{% endif %}
|
|
132
|
+
HEREDOC
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def bookmark(anchor)
|
|
136
|
+
mangled = anchor.gsub("}}", ' | replace: "\", "-", "-}}')
|
|
137
|
+
"[[#{schema_id}.#{mangled}]]"
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Suma
|
|
4
|
+
module SchemaTemplate
|
|
5
|
+
# Emits a plain AsciiDoc body for a single EXPRESS schema, producing
|
|
6
|
+
# both HTML and XML outputs via Metanorma.
|
|
7
|
+
class Plain
|
|
8
|
+
EXTENSIONS = "xml,html"
|
|
9
|
+
|
|
10
|
+
attr_reader :schema_id
|
|
11
|
+
|
|
12
|
+
def initialize(schema_id)
|
|
13
|
+
@schema_id = schema_id
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def extensions
|
|
17
|
+
EXTENSIONS
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def render(path_to_schema_yaml)
|
|
21
|
+
<<~ADOC
|
|
22
|
+
= #{schema_id}
|
|
23
|
+
:lutaml-express-index: schemas; #{path_to_schema_yaml};
|
|
24
|
+
:bare: true
|
|
25
|
+
:mn-document-class: iso
|
|
26
|
+
:mn-output-extensions: #{extensions}
|
|
27
|
+
|
|
28
|
+
[lutaml_express_liquid,schemas,context]
|
|
29
|
+
----
|
|
30
|
+
{% for schema in context.schemas %}
|
|
31
|
+
|
|
32
|
+
[%unnumbered]
|
|
33
|
+
== #{schema_id}
|
|
34
|
+
|
|
35
|
+
[source%unnumbered]
|
|
36
|
+
--
|
|
37
|
+
{{ schema.formatted }}
|
|
38
|
+
--
|
|
39
|
+
{% endfor %}
|
|
40
|
+
----
|
|
41
|
+
|
|
42
|
+
ADOC
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Suma
|
|
4
|
+
# Pure renderers for the AsciiDoc source fed to Metanorma when compiling
|
|
5
|
+
# an EXPRESS schema to HTML/XML.
|
|
6
|
+
#
|
|
7
|
+
# Each template knows how to produce the adoc body for one compilation
|
|
8
|
+
# flavour (plain HTML, or HTML with cross-reference anchors). Templates
|
|
9
|
+
# have no I/O and no knowledge of the underlying ExpressSchema — they
|
|
10
|
+
# only need the schema id, because the rendered adoc is consumed by
|
|
11
|
+
# Liquid inside Metanorma, which fetches the schema by id from the
|
|
12
|
+
# surrounding lutaml-express-index.
|
|
13
|
+
#
|
|
14
|
+
# Composition with the compiler lives in SchemaCompiler.
|
|
15
|
+
module SchemaTemplate
|
|
16
|
+
autoload :Plain, "suma/schema_template/plain"
|
|
17
|
+
autoload :Document, "suma/schema_template/document"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Suma
|
|
4
|
+
module SvgQuality
|
|
5
|
+
module Formatters
|
|
6
|
+
autoload :TerminalFormatter,
|
|
7
|
+
"suma/svg_quality/formatters/terminal_formatter"
|
|
8
|
+
autoload :JsonFormatter, "suma/svg_quality/formatters/json_formatter"
|
|
9
|
+
autoload :YamlFormatter, "suma/svg_quality/formatters/yaml_formatter"
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
data/lib/suma/svg_quality.rb
CHANGED
|
@@ -4,7 +4,9 @@ require "svg_conform"
|
|
|
4
4
|
|
|
5
5
|
module Suma
|
|
6
6
|
module SvgQuality
|
|
7
|
-
|
|
7
|
+
autoload :Report, "suma/svg_quality/report"
|
|
8
|
+
autoload :BatchReport, "suma/svg_quality/batch_report"
|
|
9
|
+
|
|
8
10
|
module QualityTiers
|
|
9
11
|
CRITICAL = { name: :critical, min_errors: 200, emoji: "💥" }.freeze
|
|
10
12
|
HIGH = { name: :high, min_errors: 100, emoji: "🔴" }.freeze
|
data/lib/suma/term_extractor.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "fileutils"
|
|
4
|
-
require_relative "utils"
|
|
5
4
|
require "expressir"
|
|
6
5
|
require "glossarist"
|
|
7
6
|
|
|
@@ -16,13 +15,16 @@ module Suma
|
|
|
16
15
|
\s*?\.?$ # Optional whitespace and period at the end
|
|
17
16
|
}x
|
|
18
17
|
|
|
19
|
-
def initialize(schema_manifest_file, output_path,
|
|
18
|
+
def initialize(schema_manifest_file, output_path, urn:,
|
|
19
|
+
language_code: "eng")
|
|
20
20
|
@schema_manifest_file = File.expand_path(schema_manifest_file)
|
|
21
21
|
@output_path = output_path
|
|
22
22
|
@language_code = language_code
|
|
23
|
+
@urn = Suma::Urn.new(urn)
|
|
23
24
|
end
|
|
24
25
|
|
|
25
26
|
def call
|
|
27
|
+
validate_inputs
|
|
26
28
|
get_exp_files.map do |exp_file|
|
|
27
29
|
extract(exp_file)
|
|
28
30
|
end
|
|
@@ -30,12 +32,24 @@ module Suma
|
|
|
30
32
|
|
|
31
33
|
private
|
|
32
34
|
|
|
35
|
+
def validate_inputs
|
|
36
|
+
unless File.exist?(@schema_manifest_file)
|
|
37
|
+
raise Errno::ENOENT, "Specified SCHEMA_MANIFEST_FILE " \
|
|
38
|
+
"`#{@schema_manifest_file}` not found."
|
|
39
|
+
end
|
|
40
|
+
unless File.file?(@schema_manifest_file)
|
|
41
|
+
raise Errno::ENOENT, "Specified SCHEMA_MANIFEST_FILE " \
|
|
42
|
+
"`#{@schema_manifest_file}` is not a file."
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
33
46
|
def get_exp_files
|
|
34
47
|
config = Expressir::SchemaManifest.from_file(@schema_manifest_file)
|
|
35
48
|
paths = config.schemas.map(&:path)
|
|
36
49
|
|
|
37
50
|
if paths.empty?
|
|
38
|
-
raise Errno::ENOENT,
|
|
51
|
+
raise Errno::ENOENT,
|
|
52
|
+
"No EXPRESS files found in `#{@schema_manifest_file}`."
|
|
39
53
|
end
|
|
40
54
|
|
|
41
55
|
paths
|
|
@@ -56,33 +70,55 @@ module Suma
|
|
|
56
70
|
end
|
|
57
71
|
|
|
58
72
|
def output_data(collection)
|
|
59
|
-
|
|
73
|
+
output_dir = File.expand_path(@output_path)
|
|
74
|
+
FileUtils.mkdir_p(output_dir)
|
|
60
75
|
Utils.log "Saving collection to files in: #{@output_path}"
|
|
61
|
-
|
|
76
|
+
|
|
77
|
+
collection.each do |concept|
|
|
78
|
+
doc = Glossarist::V3::ConceptDocument.from_managed_concept(concept)
|
|
79
|
+
doc.localizations = concept.data.localizations.keys.map do |lang|
|
|
80
|
+
concept.localization(lang)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
filename = "#{concept.uuid.gsub(/[^\w.-]/, '_')}.yaml"
|
|
84
|
+
File.write(File.join(output_dir, filename), doc.to_yamls,
|
|
85
|
+
encoding: "utf-8")
|
|
86
|
+
end
|
|
62
87
|
end
|
|
63
88
|
|
|
64
89
|
def build_managed_concept_collection(schema)
|
|
65
90
|
source_ref = get_source_ref(schema)
|
|
91
|
+
section_ref = get_section_ref(schema)
|
|
66
92
|
|
|
67
93
|
Glossarist::ManagedConceptCollection.new.tap do |collection|
|
|
68
94
|
schema.entities.each do |entity|
|
|
95
|
+
localized_concept_id = Glossarist::Utilities::UUID.uuid_v5(
|
|
96
|
+
Glossarist::Utilities::UUID::OID_NAMESPACE,
|
|
97
|
+
"#{schema.id}.#{entity.id}-#{@language_code}",
|
|
98
|
+
)
|
|
99
|
+
|
|
69
100
|
localized_concept = build_localized_concept(
|
|
70
101
|
schema: schema,
|
|
71
102
|
entity: entity,
|
|
72
103
|
source_ref: source_ref,
|
|
104
|
+
uuid: localized_concept_id,
|
|
73
105
|
)
|
|
74
|
-
localized_concept_id = get_localized_concept_identifier(schema, entity)
|
|
75
106
|
|
|
76
|
-
managed_data = Glossarist::ManagedConceptData.new.tap do |data|
|
|
77
|
-
data.id =
|
|
78
|
-
data.localizations
|
|
107
|
+
managed_data = Glossarist::V3::ManagedConceptData.new.tap do |data|
|
|
108
|
+
data.id = "#{schema.id}.#{entity.id}"
|
|
109
|
+
data.localizations.store(@language_code, localized_concept)
|
|
79
110
|
data.localized_concepts = { @language_code => localized_concept_id }
|
|
111
|
+
data.domains = [section_ref] if section_ref
|
|
80
112
|
end
|
|
81
113
|
|
|
82
|
-
managed_concept = Glossarist::ManagedConcept.new.tap do |concept|
|
|
83
|
-
concept.id =
|
|
84
|
-
concept.uuid =
|
|
114
|
+
managed_concept = Glossarist::V3::ManagedConcept.new.tap do |concept|
|
|
115
|
+
concept.id = managed_data.id
|
|
116
|
+
concept.uuid = Glossarist::Utilities::UUID.uuid_v5(
|
|
117
|
+
Glossarist::Utilities::UUID::OID_NAMESPACE,
|
|
118
|
+
managed_data.id,
|
|
119
|
+
)
|
|
85
120
|
concept.data = managed_data
|
|
121
|
+
concept.schema_version = "v3"
|
|
86
122
|
end
|
|
87
123
|
|
|
88
124
|
collection.store(managed_concept)
|
|
@@ -90,10 +126,10 @@ module Suma
|
|
|
90
126
|
end
|
|
91
127
|
end
|
|
92
128
|
|
|
93
|
-
def build_localized_concept(schema:, entity:, source_ref:)
|
|
129
|
+
def build_localized_concept(schema:, entity:, source_ref:, uuid:)
|
|
94
130
|
schema_domain = get_domain(schema)
|
|
95
131
|
|
|
96
|
-
localized_concept_data = Glossarist::ConceptData.new.tap do |data|
|
|
132
|
+
localized_concept_data = Glossarist::V3::ConceptData.new.tap do |data|
|
|
97
133
|
data.terms = get_entity_terms(entity)
|
|
98
134
|
data.definition = get_entity_definitions(entity, schema)
|
|
99
135
|
data.language_code = @language_code
|
|
@@ -105,34 +141,60 @@ module Suma
|
|
|
105
141
|
data.examples = []
|
|
106
142
|
end
|
|
107
143
|
|
|
108
|
-
Glossarist::LocalizedConcept.new
|
|
144
|
+
Glossarist::V3::LocalizedConcept.new(
|
|
145
|
+
data: localized_concept_data, uuid: uuid,
|
|
146
|
+
)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def schema_urn(schema)
|
|
150
|
+
@urn.for_schema(schema.id)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def term_urn(concept_identifier)
|
|
154
|
+
@urn.for_term(concept_identifier)
|
|
109
155
|
end
|
|
110
156
|
|
|
111
|
-
def
|
|
112
|
-
|
|
157
|
+
def express_entity_urn(full_ref)
|
|
158
|
+
@urn.for_entity(full_ref)
|
|
113
159
|
end
|
|
114
160
|
|
|
115
|
-
def
|
|
116
|
-
"#{
|
|
161
|
+
def urn_mention(urn, display)
|
|
162
|
+
"{{#{urn},#{display}}}"
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def get_section_ref(schema)
|
|
166
|
+
return nil unless @urn
|
|
167
|
+
|
|
168
|
+
Glossarist::ConceptReference.new(
|
|
169
|
+
concept_id: "section-#{schema.id}",
|
|
170
|
+
source: schema_urn(schema),
|
|
171
|
+
ref_type: "section",
|
|
172
|
+
)
|
|
117
173
|
end
|
|
118
174
|
|
|
119
175
|
def get_source_ref(schema)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
176
|
+
ref = Glossarist::Citation::Ref.new
|
|
177
|
+
ref.source = schema_urn(schema)
|
|
178
|
+
|
|
179
|
+
build_custom_locality(schema).each do |cl|
|
|
180
|
+
case cl.name
|
|
181
|
+
when "version" then ref.version = cl.value
|
|
182
|
+
end
|
|
124
183
|
end
|
|
125
184
|
|
|
126
|
-
Glossarist::
|
|
185
|
+
origin = Glossarist::V3::Citation.new
|
|
186
|
+
origin.ref = ref
|
|
187
|
+
Glossarist::V3::ConceptSource.new(id: schema.id, type: "authoritative",
|
|
188
|
+
origin: origin)
|
|
127
189
|
end
|
|
128
190
|
|
|
129
191
|
def build_custom_locality(schema)
|
|
130
192
|
localities = []
|
|
131
|
-
localities << Glossarist::CustomLocality.new(name: "schema", value: schema.id)
|
|
132
193
|
|
|
133
194
|
version_item = schema.version.items.detect { |i| i.name == "version" }
|
|
134
195
|
if version_item
|
|
135
|
-
localities << Glossarist::CustomLocality.new(name: "version",
|
|
196
|
+
localities << Glossarist::CustomLocality.new(name: "version",
|
|
197
|
+
value: version_item.value)
|
|
136
198
|
end
|
|
137
199
|
|
|
138
200
|
localities
|
|
@@ -160,10 +222,10 @@ module Suma
|
|
|
160
222
|
|
|
161
223
|
def get_entity_definitions(entity, schema)
|
|
162
224
|
schema_type = extract_file_type(schema.file)
|
|
163
|
-
|
|
225
|
+
get_domain(schema)
|
|
164
226
|
|
|
165
|
-
definition = generate_entity_definition(entity,
|
|
166
|
-
[Glossarist::DetailedDefinition.new(content: definition)]
|
|
227
|
+
definition = generate_entity_definition(entity, schema, schema_type)
|
|
228
|
+
[Glossarist::V3::DetailedDefinition.new(content: definition)]
|
|
167
229
|
end
|
|
168
230
|
|
|
169
231
|
def get_entity_notes(entity, schema_domain, definitions)
|
|
@@ -172,7 +234,7 @@ module Suma
|
|
|
172
234
|
if entity.remarks && !entity.remarks.empty?
|
|
173
235
|
trimmed_def = trim_definition(entity.remarks)
|
|
174
236
|
if trimmed_def && !trimmed_def.empty?
|
|
175
|
-
notes << Glossarist::DetailedDefinition.new(
|
|
237
|
+
notes << Glossarist::V3::DetailedDefinition.new(
|
|
176
238
|
content: convert_express_xref(trimmed_def, schema_domain),
|
|
177
239
|
)
|
|
178
240
|
end
|
|
@@ -343,11 +405,14 @@ module Suma
|
|
|
343
405
|
|
|
344
406
|
def express_reference_to_mention(description)
|
|
345
407
|
description
|
|
346
|
-
.gsub(/<<express:([
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
408
|
+
.gsub(/<<express:([\w.]+)>>/) do |_match|
|
|
409
|
+
full_ref = Regexp.last_match[1]
|
|
410
|
+
entity_id = full_ref.split(".").last
|
|
411
|
+
urn_mention(express_entity_urn(full_ref), entity_id)
|
|
412
|
+
end.gsub(/<<express:([\w.]+),([\w. ][\w. ]*)>>/) do |_match|
|
|
413
|
+
full_ref = Regexp.last_match[1]
|
|
414
|
+
display = Regexp.last_match(2)
|
|
415
|
+
urn_mention(express_entity_urn(full_ref), display)
|
|
351
416
|
end
|
|
352
417
|
end
|
|
353
418
|
|
|
@@ -355,38 +420,46 @@ module Suma
|
|
|
355
420
|
entity_id.downcase.gsub("_", " ")
|
|
356
421
|
end
|
|
357
422
|
|
|
358
|
-
def generate_entity_definition(entity,
|
|
423
|
+
def generate_entity_definition(entity, schema, schema_type)
|
|
359
424
|
return "" if entity.nil?
|
|
360
425
|
|
|
361
426
|
entity_type = case schema_type
|
|
362
427
|
when "module_arm"
|
|
363
|
-
"
|
|
428
|
+
urn_mention(term_urn("general.application_object"),
|
|
429
|
+
"application object")
|
|
364
430
|
when "module_mim"
|
|
365
|
-
"
|
|
431
|
+
urn_mention(term_urn("express-language.entity_data_type"),
|
|
432
|
+
"entity data type")
|
|
366
433
|
when "resource", "business_object_model"
|
|
367
|
-
"
|
|
434
|
+
urn_mention(term_urn("express-language.entity_data_type"),
|
|
435
|
+
"entity data type")
|
|
368
436
|
else
|
|
369
437
|
raise Error, "[suma] encountered unsupported schema_type"
|
|
370
438
|
end
|
|
371
439
|
|
|
440
|
+
entity_ref = urn_mention(term_urn("express-language.entity"), "entity")
|
|
441
|
+
|
|
372
442
|
if entity.subtype_of.empty?
|
|
373
443
|
"#{entity_type} " \
|
|
374
444
|
"that represents the " \
|
|
375
|
-
"#{entity_name_to_text(entity.id)} {
|
|
445
|
+
"#{entity_name_to_text(entity.id)} #{entity_ref}"
|
|
376
446
|
else
|
|
377
|
-
entity_subtypes = entity.subtype_of.map
|
|
447
|
+
entity_subtypes = entity.subtype_of.map do |e|
|
|
448
|
+
urn_mention(express_entity_urn("#{schema.id}.#{e.id}"), e.id)
|
|
449
|
+
end
|
|
378
450
|
|
|
379
451
|
"#{entity_type} that is a type of " \
|
|
380
452
|
"#{entity_subtypes.join(' and ')} " \
|
|
381
453
|
"that represents the " \
|
|
382
|
-
"#{entity_name_to_text(entity.id)} {
|
|
454
|
+
"#{entity_name_to_text(entity.id)} #{entity_ref}"
|
|
383
455
|
end
|
|
384
456
|
end
|
|
385
457
|
|
|
386
|
-
def convert_express_xref(content,
|
|
387
|
-
content.gsub(/<<express:(
|
|
388
|
-
|
|
389
|
-
|
|
458
|
+
def convert_express_xref(content, _schema_domain)
|
|
459
|
+
content.gsub(/<<express:([\w.]+),([\w. ][\w. ]*)>>/) do
|
|
460
|
+
full_ref = Regexp.last_match(1)
|
|
461
|
+
display = Regexp.last_match(2)
|
|
462
|
+
urn_mention(express_entity_urn(full_ref), display)
|
|
390
463
|
end
|
|
391
464
|
end
|
|
392
465
|
end
|