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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +10 -1
  3. data/.rubocop_todo.yml +170 -13
  4. data/CLAUDE.md +37 -11
  5. data/Gemfile +3 -3
  6. data/README.adoc +57 -1
  7. data/exe/suma +1 -1
  8. data/lib/suma/cli/build.rb +0 -5
  9. data/lib/suma/cli/check_svg_quality.rb +0 -6
  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 +0 -3
  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 +0 -1
  18. data/lib/suma/cli/validate.rb +0 -2
  19. data/lib/suma/cli/validate_links.rb +0 -2
  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_schema.rb +0 -1
  26. data/lib/suma/jsdai/figure.rb +0 -3
  27. data/lib/suma/jsdai.rb +5 -2
  28. data/lib/suma/link_validator.rb +15 -7
  29. data/lib/suma/manifest_traverser.rb +92 -0
  30. data/lib/suma/processor.rb +5 -8
  31. data/lib/suma/register_manifest_generator.rb +163 -0
  32. data/lib/suma/schema_category.rb +83 -0
  33. data/lib/suma/schema_collection.rb +29 -33
  34. data/lib/suma/schema_comparer.rb +4 -3
  35. data/lib/suma/schema_compiler.rb +86 -0
  36. data/lib/suma/schema_discovery.rb +75 -0
  37. data/lib/suma/schema_exporter.rb +2 -18
  38. data/lib/suma/schema_manifest_generator.rb +14 -6
  39. data/lib/suma/schema_naming.rb +111 -0
  40. data/lib/suma/schema_template/document.rb +141 -0
  41. data/lib/suma/schema_template/plain.rb +46 -0
  42. data/lib/suma/schema_template.rb +19 -0
  43. data/lib/suma/svg_quality/batch_report.rb +0 -2
  44. data/lib/suma/svg_quality/formatters.rb +12 -0
  45. data/lib/suma/svg_quality.rb +3 -1
  46. data/lib/suma/term_extractor.rb +119 -46
  47. data/lib/suma/urn.rb +61 -0
  48. data/lib/suma/version.rb +1 -1
  49. data/lib/suma.rb +31 -3
  50. data/suma.gemspec +1 -1
  51. metadata +24 -6
  52. data/lib/suma/schema_attachment.rb +0 -103
  53. 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: 041f227f2bd35c3d90138ab621e51b9abf68206f7b295523da2827d82d6b63c7
4
+ data.tar.gz: f64aed0f1f4aa096d66c4c299581a2437a991fe6f522b50170b26557b81a0092
5
5
  SHA512:
6
- metadata.gz: 0e4e8fe19fb5b9ec7c8023258e55a8ed100c98bb4ee271898562eeed13d5e1646d09c673e0053f2271827c8413408d5cb9295e94cc39d298be7161d33a0805c2
7
- data.tar.gz: 8110684a885977266204dace36b4b5bb8a88113c1b410aa78c19d8ad4c58c2a49858f14f9495e433414d43b0bd13716a49e47eb8ef7724ee34306826a215ff15
6
+ metadata.gz: ac0d654f283a393c6ae620763920decec16ce2bad44c5cc5722f123bf12ee7539069e35dbbb4909f061fdb14e240f26f033d04e357cfdaff814966cc5f185f8b
7
+ data.tar.gz: a2a4ca844993d87bc534c77d99e5767aa0f6f86b1f028a15c9a9387ddc761303fcef390a3fe98dce907580b8da1657bb83f96d7c4d0cdd0e03f59d690a1c688f
data/.gitignore CHANGED
@@ -11,4 +11,13 @@
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 (not for commit)
17
+ /TODO.clean/
18
+ /TODO.cleanup/
19
+ /TODO.refactor/
20
+ /TODO.remaining/
21
+
22
+ # vendored gems (use Gemfile / Gemfile.lock elsewhere)
23
+ /*.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
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."
@@ -1,12 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "pathname"
4
- require_relative "../svg_quality"
5
- require_relative "../svg_quality/report"
6
- require_relative "../svg_quality/batch_report"
7
- require_relative "../svg_quality/formatters/terminal_formatter"
8
- require_relative "../svg_quality/formatters/json_formatter"
9
- require_relative "../svg_quality/formatters/yaml_formatter"
10
4
 
11
5
  module Suma
12
6
  module Cli
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "thor"
4
- require_relative "../schema_comparer"
5
4
 
6
5
  module Suma
7
6
  module Cli
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "thor"
4
- require_relative "../thor_ext"
5
- require_relative "../jsdai"
6
4
  require "fileutils"
7
5
 
8
6
  module Suma
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "thor"
4
+ require "expressir"
5
+ require "expressir/cli"
6
+
7
+ module Suma
8
+ module Cli
9
+ # Top-level CLI entrypoint.
10
+ #
11
+ # Each command delegates to a dedicated Thor class under +Suma::Cli::+,
12
+ # which reparses ARGV and therefore owns the canonical +option+
13
+ # declarations. Re-declaring options here would duplicate the inner
14
+ # classes' declarations and cause help text and validation logic to
15
+ # drift. Options are declared in exactly one place (the inner class).
16
+ #
17
+ # The exception is +check_svg_quality+, which constructs its analyzer
18
+ # inline (no inner Thor class), so its options belong here.
19
+ class Core < Thor
20
+ extend ThorExt::Start
21
+
22
+ desc "build METANORMA_SITE_MANIFEST",
23
+ "Build collection specified in site manifest (`metanorma*.yml`)"
24
+ def build(_site_manifest)
25
+ Cli::Build.start
26
+ end
27
+
28
+ desc "generate-schemas METANORMA_MANIFEST_FILE SCHEMA_MANIFEST_FILE",
29
+ "Generate EXPRESS schema manifest file from Metanorma site manifest"
30
+ def generate_schemas(_metanorma_manifest_file, _schema_manifest_file)
31
+ Cli::GenerateSchemas.start
32
+ end
33
+
34
+ desc "reformat EXPRESS_FILE_PATH",
35
+ "Reformat EXPRESS files"
36
+ def reformat(_express_file_path)
37
+ Cli::Reformat.start
38
+ end
39
+
40
+ desc "extract-terms SCHEMA_MANIFEST_FILE GLOSSARIST_OUTPUT_PATH",
41
+ "Extract terms from SCHEMA_MANIFEST_FILE into " \
42
+ "Glossarist v3 format"
43
+ def extract_terms(_schema_manifest_file, _glossarist_output_path)
44
+ Cli::ExtractTerms.start
45
+ end
46
+
47
+ desc "generate-register SCHEMA_MANIFEST_FILE OUTPUT_PATH",
48
+ "Generate a Glossarist register.yaml with hierarchical sections"
49
+ def generate_register(_schema_manifest_file, _output_path)
50
+ Cli::GenerateRegister.start
51
+ end
52
+
53
+ desc "convert-jsdai XML_FILE IMAGE_FILE OUTPUT_DIR",
54
+ "Convert JSDAI XML and image files to SVG and EXP files"
55
+ def convert_jsdai(_xml_file, _image_file, _output_dir)
56
+ Cli::ConvertJsdai.start
57
+ end
58
+
59
+ desc "export *FILES",
60
+ "Export EXPRESS schemas from manifest files or " \
61
+ "standalone EXPRESS files"
62
+ def export(*_files)
63
+ Cli::Export.start
64
+ end
65
+
66
+ desc "compare TRIAL_SCHEMA REFERENCE_SCHEMA",
67
+ "Compare EXPRESS schemas using eengine and generate Change YAML"
68
+ def compare(_trial_schema, _reference_schema)
69
+ Cli::Compare.start
70
+ end
71
+
72
+ desc "validate SUBCOMMAND ...ARGS", "Validate express documents"
73
+ subcommand "validate", Cli::Validate
74
+
75
+ desc "check_svg_quality [PATH]",
76
+ "Check SVG quality and sort by severity (critical files first)"
77
+ option :pattern, type: :string, default: Cli::CheckSvgQuality::DEFAULT_PATTERN,
78
+ desc: "Glob pattern for finding SVG files"
79
+ option :profile, type: :string,
80
+ default: Cli::CheckSvgQuality::DEFAULT_PROFILE,
81
+ desc: "Validation profile to use (metanorma, svg_1_2_rfc, etc.)"
82
+ option :format, type: :string, default: "terminal",
83
+ desc: "Output format: terminal, yaml, json"
84
+ option :output, type: :string, aliases: "-o",
85
+ desc: "Output file path"
86
+ option :min_errors, type: :numeric,
87
+ desc: "Minimum error count threshold"
88
+ option :limit, type: :numeric, default: nil,
89
+ desc: "Maximum number of files to show (default: unlimited)"
90
+ option :sort, type: :string, default: "errors",
91
+ desc: "Sort by: errors (most errors first) or quality (lowest scores first)"
92
+ option :progress, type: :boolean, default: false,
93
+ desc: "Show progress during processing"
94
+ option :summary_only, type: :boolean, default: false,
95
+ desc: "Show only summary"
96
+ def check_svg_quality(path = Cli::CheckSvgQuality::DATA_PATH)
97
+ analyzer = Cli::CheckSvgQuality.new(
98
+ pattern: options[:pattern],
99
+ profile: options[:profile],
100
+ format: options[:format],
101
+ output: options[:output],
102
+ min_errors: options[:min_errors],
103
+ summary_only: options[:summary_only],
104
+ progress: options[:progress],
105
+ limit: options[:limit],
106
+ sort: options[:sort],
107
+ )
108
+ analyzer.run(path)
109
+ end
110
+
111
+ desc "expressir SUBCOMMAND ...ARGS", "Expressir commands"
112
+ subcommand "expressir", Expressir::Cli
113
+
114
+ def self.exit_on_failure?
115
+ true
116
+ end
117
+ end
118
+ end
119
+ end
@@ -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
@@ -18,8 +17,6 @@ module Suma
18
17
  desc: "Create ZIP archive of exported schemas"
19
18
 
20
19
  def export(*files)
21
- require_relative "../schema_exporter"
22
- require_relative "../utils"
23
20
  require "expressir"
24
21
 
25
22
  validate_files(files)