suma 0.2.6 → 0.4.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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +7 -1
  3. data/.rubocop_todo.yml +170 -13
  4. data/CLAUDE.md +37 -11
  5. data/Gemfile +3 -3
  6. data/README.adoc +127 -13
  7. data/exe/suma +1 -1
  8. data/lib/suma/cli/build.rb +0 -5
  9. data/lib/suma/cli/check_svg_quality.rb +82 -97
  10. data/lib/suma/cli/compare.rb +0 -1
  11. data/lib/suma/cli/convert_jsdai.rb +0 -2
  12. data/lib/suma/cli/core.rb +119 -0
  13. data/lib/suma/cli/export.rb +37 -22
  14. data/lib/suma/cli/extract_terms.rb +5 -8
  15. data/lib/suma/cli/generate_register.rb +34 -0
  16. data/lib/suma/cli/generate_schemas.rb +0 -2
  17. data/lib/suma/cli/reformat.rb +39 -64
  18. data/lib/suma/cli/validate.rb +14 -7
  19. data/lib/suma/cli/validate_links.rb +11 -157
  20. data/lib/suma/cli.rb +12 -141
  21. data/lib/suma/collection_config.rb +0 -2
  22. data/lib/suma/collection_manifest.rb +7 -110
  23. data/lib/suma/eengine/wrapper.rb +0 -1
  24. data/lib/suma/eengine.rb +8 -0
  25. data/lib/suma/express_reformatter.rb +94 -0
  26. data/lib/suma/express_schema.rb +0 -1
  27. data/lib/suma/jsdai/figure.rb +0 -3
  28. data/lib/suma/jsdai.rb +5 -2
  29. data/lib/suma/link_validation.rb +144 -0
  30. data/lib/suma/link_validator.rb +17 -8
  31. data/lib/suma/manifest_traverser.rb +92 -0
  32. data/lib/suma/processor.rb +5 -8
  33. data/lib/suma/register_manifest_generator.rb +163 -0
  34. data/lib/suma/schema_category.rb +83 -0
  35. data/lib/suma/schema_collection.rb +30 -34
  36. data/lib/suma/schema_comparer.rb +4 -3
  37. data/lib/suma/schema_compiler.rb +86 -0
  38. data/lib/suma/schema_discovery.rb +75 -0
  39. data/lib/suma/schema_exporter.rb +14 -42
  40. data/lib/suma/schema_manifest_generator.rb +14 -6
  41. data/lib/suma/schema_naming.rb +111 -0
  42. data/lib/suma/schema_template/document.rb +141 -0
  43. data/lib/suma/schema_template/plain.rb +46 -0
  44. data/lib/suma/schema_template.rb +19 -0
  45. data/lib/suma/svg_quality/batch_report.rb +0 -2
  46. data/lib/suma/svg_quality/formatters.rb +12 -0
  47. data/lib/suma/svg_quality/scanner.rb +61 -0
  48. data/lib/suma/svg_quality.rb +4 -1
  49. data/lib/suma/term_classification.rb +78 -0
  50. data/lib/suma/term_extractor.rb +125 -81
  51. data/lib/suma/urn.rb +61 -0
  52. data/lib/suma/version.rb +1 -1
  53. data/lib/suma.rb +35 -3
  54. data/suma.gemspec +1 -1
  55. metadata +28 -6
  56. data/lib/suma/schema_attachment.rb +0 -103
  57. data/lib/suma/schema_document.rb +0 -118
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6e6db67576d42aaaed54f90f72960ad405774d4084be5f7c0e8f1b277ebbbd50
4
- data.tar.gz: ed5cdf3967496436950306f0edcf553751bb3da06c4e4582a014b8e7610e6d35
3
+ metadata.gz: 304c4c7a2ec03c83604a127370259b022e0102d303c4951c2d730d3681d3ad39
4
+ data.tar.gz: b8d9bcd807ea0aadb4f038dd58823d829d495827e4785316cb7c715e79b512cb
5
5
  SHA512:
6
- metadata.gz: 0e4e8fe19fb5b9ec7c8023258e55a8ed100c98bb4ee271898562eeed13d5e1646d09c673e0053f2271827c8413408d5cb9295e94cc39d298be7161d33a0805c2
7
- data.tar.gz: 8110684a885977266204dace36b4b5bb8a88113c1b410aa78c19d8ad4c58c2a49858f14f9495e433414d43b0bd13716a49e47eb8ef7724ee34306826a215ff15
6
+ metadata.gz: 21977b339cd0a16936940c50de766ba2130f3dc46df7965db1de04360a65c1d685e1b59786e9a49548d0e79f1d20befcf732a66482b6e8b8793a547bd557d28e
7
+ data.tar.gz: bd1122e6d73a9a22b3a3830c7cf654c909a541e7c332808349b15bb469f772338ad7a84a25590f1c8d13b46b84d8399673fa2f43f16f5d943e0e1f8e2469a08a
data/.gitignore CHANGED
@@ -11,4 +11,10 @@
11
11
  .rspec_status
12
12
  .rubocop-https---*-yml
13
13
  .ruby-version
14
- Gemfile.lock
14
+ Gemfile.lock
15
+
16
+ # local planning scratch directories and files (not for commit)
17
+ /TODO*
18
+
19
+ # vendored gems (use Gemfile / Gemfile.lock elsewhere)
20
+ /*.gem
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2026-05-11 08:57:26 UTC using RuboCop version 1.86.1.
3
+ # on 2026-07-02 16:27:30 UTC using RuboCop version 1.87.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -16,13 +16,147 @@ Gemspec/RequiredRubyVersion:
16
16
  Exclude:
17
17
  - 'suma.gemspec'
18
18
 
19
- # Offense count: 120
19
+ # Offense count: 35
20
+ # This cop supports safe autocorrection (--autocorrect).
21
+ # Configuration parameters: EnforcedStyle, IndentationWidth.
22
+ # SupportedStyles: with_first_argument, with_fixed_indentation
23
+ Layout/ArgumentAlignment:
24
+ Exclude:
25
+ - 'lib/suma/link_validator.rb'
26
+ - 'lib/suma/schema_comparer.rb'
27
+ - 'lib/suma/schema_compiler.rb'
28
+ - 'lib/suma/schema_manifest_generator.rb'
29
+ - 'lib/suma/svg_quality/formatters.rb'
30
+ - 'lib/suma/term_extractor.rb'
31
+ - 'spec/suma/link_validator_spec.rb'
32
+ - 'spec/suma/manifest_traverser_spec.rb'
33
+ - 'spec/suma/register_manifest_generator_spec.rb'
34
+ - 'spec/suma/schema_comparer_integration_spec.rb'
35
+ - 'spec/suma/schema_comparer_spec.rb'
36
+ - 'spec/suma/schema_discovery_spec.rb'
37
+ - 'spec/suma/term_extractor_spec.rb'
38
+
39
+ # Offense count: 2
40
+ # This cop supports safe autocorrection (--autocorrect).
41
+ # Configuration parameters: EnforcedStyle, IndentationWidth.
42
+ # SupportedStyles: with_first_element, with_fixed_indentation
43
+ Layout/ArrayAlignment:
44
+ Exclude:
45
+ - 'lib/suma/schema_naming.rb'
46
+ - 'spec/suma/register_manifest_generator_spec.rb'
47
+
48
+ # Offense count: 6
49
+ # This cop supports safe autocorrection (--autocorrect).
50
+ # Configuration parameters: EnforcedStyleAlignWith.
51
+ # SupportedStylesAlignWith: either, start_of_block, start_of_line
52
+ Layout/BlockAlignment:
53
+ Exclude:
54
+ - 'lib/suma/link_validator.rb'
55
+ - 'lib/suma/register_manifest_generator.rb'
56
+ - 'spec/suma/term_extractor_spec.rb'
57
+
58
+ # Offense count: 6
59
+ # This cop supports safe autocorrection (--autocorrect).
60
+ Layout/BlockEndNewline:
61
+ Exclude:
62
+ - 'lib/suma/link_validator.rb'
63
+ - 'lib/suma/register_manifest_generator.rb'
64
+ - 'spec/suma/term_extractor_spec.rb'
65
+
66
+ # Offense count: 3
67
+ # This cop supports safe autocorrection (--autocorrect).
68
+ # Configuration parameters: IndentationWidth.
69
+ Layout/ClosingParenthesisIndentation:
70
+ Exclude:
71
+ - 'lib/suma/schema_template/document.rb'
72
+ - 'spec/suma/link_validator_spec.rb'
73
+ - 'spec/suma/schema_index_spec.rb'
74
+
75
+ # Offense count: 3
76
+ # This cop supports safe autocorrection (--autocorrect).
77
+ # Configuration parameters: EnforcedStyle, IndentationWidth.
78
+ # SupportedStyles: consistent, consistent_relative_to_receiver, special_for_inner_method_call, special_for_inner_method_call_in_parentheses
79
+ Layout/FirstArgumentIndentation:
80
+ Exclude:
81
+ - 'lib/suma/schema_template/document.rb'
82
+ - 'spec/suma/link_validator_spec.rb'
83
+ - 'spec/suma/schema_index_spec.rb'
84
+
85
+ # Offense count: 6
86
+ # This cop supports safe autocorrection (--autocorrect).
87
+ # Configuration parameters: EnforcedStyle, IndentationWidth.
88
+ # SupportedStyles: special_inside_parentheses, consistent, align_brackets
89
+ Layout/FirstArrayElementIndentation:
90
+ Exclude:
91
+ - 'spec/suma/manifest_traverser_spec.rb'
92
+
93
+ # Offense count: 14
94
+ # This cop supports safe autocorrection (--autocorrect).
95
+ # Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
96
+ # SupportedHashRocketStyles: key, separator, table
97
+ # SupportedColonStyles: key, separator, table
98
+ # SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
99
+ Layout/HashAlignment:
100
+ Exclude:
101
+ - 'lib/suma/schema_compiler.rb'
102
+ - 'lib/suma/term_extractor.rb'
103
+ - 'spec/suma/manifest_traverser_spec.rb'
104
+
105
+ # Offense count: 12
106
+ # This cop supports safe autocorrection (--autocorrect).
107
+ # Configuration parameters: Width, EnforcedStyleAlignWith, AllowedPatterns.
108
+ # SupportedStylesAlignWith: start_of_line, relative_to_receiver
109
+ Layout/IndentationWidth:
110
+ Exclude:
111
+ - 'lib/suma/link_validator.rb'
112
+ - 'lib/suma/register_manifest_generator.rb'
113
+ - 'spec/suma/term_extractor_spec.rb'
114
+
115
+ # Offense count: 189
20
116
  # This cop supports safe autocorrection (--autocorrect).
21
117
  # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
22
118
  # URISchemes: http, https
23
119
  Layout/LineLength:
24
120
  Enabled: false
25
121
 
122
+ # Offense count: 3
123
+ # This cop supports safe autocorrection (--autocorrect).
124
+ # Configuration parameters: EnforcedStyle.
125
+ # SupportedStyles: symmetrical, new_line, same_line
126
+ Layout/MultilineArrayBraceLayout:
127
+ Exclude:
128
+ - 'spec/suma/manifest_traverser_spec.rb'
129
+
130
+ # Offense count: 3
131
+ # This cop supports safe autocorrection (--autocorrect).
132
+ # Configuration parameters: EnforcedStyle.
133
+ # SupportedStyles: symmetrical, new_line, same_line
134
+ Layout/MultilineMethodCallBraceLayout:
135
+ Exclude:
136
+ - 'lib/suma/schema_template/document.rb'
137
+ - 'spec/suma/link_validator_spec.rb'
138
+ - 'spec/suma/schema_index_spec.rb'
139
+
140
+ # Offense count: 32
141
+ # This cop supports safe autocorrection (--autocorrect).
142
+ # Configuration parameters: AllowInHeredoc.
143
+ Layout/TrailingWhitespace:
144
+ Exclude:
145
+ - 'lib/suma/link_validator.rb'
146
+ - 'lib/suma/schema_comparer.rb'
147
+ - 'lib/suma/schema_compiler.rb'
148
+ - 'lib/suma/schema_manifest_generator.rb'
149
+ - 'lib/suma/schema_naming.rb'
150
+ - 'lib/suma/svg_quality/formatters.rb'
151
+ - 'lib/suma/term_extractor.rb'
152
+ - 'spec/suma/link_validator_spec.rb'
153
+ - 'spec/suma/manifest_traverser_spec.rb'
154
+ - 'spec/suma/register_manifest_generator_spec.rb'
155
+ - 'spec/suma/schema_comparer_integration_spec.rb'
156
+ - 'spec/suma/schema_comparer_spec.rb'
157
+ - 'spec/suma/schema_discovery_spec.rb'
158
+ - 'spec/suma/term_extractor_spec.rb'
159
+
26
160
  # Offense count: 4
27
161
  # Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch.
28
162
  Lint/DuplicateBranch:
@@ -48,29 +182,31 @@ Lint/UnusedMethodArgument:
48
182
  Exclude:
49
183
  - 'lib/suma/svg_quality.rb'
50
184
 
51
- # Offense count: 29
185
+ # Offense count: 32
52
186
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
53
187
  Metrics/AbcSize:
54
188
  Exclude:
55
- - 'lib/suma/cli.rb'
56
189
  - 'lib/suma/cli/check_svg_quality.rb'
190
+ - 'lib/suma/cli/core.rb'
57
191
  - 'lib/suma/jsdai/figure.rb'
58
192
  - 'lib/suma/jsdai/figure_image.rb'
59
193
  - 'lib/suma/link_validator.rb'
194
+ - 'lib/suma/manifest_traverser.rb'
60
195
  - 'lib/suma/processor.rb'
61
- - 'lib/suma/schema_attachment.rb'
196
+ - 'lib/suma/schema_collection.rb'
62
197
  - 'lib/suma/schema_comparer.rb'
63
- - 'lib/suma/schema_document.rb'
198
+ - 'lib/suma/schema_compiler.rb'
64
199
  - 'lib/suma/schema_manifest_generator.rb'
200
+ - 'lib/suma/schema_template/document.rb'
65
201
  - 'lib/suma/svg_quality/formatters/terminal_formatter.rb'
66
202
  - 'lib/suma/term_extractor.rb'
67
203
  - 'lib/suma/thor_ext.rb'
68
204
 
69
- # Offense count: 1
205
+ # Offense count: 3
70
206
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
71
207
  # AllowedMethods: refine
72
208
  Metrics/BlockLength:
73
- Max: 54
209
+ Max: 58
74
210
 
75
211
  # Offense count: 14
76
212
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
@@ -87,12 +223,12 @@ Metrics/CyclomaticComplexity:
87
223
  - 'lib/suma/term_extractor.rb'
88
224
  - 'lib/suma/thor_ext.rb'
89
225
 
90
- # Offense count: 25
226
+ # Offense count: 31
91
227
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
92
228
  Metrics/MethodLength:
93
- Max: 59
229
+ Max: 63
94
230
 
95
- # Offense count: 2
231
+ # Offense count: 3
96
232
  # Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
97
233
  Metrics/ParameterLists:
98
234
  Max: 9
@@ -150,7 +286,7 @@ RSpec/ContextWording:
150
286
  Exclude:
151
287
  - 'spec/suma/cli/export_spec.rb'
152
288
 
153
- # Offense count: 71
289
+ # Offense count: 111
154
290
  # Configuration parameters: CountAsOne.
155
291
  RSpec/ExampleLength:
156
292
  Max: 60
@@ -181,7 +317,7 @@ RSpec/MessageSpies:
181
317
  Exclude:
182
318
  - 'spec/suma/schema_comparer_integration_spec.rb'
183
319
 
184
- # Offense count: 50
320
+ # Offense count: 87
185
321
  RSpec/MultipleExpectations:
186
322
  Max: 21
187
323
 
@@ -203,6 +339,27 @@ RSpec/StubbedMock:
203
339
  Exclude:
204
340
  - 'spec/suma/schema_comparer_integration_spec.rb'
205
341
 
342
+ # Offense count: 9
343
+ # This cop supports safe autocorrection (--autocorrect).
344
+ # Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, AllowedMethods, AllowedPatterns, AllowBracesOnProceduralOneLiners, BracesRequiredMethods.
345
+ # SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces
346
+ # ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object
347
+ # FunctionalMethods: let, let!, subject, watch
348
+ # AllowedMethods: lambda, proc, it
349
+ Style/BlockDelimiters:
350
+ Exclude:
351
+ - 'lib/suma/link_validator.rb'
352
+ - 'lib/suma/register_manifest_generator.rb'
353
+ - 'spec/suma/term_extractor_spec.rb'
354
+
355
+ # Offense count: 4
356
+ # This cop supports safe autocorrection (--autocorrect).
357
+ Style/MultilineIfModifier:
358
+ Exclude:
359
+ - 'lib/suma/schema_comparer.rb'
360
+ - 'lib/suma/schema_manifest_generator.rb'
361
+ - 'lib/suma/schema_naming.rb'
362
+
206
363
  # Offense count: 1
207
364
  # Configuration parameters: AllowedMethods.
208
365
  # AllowedMethods: respond_to_missing?
data/CLAUDE.md CHANGED
@@ -27,7 +27,8 @@ exe/suma export -o OUTPUT_DIR schema1.yml schema2.exp # Export schemas (YAML ma
27
27
  exe/suma compare TRIAL_SCHEMA REFERENCE_SCHEMA -v VER # Compare schemas, generate .changes.yaml
28
28
  exe/suma reformat PATH # Reformat EXP files (use -r for recursive)
29
29
  exe/suma generate-schemas METANORMA_YAML SCHEMAS_YAML # Generate schema manifest from site manifest
30
- exe/suma extract-terms SCHEMA_YAML GLOSSARIST_DIR # Extract terms to Glossarist v2 format
30
+ exe/suma extract-terms SCHEMA_YAML GLOSSARIST_DIR -u URN # Extract EXPRESS entity concepts to Glossarist v3 format
31
+ exe/suma generate-register SCHEMA_YAML OUT_DIR -u URN --id ID --ref REF # Generate hierarchical register.yaml from schema manifest
31
32
  exe/suma validate links SCHEMAS_FILE DOCS_PATH # Validate EXPRESS cross-reference links
32
33
  ```
33
34
 
@@ -35,27 +36,50 @@ exe/suma validate links SCHEMAS_FILE DOCS_PATH # Validate EXPRESS cross
35
36
 
36
37
  ### Core pipeline (build command)
37
38
 
38
- 1. `Processor.run` receives a Metanorma site manifest YAML
39
+ 1. `Processor.new(...).run` receives a Metanorma site manifest YAML
39
40
  2. `SiteConfig` reads the site manifest, finds collection YAML paths
40
41
  3. `CollectionConfig` extends `Metanorma::Collection::Config` with a `CollectionManifest` that discovers `schemas.yaml` files
41
- 4. `SchemaCollection` loads all discovered schemas via `Expressir`, exports plain `.exp` files, and compiles documentation (Metanorma `.adoc` → XML/HTML)
42
- 5. `SchemaExporter` handles exporting schemas to a directory (with optional ZIP packaging)
42
+ 4. `ManifestTraverser` walks the manifest tree (`expand_schemas_only`, `export_schema_config`, `remove_schemas_only_sources`); `SchemaDiscovery` loads each `schemas.yaml` and builds doc sub-trees
43
+ 5. `SchemaCollection` loads all discovered schemas via `Expressir`, exports plain `.exp` files, and compiles documentation via `SchemaCompiler` + `SchemaTemplate::Plain|Document` (Metanorma `.adoc` XML/HTML)
44
+ 6. `SchemaExporter` handles exporting schemas to a directory (with optional ZIP packaging)
43
45
 
44
46
  ### Key classes
45
47
 
46
- - **`ExpressSchema`** — wraps a single EXPRESS schema file; parses via `Expressir::Express::Parser`, can output plain or annotated `.exp`
47
- - **`SchemaAttachment`** — compiles one schema into a Metanorma `.adoc` document and renders it via `Metanorma::Compile`
48
- - **`SchemaDocument`** (extends `SchemaAttachment`) adds cross-reference bookmarks and uses XML-only output
49
- - **`SchemaCollection`** — orchestrates processing of all schemas from a config
48
+ - **`ExpressSchema`** — wraps a single EXPRESS schema file; parses via `Expressir::Express::Parser`, can output plain or annotated `.exp`. Includes nested `Type` module for schema classification (resource/module_arm/module_mim/business_object_model/core_model/standalone) based on ID suffixes and path segments
49
+ - **`SchemaCategory`** — value object mapping `ExpressSchema::Type` to a register/export category (id, label, prefix, types, directory). Single source of truth for category identity across `SchemaExporter`, `SchemaNaming`, and `RegisterManifestGenerator`
50
+ - **`Urn`** value object encapsulating ISO URN semantics (wildcard stripping, base/alias split, leaf composition for `for_schema`/`for_term`/`for_entity`)
51
+ - **`TermExtractor`** — extracts EXPRESS entity concepts from a schema manifest into Glossarist v3 YAML format. Generates definitions with URN cross-references, processes remarks into notes, and resolves EXPRESS xrefs to URN mentions. Assigns stable UUIDv5 identifiers
52
+ - **`RegisterManifestGenerator`** (file: `lib/suma/register_manifest_generator.rb`) — generates a Glossarist v3 `register.yaml` with hierarchical sections from a schema manifest. Classifies schemas via `ExpressSchema::Type` (DRY), delegates naming to `SchemaNaming` (OCP), orders resources before modules. Uses the Section model's `children` field for hierarchy
53
+ - **`SchemaNaming`** — pure module that converts EXPRESS schema IDs to human-readable display names. Strips type suffixes (`_schema`/`_arm`/`_mim`/`_bom`), title-cases with acronym preservation (AIC, AEC, BREP, 2D, 3D…), lowercases function words, appends type labels (ARM/MIM)
54
+ - **`SchemaTemplate::Plain` / `SchemaTemplate::Document`** — pure renderers for the AsciiDoc body fed to Metanorma (no I/O, no schema knowledge). `Document` adds cross-reference anchors and produces XML-only output
55
+ - **`SchemaCompiler`** — orchestrates one schema's compilation: writes adoc + config, invokes `Metanorma::Compile`. Templates are injected via the constructor (composition over inheritance)
56
+ - **`SchemaCollection`** — orchestrates processing of all schemas from a config; selects `Plain` for top-level schemas and `Document` for schemas-only entries
50
57
  - **`SchemaExporter`** — standalone export of schemas from manifest or `.exp` files to a directory, with optional ZIP
51
- - **`CollectionManifest`** — traverses collection YAML files, builds unified `Expressir::SchemaManifest`
58
+ - **`CollectionManifest`** — pure data model (lutaml-model attributes + YAML mappings) for one node of a Metanorma collection manifest. No imperative methods
59
+ - **`ManifestTraverser`** — tree-walking service over a `CollectionManifest` (`find_schemas_only`, `export_schema_config`, `expand_schemas_only`, `remove_schemas_only_sources`)
60
+ - **`SchemaDiscovery`** — schema-config I/O service on a single manifest node (`load_config` from `schemas.yaml`, `build_doc_entries`, `build_added_manifest`)
61
+ - **`SchemaIndex`** — O(1) lookup index for schema and element names, used by `LinkValidator`
62
+ - **`LinkValidator`** — validates EXPRESS cross-reference links against a `SchemaIndex`; returns `LinkValidationResult` structs for unresolved links
52
63
 
53
64
  ### CLI structure
54
65
 
55
66
  - `Suma::Cli::Core` (Thor subclass) — top-level CLI entrypoint
56
- - Subcommands delegate to `Cli::Build`, `Cli::Export`, `Cli::Compare`, `Cli::Validate`, `Cli::Reformat`, `Cli::GenerateSchemas`, `Cli::ExtractTerms`, `Cli::ConvertJsdai`
67
+ - Subcommands delegate to `Cli::Build`, `Cli::Export`, `Cli::Compare`, `Cli::Validate`, `Cli::Reformat`, `Cli::GenerateSchemas`, `Cli::ExtractTerms`, `Cli::GenerateRegister`, `Cli::ConvertJsdai`
57
68
  - Thor extension (`ThorExt::Start`) adds `-h`/`--help` support and error formatting
58
69
 
70
+ ### Terminology extraction (extract-terms / generate-register)
71
+
72
+ The `extract-terms` command reads an EXPRESS schema manifest, parses each `.exp` file via `Expressir`, and emits Glossarist v3 concept YAML with:
73
+ - Entity definitions using URN cross-references (`{{urn:...term,entity data type}}`, `{{urn:...term,entity}}`)
74
+ - Entity remarks processed into notes (first-sentence extraction, redundant note removal, invalid reference filtering)
75
+ - Domain classification via `ExpressSchema::Type` (resource vs application module)
76
+ - Section references for hierarchical grouping
77
+
78
+ The `generate-register` command reads the same schema manifest and emits `register.yaml` with hierarchical sections:
79
+ - Top-level groups: Resources (133) before Application Modules (1123)
80
+ - Child sections use human-readable names from `SchemaNaming` (e.g. "Resource: Topology", "Module: Activity (ARM)")
81
+ - Parent group IDs are included in concept metadata so the concept-browser can filter by group
82
+
59
83
  ### External dependencies
60
84
 
61
85
  - **expressir** — EXPRESS schema parsing and manifest handling
@@ -73,4 +97,6 @@ The `compare` command uses an external `eengine` binary to diff two EXPRESS sche
73
97
  - Ruby 3.0+ with `frozen_string_literal: true` in every file
74
98
  - RuboCop with performance, rake, and rspec plugins; inherits from riboseinc OSS guide
75
99
  - Some CLI files are excluded from RuboCop in `.rubocop.yml`
76
- - Use `Utils.log` for user-facing output (prefixes with `[suma]`)
100
+ - Internal library code uses Ruby `autoload` (defined in the immediate parent namespace's file); no `require_relative`
101
+ - No `send` to call private methods, no `instance_variable_set`/`get`, no `respond_to?` for type checking
102
+ - Use `Utils.log` for user-facing output (writes to `$stderr`, prefix `[suma]`; `level: :debug` gated by `SUMA_DEBUG`)
data/Gemfile CHANGED
@@ -6,9 +6,9 @@ source "https://rubygems.org"
6
6
  gemspec
7
7
 
8
8
  gem "canon"
9
- gem "metanorma", github: "metanorma/metanorma", branch: "main"
10
- gem "metanorma-plugin-lutaml", github: "metanorma/metanorma-plugin-lutaml", branch: "main"
11
- gem "metanorma-standoc", github: "metanorma/metanorma-standoc", branch: "main"
9
+ # gem "metanorma", github: "metanorma/metanorma", branch: "main"
10
+ # gem "metanorma-plugin-lutaml", github: "metanorma/metanorma-plugin-lutaml", branch: "main"
11
+ # gem "metanorma-standoc", github: "metanorma/metanorma-standoc", branch: "main"
12
12
  gem "nokogiri"
13
13
  gem "openssl", "~> 3.0"
14
14
  gem "rake"
data/README.adoc CHANGED
@@ -39,7 +39,8 @@ $ suma
39
39
  Commands:
40
40
  suma build METANORMA_SITE_MANIFEST # Build collection specified in site manifest (`metanorma*.yml`)
41
41
  suma convert-jsdai XML_FILE IMAGE_FILE OUTPUT_DIR # Convert JSDAI XML and image files to SVG and EXP files
42
- suma extract-terms SCHEMA_MANIFEST_FILE GLOSSARIST_OUTPUT_PATH # Extract terms from SCHEMA_MANIFEST_FILE into Glossarist v2 format
42
+ suma extract-terms SCHEMA_MANIFEST_FILE GLOSSARIST_OUTPUT_PATH # Extract EXPRESS entity concepts into Glossarist v3 format
43
+ suma generate-register SCHEMA_MANIFEST_FILE OUTPUT_PATH # Generate hierarchical register.yaml from schema manifest
43
44
  suma generate-schemas METANORMA_MANIFEST_FILE SCHEMA_MANIFEST_FILE # Generate EXPRESS schema manifest file from Metanorma site manifest
44
45
  suma help [COMMAND] # Describe available commands or one specific command
45
46
  suma reformat EXPRESS_FILE_PATH # Reformat EXPRESS files
@@ -301,6 +302,61 @@ $ bundle exec suma extract-terms schemas-activity-modules.yml terms_output
301
302
  ====
302
303
 
303
304
 
305
+ === Generate register command
306
+
307
+ The `suma generate-register` command reads an EXPRESS schema manifest and
308
+ emits a Glossarist v3 `register.yaml` with hierarchical sections. The
309
+ output is used by the concept browser to render a navigable sidebar of
310
+ sections and to resolve concept cross-references.
311
+
312
+ [source,sh]
313
+ ----
314
+ $ suma generate-register SCHEMA_MANIFEST_FILE OUTPUT_PATH -u URN --id ID --ref REF
315
+ ----
316
+
317
+ Parameters:
318
+
319
+ `SCHEMA_MANIFEST_FILE`:: Path to the schema manifest (e.g., "schemas-smrl-part-2.yml")
320
+
321
+ `OUTPUT_PATH`:: Directory where `register.yaml` will be written
322
+
323
+ Options:
324
+
325
+ `--urn`, `-u`:: Base URN prefix for the dataset (e.g. `urn:iso:std:iso:10303:-2:ed-2:en:tech:*`).
326
+ The wildcard is stripped for the base URN and kept in `urnAliases`.
327
+ *Required*.
328
+
329
+ The URN is fully configurable — every component can be changed to match the
330
+ dataset being exported. The general structure is:
331
+
332
+ ----
333
+ urn:iso:std:iso:<part>:ed-<edition>:<lang>:tech:*
334
+ ----
335
+
336
+ For example, to export edition 3 in French:
337
+
338
+ ----
339
+ --urn urn:iso:std:iso:10303:-2:ed-3:fr:tech:*
340
+ ----
341
+
342
+ The current ISO 10303-2 SMRL data is edition 2; use `ed-2` unless you are
343
+ re-publishing an earlier edition.
344
+
345
+ `--id`:: Dataset identifier (e.g. `iso10303-2-express`). *Required*.
346
+
347
+ `--ref`:: Human-readable dataset reference label (e.g. `ISO 10303-2 EXPRESS Concepts`). *Required*.
348
+
349
+ `--language_code`, `-l`:: Language code for section names (default: "eng")
350
+
351
+ The generated register contains two top-level groups:
352
+
353
+ * **Resources** — integrated resource schemas (path contains `schemas/resources/`)
354
+ * **Application Modules** — ARM and MIM schemas (path contains `schemas/modules/`)
355
+
356
+ Each schema gets a human-readable name via the `SchemaNaming` module
357
+ (e.g. `topology_schema` → "Resource: Topology", `Activity_method_assignment_mim` → "Module: Activity Method Assignment (MIM)"). Acronyms (AIC, AEC, BREP, 2D, 3D) are preserved; function words (as, of, the) are lowercased per ISO title-case convention.
358
+
359
+
304
360
  === Convert JSDAI image outputs to SVG and Annotated EXPRESS
305
361
 
306
362
  The `suma convert-jsdai` command converts JSDAI EXPRESS-G diagram outputs
@@ -1009,34 +1065,31 @@ examples demonstrate common usage patterns.
1009
1065
  require 'suma'
1010
1066
 
1011
1067
  # Build a collection with default settings
1012
- Suma::Processor.run(
1068
+ Suma::Processor.new(
1013
1069
  metanorma_yaml_path: "metanorma-srl.yml",
1014
1070
  schemas_all_path: "schemas-srl.yml",
1015
1071
  compile: true,
1016
1072
  output_directory: "_site"
1017
- )
1073
+ ).run
1018
1074
 
1019
1075
  # Generate schema listing without compilation
1020
- Suma::Processor.run(
1076
+ Suma::Processor.new(
1021
1077
  metanorma_yaml_path: "metanorma-srl.yml",
1022
1078
  schemas_all_path: "schemas-srl.yml",
1023
- compile: false,
1024
- output_directory: "_site"
1025
- )
1079
+ compile: false
1080
+ ).run
1026
1081
  ----
1027
1082
 
1028
- === Working with schema configurations
1083
+ === Working with schema manifests
1084
+
1085
+ Schema manifests are loaded via `Expressir::SchemaManifest`:
1029
1086
 
1030
1087
  [source,ruby]
1031
1088
  ----
1032
1089
  require 'suma'
1033
1090
 
1034
- # Load schemas using SchemaConfig
1035
1091
  schemas_file_path = "schemas-srl.yml"
1036
- schemas_config = Suma::SchemaConfig::Config.from_yaml(IO.read(schemas_file_path))
1037
-
1038
- # Set the initial path to resolve relative paths
1039
- schemas_config.set_initial_path(schemas_file_path)
1092
+ schemas_config = Expressir::SchemaManifest.from_file(schemas_file_path)
1040
1093
 
1041
1094
  # Access schema information
1042
1095
  schemas_config.schemas.each do |schema|
@@ -1045,6 +1098,67 @@ schemas_config.schemas.each do |schema|
1045
1098
  end
1046
1099
  ----
1047
1100
 
1101
+ === Extracting terms
1102
+
1103
+ [source,ruby]
1104
+ ----
1105
+ require 'suma'
1106
+
1107
+ Suma::TermExtractor.new(
1108
+ "schemas-smrl-part-2.yml",
1109
+ "glossarist_output",
1110
+ urn: "urn:iso:std:iso:10303:-2:ed-2:en:tech:*",
1111
+ ).call
1112
+ ----
1113
+
1114
+ === Generating a register.yaml
1115
+
1116
+ [source,ruby]
1117
+ ----
1118
+ require 'suma'
1119
+
1120
+ Suma::RegisterManifestGenerator.new(
1121
+ "schemas-smrl-part-2.yml",
1122
+ "register_output",
1123
+ urn: "urn:iso:std:iso:10303:-2:ed-2:en:tech:*",
1124
+ id: "iso10303-2-express",
1125
+ ref: "ISO 10303-2 EXPRESS Concepts",
1126
+ ).generate
1127
+ ----
1128
+
1129
+ === Architecture
1130
+
1131
+ Suma's domain is split into MECE concerns:
1132
+
1133
+ * **Data models** (pure): `CollectionManifest`, `ExpressSchema`
1134
+ * **Value objects** (pure): `SchemaCategory`, `Urn`
1135
+ * **Services** (single concern): `ManifestTraverser`, `SchemaDiscovery`,
1136
+ `SchemaCompiler`, `SchemaExporter`, `SchemaIndex`, `LinkValidator`,
1137
+ `SchemaComparer`, `SchemaManifestGenerator`, `TermExtractor`,
1138
+ `RegisterManifestGenerator`, `Processor`
1139
+ * **Renderers** (pure, composable): `SchemaTemplate::Plain`,
1140
+ `SchemaTemplate::Document`
1141
+
1142
+ Key invariants:
1143
+
1144
+ * The classifier `ExpressSchema::Type.classify(id:, path:)` is the single
1145
+ source of truth for schema type. `SchemaCategory`, `SchemaNaming`,
1146
+ `SchemaExporter`, and `RegisterManifestGenerator` all derive from it.
1147
+ * `Urn` owns URN semantics (wildcard stripping, base/alias split, leaf
1148
+ composition).
1149
+ * `CollectionManifest` is a pure data model; tree walking lives in
1150
+ `ManifestTraverser`, schema I/O lives in `SchemaDiscovery`.
1151
+ * `SchemaCompiler` orchestrates one Metanorma compilation; the adoc body
1152
+ is injected via a `SchemaTemplate::*` renderer.
1153
+
1154
+ Code-style rules enforced throughout `lib/suma/`:
1155
+
1156
+ * Ruby `autoload` only — no `require_relative`
1157
+ * No `send` to call private methods
1158
+ * No `instance_variable_set` / `instance_variable_get`
1159
+ * No `respond_to?` for type checking
1160
+ * `Utils.log` writes to `$stderr`; debug level gated by `SUMA_DEBUG`
1161
+
1048
1162
 
1049
1163
  == Copyright and license
1050
1164
 
data/exe/suma CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require "suma/cli"
4
+ require "suma"
5
5
 
6
6
  Suma::Cli::Core.start(ARGV)
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "thor"
4
- require_relative "../thor_ext"
5
4
 
6
5
  module Suma
7
6
  module Cli
@@ -15,10 +14,6 @@ module Suma
15
14
  desc: "Generate file that contains all schemas in the collection."
16
15
 
17
16
  def build(metanorma_site_manifest)
18
- # Lazy-load dependencies only when this command is actually used
19
- require_relative "../processor"
20
- require_relative "../utils"
21
-
22
17
  unless File.exist?(metanorma_site_manifest)
23
18
  raise Errno::ENOENT, "Specified Metanorma site manifest file " \
24
19
  "`#{metanorma_site_manifest}` not found."