suma 0.3.0 → 0.5.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 +2 -5
- data/README.adoc +70 -12
- data/lib/suma/cli/check_svg_quality.rb +82 -91
- data/lib/suma/cli/core.rb +32 -4
- data/lib/suma/cli/export.rb +37 -19
- data/lib/suma/cli/reformat.rb +39 -63
- data/lib/suma/cli/validate.rb +14 -5
- data/lib/suma/cli/validate_links.rb +11 -155
- data/lib/suma/eengine_converter.rb +9 -8
- data/lib/suma/express_reformatter.rb +94 -0
- data/lib/suma/link_validation.rb +144 -0
- data/lib/suma/link_validator/step.rb +149 -0
- data/lib/suma/link_validator.rb +22 -98
- data/lib/suma/note_processor.rb +270 -0
- data/lib/suma/schema_collection.rb +1 -1
- data/lib/suma/schema_comparer.rb +1 -1
- data/lib/suma/schema_exporter.rb +14 -26
- data/lib/suma/svg_quality/scanner.rb +61 -0
- data/lib/suma/svg_quality.rb +1 -0
- data/lib/suma/term_classification.rb +78 -0
- data/lib/suma/term_extractor.rb +25 -240
- data/lib/suma/version.rb +1 -1
- data/lib/suma.rb +5 -0
- metadata +8 -2
data/lib/suma/term_extractor.rb
CHANGED
|
@@ -6,15 +6,6 @@ require "glossarist"
|
|
|
6
6
|
|
|
7
7
|
module Suma
|
|
8
8
|
class TermExtractor
|
|
9
|
-
REDUNDANT_NOTE_REGEX =
|
|
10
|
-
%r{
|
|
11
|
-
^An? # Starts with "A" or "An"
|
|
12
|
-
\s.*?\sis\sa\stype\sof # Text followed by "is a type of"
|
|
13
|
-
(\sa|\san)? # Optional " a" or " an"
|
|
14
|
-
\s\{\{[^\}]*\}\} # Text in double curly braces
|
|
15
|
-
\s*?\.?$ # Optional whitespace and period at the end
|
|
16
|
-
}x
|
|
17
|
-
|
|
18
9
|
def initialize(schema_manifest_file, output_path, urn:,
|
|
19
10
|
language_code: "eng")
|
|
20
11
|
@schema_manifest_file = File.expand_path(schema_manifest_file)
|
|
@@ -64,7 +55,9 @@ module Suma
|
|
|
64
55
|
|
|
65
56
|
raise Error, "Schema must have an associated file" unless schema.file
|
|
66
57
|
|
|
67
|
-
|
|
58
|
+
classification = TermClassification.for_schema(id: schema.id,
|
|
59
|
+
path: schema.file)
|
|
60
|
+
collection = build_managed_concept_collection(schema, classification)
|
|
68
61
|
output_data(collection)
|
|
69
62
|
collection
|
|
70
63
|
end
|
|
@@ -86,7 +79,7 @@ module Suma
|
|
|
86
79
|
end
|
|
87
80
|
end
|
|
88
81
|
|
|
89
|
-
def build_managed_concept_collection(schema)
|
|
82
|
+
def build_managed_concept_collection(schema, classification)
|
|
90
83
|
source_ref = get_source_ref(schema)
|
|
91
84
|
section_ref = get_section_ref(schema)
|
|
92
85
|
|
|
@@ -102,6 +95,7 @@ module Suma
|
|
|
102
95
|
entity: entity,
|
|
103
96
|
source_ref: source_ref,
|
|
104
97
|
uuid: localized_concept_id,
|
|
98
|
+
classification: classification,
|
|
105
99
|
)
|
|
106
100
|
|
|
107
101
|
managed_data = Glossarist::V3::ManagedConceptData.new.tap do |data|
|
|
@@ -126,17 +120,22 @@ module Suma
|
|
|
126
120
|
end
|
|
127
121
|
end
|
|
128
122
|
|
|
129
|
-
def build_localized_concept(schema:, entity:, source_ref:, uuid
|
|
130
|
-
|
|
123
|
+
def build_localized_concept(schema:, entity:, source_ref:, uuid:,
|
|
124
|
+
classification:)
|
|
125
|
+
schema_domain = classification.domain_for(schema.id)
|
|
131
126
|
|
|
132
127
|
localized_concept_data = Glossarist::V3::ConceptData.new.tap do |data|
|
|
133
128
|
data.terms = get_entity_terms(entity)
|
|
134
|
-
data.definition = get_entity_definitions(entity, schema)
|
|
129
|
+
data.definition = get_entity_definitions(entity, schema, classification)
|
|
135
130
|
data.language_code = @language_code
|
|
136
131
|
data.domain = schema_domain
|
|
137
132
|
data.sources = [source_ref] if source_ref
|
|
138
133
|
|
|
139
|
-
notes =
|
|
134
|
+
notes = NoteProcessor.call(
|
|
135
|
+
entity.remarks,
|
|
136
|
+
definitions: data.definition,
|
|
137
|
+
xref_to_mention: method(:xref_to_mention),
|
|
138
|
+
)
|
|
140
139
|
data.notes = notes if notes && !notes.empty?
|
|
141
140
|
data.examples = []
|
|
142
141
|
end
|
|
@@ -162,6 +161,10 @@ module Suma
|
|
|
162
161
|
"{{#{urn},#{display}}}"
|
|
163
162
|
end
|
|
164
163
|
|
|
164
|
+
def xref_to_mention(full_ref, display)
|
|
165
|
+
urn_mention(express_entity_urn(full_ref), display)
|
|
166
|
+
end
|
|
167
|
+
|
|
165
168
|
def get_section_ref(schema)
|
|
166
169
|
return nil unless @urn
|
|
167
170
|
|
|
@@ -200,16 +203,6 @@ module Suma
|
|
|
200
203
|
localities
|
|
201
204
|
end
|
|
202
205
|
|
|
203
|
-
def get_domain(schema)
|
|
204
|
-
prefix = if schema.id.end_with?("_arm", "_mim")
|
|
205
|
-
"application module"
|
|
206
|
-
else
|
|
207
|
-
"resource"
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
"#{prefix}: #{schema.id}"
|
|
211
|
-
end
|
|
212
|
-
|
|
213
206
|
def get_entity_terms(entity)
|
|
214
207
|
[
|
|
215
208
|
Glossarist::Designation::Base.new(
|
|
@@ -220,222 +213,22 @@ module Suma
|
|
|
220
213
|
]
|
|
221
214
|
end
|
|
222
215
|
|
|
223
|
-
def get_entity_definitions(entity, schema)
|
|
224
|
-
|
|
225
|
-
get_domain(schema)
|
|
226
|
-
|
|
227
|
-
definition = generate_entity_definition(entity, schema, schema_type)
|
|
216
|
+
def get_entity_definitions(entity, schema, classification)
|
|
217
|
+
definition = generate_entity_definition(entity, schema, classification)
|
|
228
218
|
[Glossarist::V3::DetailedDefinition.new(content: definition)]
|
|
229
219
|
end
|
|
230
220
|
|
|
231
|
-
def get_entity_notes(entity, schema_domain, definitions)
|
|
232
|
-
notes = []
|
|
233
|
-
|
|
234
|
-
if entity.remarks && !entity.remarks.empty?
|
|
235
|
-
trimmed_def = trim_definition(entity.remarks)
|
|
236
|
-
if trimmed_def && !trimmed_def.empty?
|
|
237
|
-
notes << Glossarist::V3::DetailedDefinition.new(
|
|
238
|
-
content: convert_express_xref(trimmed_def, schema_domain),
|
|
239
|
-
)
|
|
240
|
-
end
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
notes = only_keep_first_sentence(notes)
|
|
244
|
-
notes = remove_see_content(notes)
|
|
245
|
-
notes = remove_redundant_note(notes)
|
|
246
|
-
notes = remove_invalid_references(notes)
|
|
247
|
-
compare_with_definitions(notes, definitions)
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
def only_keep_first_sentence(notes)
|
|
251
|
-
notes.each do |note|
|
|
252
|
-
if note&.content && should_preserve_complete_structure?(note.content)
|
|
253
|
-
next
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
if note&.content
|
|
257
|
-
new_content = note.content
|
|
258
|
-
.split(".\n").first.strip
|
|
259
|
-
.split(". ").first.strip
|
|
260
|
-
note.content = new_content.end_with?(".") ? new_content : "#{new_content}."
|
|
261
|
-
end
|
|
262
|
-
end
|
|
263
|
-
end
|
|
264
|
-
|
|
265
|
-
def should_preserve_complete_structure?(content)
|
|
266
|
-
return false if content.nil? || content.empty?
|
|
267
|
-
|
|
268
|
-
lines = content.split("\n")
|
|
269
|
-
first_paragraph = lines.first&.strip
|
|
270
|
-
|
|
271
|
-
if first_paragraph&.end_with?(":") && lines.length > 1
|
|
272
|
-
if first_paragraph.count(".").positive?
|
|
273
|
-
return false
|
|
274
|
-
end
|
|
275
|
-
|
|
276
|
-
remaining_content = lines[1..].join("\n")
|
|
277
|
-
return starts_with_list?(remaining_content.strip)
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
false
|
|
281
|
-
end
|
|
282
|
-
|
|
283
|
-
def compare_with_definitions(notes, definitions)
|
|
284
|
-
if notes&.first&.content == definitions&.first&.content
|
|
285
|
-
return []
|
|
286
|
-
end
|
|
287
|
-
|
|
288
|
-
notes
|
|
289
|
-
end
|
|
290
|
-
|
|
291
|
-
def remove_invalid_references(notes)
|
|
292
|
-
notes.reject do |note|
|
|
293
|
-
note.content.include?("image::") ||
|
|
294
|
-
note.content.match?(/<<(.*?){1,999}>>/)
|
|
295
|
-
end
|
|
296
|
-
end
|
|
297
|
-
|
|
298
|
-
def remove_redundant_note(notes)
|
|
299
|
-
notes.reject do |note|
|
|
300
|
-
note.content.match?(REDUNDANT_NOTE_REGEX) &&
|
|
301
|
-
!note.content.include?("\n")
|
|
302
|
-
end
|
|
303
|
-
end
|
|
304
|
-
|
|
305
|
-
def remove_see_content(notes)
|
|
306
|
-
notes.each do |note|
|
|
307
|
-
note.content = note.content.gsub(/\s+\(see(.*?){1,999}\)/, "")
|
|
308
|
-
end
|
|
309
|
-
end
|
|
310
|
-
|
|
311
|
-
def extract_file_type(filename)
|
|
312
|
-
match = filename.match(/(arm|mim|bom)_annotated\.exp$/)
|
|
313
|
-
return "resource" unless match
|
|
314
|
-
|
|
315
|
-
{
|
|
316
|
-
"arm" => "module_arm",
|
|
317
|
-
"mim" => "module_mim",
|
|
318
|
-
"bom" => "business_object_model",
|
|
319
|
-
}[match.captures[0]] || "resource"
|
|
320
|
-
end
|
|
321
|
-
|
|
322
|
-
def starts_with_list?(content)
|
|
323
|
-
return false if content.nil? || content.empty?
|
|
324
|
-
|
|
325
|
-
content.match?(/^\s*[*\-+]\s+/) || content.match?(/^\s*\d+\.\s+/)
|
|
326
|
-
end
|
|
327
|
-
|
|
328
|
-
def trim_definition(definition)
|
|
329
|
-
return nil if definition.nil? || definition.empty?
|
|
330
|
-
|
|
331
|
-
definition_str = definition.is_a?(Array) ? definition.join("\n\n") : definition.to_s
|
|
332
|
-
|
|
333
|
-
return nil if definition_str.empty?
|
|
334
|
-
|
|
335
|
-
paragraphs = definition_str.split("\n\n")
|
|
336
|
-
first_paragraph = paragraphs.first
|
|
337
|
-
|
|
338
|
-
combined = if paragraphs.length == 1
|
|
339
|
-
apply_first_sentence_logic(first_paragraph)
|
|
340
|
-
elsif first_paragraph.end_with?(":") && paragraphs.length > 1 && starts_with_list?(paragraphs[1])
|
|
341
|
-
complete_list = extract_complete_list(paragraphs, 1)
|
|
342
|
-
"#{first_paragraph}\n\n#{complete_list}"
|
|
343
|
-
else
|
|
344
|
-
apply_first_sentence_logic(first_paragraph)
|
|
345
|
-
end
|
|
346
|
-
|
|
347
|
-
combined = "#{combined}\n"
|
|
348
|
-
combined.gsub!(/\n\/\/.*?\n/, "\n")
|
|
349
|
-
combined.strip!
|
|
350
|
-
|
|
351
|
-
express_reference_to_mention(combined)
|
|
352
|
-
end
|
|
353
|
-
|
|
354
|
-
def apply_first_sentence_logic(paragraph)
|
|
355
|
-
new_content = paragraph
|
|
356
|
-
.split(".\n").first.strip
|
|
357
|
-
.split(". ").first.strip
|
|
358
|
-
|
|
359
|
-
new_content.end_with?(".") ? new_content : "#{new_content}."
|
|
360
|
-
end
|
|
361
|
-
|
|
362
|
-
def extract_complete_list(paragraphs, start_index)
|
|
363
|
-
return paragraphs[start_index] if start_index >= paragraphs.length
|
|
364
|
-
|
|
365
|
-
combined = paragraphs[start_index].dup
|
|
366
|
-
current_index = start_index + 1
|
|
367
|
-
in_continuation_block = combined.include?("--") && !combined.match?(/--.*--/m)
|
|
368
|
-
|
|
369
|
-
while current_index < paragraphs.length
|
|
370
|
-
next_para = paragraphs[current_index]
|
|
371
|
-
|
|
372
|
-
if next_para.match?(/^--\s*$/) || next_para.end_with?("--")
|
|
373
|
-
in_continuation_block = !in_continuation_block
|
|
374
|
-
combined += "\n\n#{next_para}"
|
|
375
|
-
current_index += 1
|
|
376
|
-
next
|
|
377
|
-
end
|
|
378
|
-
|
|
379
|
-
if in_continuation_block
|
|
380
|
-
combined += "\n\n#{next_para}"
|
|
381
|
-
current_index += 1
|
|
382
|
-
next
|
|
383
|
-
end
|
|
384
|
-
|
|
385
|
-
if starts_with_list?(next_para) || is_list_continuation?(next_para)
|
|
386
|
-
combined += "\n\n#{next_para}"
|
|
387
|
-
current_index += 1
|
|
388
|
-
in_continuation_block = true if next_para.include?("--") && !next_para.match?(/--.*--/m)
|
|
389
|
-
else
|
|
390
|
-
break
|
|
391
|
-
end
|
|
392
|
-
end
|
|
393
|
-
|
|
394
|
-
combined
|
|
395
|
-
end
|
|
396
|
-
|
|
397
|
-
def is_list_continuation?(content)
|
|
398
|
-
return false if content.nil? || content.empty?
|
|
399
|
-
|
|
400
|
-
content.match?(/^\+\s*$/) ||
|
|
401
|
-
content.match?(/^--\s*$/) ||
|
|
402
|
-
content.match?(/^\s{2,}/) ||
|
|
403
|
-
content.start_with?("which", "where", "that")
|
|
404
|
-
end
|
|
405
|
-
|
|
406
|
-
def express_reference_to_mention(description)
|
|
407
|
-
description
|
|
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)
|
|
416
|
-
end
|
|
417
|
-
end
|
|
418
|
-
|
|
419
221
|
def entity_name_to_text(entity_id)
|
|
420
222
|
entity_id.downcase.gsub("_", " ")
|
|
421
223
|
end
|
|
422
224
|
|
|
423
|
-
def generate_entity_definition(entity, schema,
|
|
225
|
+
def generate_entity_definition(entity, schema, classification)
|
|
424
226
|
return "" if entity.nil?
|
|
425
227
|
|
|
426
|
-
entity_type =
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
when "module_mim"
|
|
431
|
-
urn_mention(term_urn("express-language.entity_data_type"),
|
|
432
|
-
"entity data type")
|
|
433
|
-
when "resource", "business_object_model"
|
|
434
|
-
urn_mention(term_urn("express-language.entity_data_type"),
|
|
435
|
-
"entity data type")
|
|
436
|
-
else
|
|
437
|
-
raise Error, "[suma] encountered unsupported schema_type"
|
|
438
|
-
end
|
|
228
|
+
entity_type = urn_mention(
|
|
229
|
+
term_urn(classification.entity_term),
|
|
230
|
+
classification.entity_display,
|
|
231
|
+
)
|
|
439
232
|
|
|
440
233
|
entity_ref = urn_mention(term_urn("express-language.entity"), "entity")
|
|
441
234
|
|
|
@@ -454,13 +247,5 @@ module Suma
|
|
|
454
247
|
"#{entity_name_to_text(entity.id)} #{entity_ref}"
|
|
455
248
|
end
|
|
456
249
|
end
|
|
457
|
-
|
|
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)
|
|
463
|
-
end
|
|
464
|
-
end
|
|
465
250
|
end
|
|
466
251
|
end
|
data/lib/suma/version.rb
CHANGED
data/lib/suma.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "expressir"
|
|
4
4
|
require "lutaml/model"
|
|
5
|
+
require "fileutils"
|
|
5
6
|
|
|
6
7
|
module Suma
|
|
7
8
|
autoload :VERSION, "suma/version"
|
|
@@ -10,9 +11,12 @@ module Suma
|
|
|
10
11
|
autoload :CollectionConfig, "suma/collection_config"
|
|
11
12
|
autoload :CollectionManifest, "suma/collection_manifest"
|
|
12
13
|
autoload :EengineConverter, "suma/eengine_converter"
|
|
14
|
+
autoload :ExpressReformatter, "suma/express_reformatter"
|
|
13
15
|
autoload :ExpressSchema, "suma/express_schema"
|
|
16
|
+
autoload :LinkValidation, "suma/link_validation"
|
|
14
17
|
autoload :LinkValidator, "suma/link_validator"
|
|
15
18
|
autoload :ManifestTraverser, "suma/manifest_traverser"
|
|
19
|
+
autoload :NoteProcessor, "suma/note_processor"
|
|
16
20
|
autoload :RegisterManifestGenerator, "suma/register_manifest_generator"
|
|
17
21
|
autoload :SchemaCategory, "suma/schema_category"
|
|
18
22
|
autoload :SchemaCollection, "suma/schema_collection"
|
|
@@ -26,6 +30,7 @@ module Suma
|
|
|
26
30
|
autoload :SchemaTemplate, "suma/schema_template"
|
|
27
31
|
autoload :SiteConfig, "suma/site_config"
|
|
28
32
|
autoload :SvgQuality, "suma/svg_quality"
|
|
33
|
+
autoload :TermClassification, "suma/term_classification"
|
|
29
34
|
autoload :TermExtractor, "suma/term_extractor"
|
|
30
35
|
autoload :ThorExt, "suma/thor_ext"
|
|
31
36
|
autoload :Urn, "suma/urn"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: suma
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
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-07-
|
|
11
|
+
date: 2026-07-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: expressir
|
|
@@ -206,13 +206,17 @@ files:
|
|
|
206
206
|
- lib/suma/eengine/errors.rb
|
|
207
207
|
- lib/suma/eengine/wrapper.rb
|
|
208
208
|
- lib/suma/eengine_converter.rb
|
|
209
|
+
- lib/suma/express_reformatter.rb
|
|
209
210
|
- lib/suma/express_schema.rb
|
|
210
211
|
- lib/suma/jsdai.rb
|
|
211
212
|
- lib/suma/jsdai/figure.rb
|
|
212
213
|
- lib/suma/jsdai/figure_image.rb
|
|
213
214
|
- lib/suma/jsdai/figure_xml.rb
|
|
215
|
+
- lib/suma/link_validation.rb
|
|
214
216
|
- lib/suma/link_validator.rb
|
|
217
|
+
- lib/suma/link_validator/step.rb
|
|
215
218
|
- lib/suma/manifest_traverser.rb
|
|
219
|
+
- lib/suma/note_processor.rb
|
|
216
220
|
- lib/suma/processor.rb
|
|
217
221
|
- lib/suma/register_manifest_generator.rb
|
|
218
222
|
- lib/suma/schema_category.rb
|
|
@@ -235,6 +239,8 @@ files:
|
|
|
235
239
|
- lib/suma/svg_quality/formatters/terminal_formatter.rb
|
|
236
240
|
- lib/suma/svg_quality/formatters/yaml_formatter.rb
|
|
237
241
|
- lib/suma/svg_quality/report.rb
|
|
242
|
+
- lib/suma/svg_quality/scanner.rb
|
|
243
|
+
- lib/suma/term_classification.rb
|
|
238
244
|
- lib/suma/term_extractor.rb
|
|
239
245
|
- lib/suma/thor_ext.rb
|
|
240
246
|
- lib/suma/urn.rb
|