suma 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 165792c4ce4a7a5a23cf0c8fdc649882f68235e65fcc6890a0d11ee5997c063a
4
- data.tar.gz: 05fdff4f378207ba636169838b4d3631fcfd30009f254ab5eed85a191c12ec5a
3
+ metadata.gz: 1136a7e4a745c2e2dda6f8e3a42baca536732794bb5cb92a055831b7eaa9d967
4
+ data.tar.gz: f058690c21e1126054eb135ad09c76f7f95977068c05e195855b4ccafe78ab99
5
5
  SHA512:
6
- metadata.gz: 227dd455539080a5b257f1d5cbb563c5a2fe78856d7eaac4035402060f9415dcbb80ec87928a971a77eccf8585e23c0f7d9e9fd866a8a2cea4471bb098f40ed5
7
- data.tar.gz: 47b7edf861d91dc264acd794d6ffdeb1c952aa83da822da3816e450429f81104088d3af68322245a9c70ecf920bcda1762c916e049f0c16c67208f6035960b8f
6
+ metadata.gz: dafc7f0fc01386c7568858a480d74da950c0c5b48a3f57fc02abe1e2104d68a0d612f1588a40a3046e5344baa3e177a088df6da0c0e47a47af9cf4d7ca79d365
7
+ data.tar.gz: 9fde63ff34104914a415c13280f29e6ed5e0c2e3c40d14d5e4ea8a3d4c8d45c80a6ba4cc12df6a98f687d2f21627b28532e2591a7071bf62fb7b287dcb6ae1a8
@@ -2,15 +2,15 @@
2
2
  # See https://github.com/metanorma/cimas
3
3
  name: rake
4
4
 
5
- permissions:
6
- contents: write
7
-
8
5
  on:
9
6
  push:
10
7
  branches: [ master, main ]
11
8
  tags: [ v* ]
12
9
  pull_request:
13
10
 
11
+ permissions:
12
+ contents: write
13
+
14
14
  jobs:
15
15
  rake:
16
16
  uses: metanorma/ci/.github/workflows/generic-rake.yml@main
@@ -2,11 +2,6 @@
2
2
  # See https://github.com/metanorma/cimas
3
3
  name: release
4
4
 
5
- permissions:
6
- contents: write
7
- packages: write
8
- id-token: write
9
-
10
5
  on:
11
6
  workflow_dispatch:
12
7
  inputs:
@@ -27,3 +22,4 @@ jobs:
27
22
  secrets:
28
23
  rubygems-api-key: ${{ secrets.METANORMA_CI_RUBYGEMS_API_KEY }}
29
24
  pat_token: ${{ secrets.METANORMA_CI_PAT_TOKEN }}
25
+
data/.rubocop.yml CHANGED
@@ -1,19 +1,23 @@
1
+ # Auto-generated by Cimas: Do not edit it manually!
2
+ # See https://github.com/metanorma/cimas
1
3
  inherit_from:
2
4
  - https://raw.githubusercontent.com/riboseinc/oss-guides/main/ci/rubocop.yml
3
5
  - .rubocop_todo.yml
4
6
 
7
+ # Rubocop plugins enabled centrally so every metanorma-org gem picks them up
8
+ # on cimas sync — best practice belongs at the shared-template layer, not
9
+ # per-repo. Per ronaldtse feedback on metanorma/ci#332.
5
10
  plugins:
6
- - rubocop-performance
7
- - rubocop-rake
8
- - rubocop-rspec
11
+ - rubocop-rspec
12
+ - rubocop-performance
13
+ - rubocop-rake
14
+
15
+ # local repo-specific modifications
16
+ # ...
9
17
 
10
18
  AllCops:
11
- TargetRubyVersion: 3.1
12
- NewCops: enable
13
- Exclude:
14
- - 'lib/suma/cli/reformat.rb'
15
- - 'lib/suma/cli/generate_schemas.rb'
16
- - 'lib/suma/cli/validate_ascii.rb'
17
- - 'lib/suma/cli/validate_links.rb'
18
- - 'lib/suma/cli/extract_terms.rb'
19
- - 'vendor/**/*'
19
+ # 3.3 matches the org-wide minimum being pushed via #274 (Raise minimum
20
+ # Ruby version to 3.3 due to EOL of 3.2 on 2026-03-31). Was 3.4 before
21
+ # this commit — 3.4 was above the org's stated minimum and would have
22
+ # applied Rubocop rules that fail-close on gems still targeting 3.3.
23
+ TargetRubyVersion: 3.3
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
- # `rubocop --auto-gen-config`
3
- # on 2026-07-02 16:27:30 UTC using RuboCop version 1.87.0.
2
+ # `rubocop --auto-gen-config --no-exclude-limit`
3
+ # on 2026-07-06 10:29:55 UTC using RuboCop version 1.88.1.
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,81 +16,15 @@ Gemspec/RequiredRubyVersion:
16
16
  Exclude:
17
17
  - 'suma.gemspec'
18
18
 
19
- # Offense count: 35
19
+ # Offense count: 1
20
20
  # This cop supports safe autocorrection (--autocorrect).
21
21
  # Configuration parameters: EnforcedStyle, IndentationWidth.
22
22
  # SupportedStyles: with_first_argument, with_fixed_indentation
23
23
  Layout/ArgumentAlignment:
24
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
25
  - '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
26
 
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
27
+ # Offense count: 1
94
28
  # This cop supports safe autocorrection (--autocorrect).
95
29
  # Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
96
30
  # SupportedHashRocketStyles: key, separator, table
@@ -98,71 +32,67 @@ Layout/FirstArrayElementIndentation:
98
32
  # SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
99
33
  Layout/HashAlignment:
100
34
  Exclude:
101
- - 'lib/suma/schema_compiler.rb'
102
35
  - 'lib/suma/term_extractor.rb'
103
- - 'spec/suma/manifest_traverser_spec.rb'
104
36
 
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
37
+ # Offense count: 174
116
38
  # This cop supports safe autocorrection (--autocorrect).
117
39
  # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
118
40
  # URISchemes: http, https
119
41
  Layout/LineLength:
120
- Enabled: false
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
42
  Exclude:
43
+ - 'Gemfile'
44
+ - 'lib/suma/cli/build.rb'
45
+ - 'lib/suma/cli/check_svg_quality.rb'
46
+ - 'lib/suma/cli/compare.rb'
47
+ - 'lib/suma/cli/core.rb'
48
+ - 'lib/suma/cli/validate.rb'
49
+ - 'lib/suma/cli/validate_links.rb'
50
+ - 'lib/suma/eengine/wrapper.rb'
51
+ - 'lib/suma/express_reformatter.rb'
52
+ - 'lib/suma/jsdai/figure.rb'
53
+ - 'lib/suma/jsdai/figure_image.rb'
54
+ - 'lib/suma/link_validation.rb'
145
55
  - 'lib/suma/link_validator.rb'
56
+ - 'lib/suma/link_validator/step.rb'
57
+ - 'lib/suma/manifest_traverser.rb'
58
+ - 'lib/suma/note_processor.rb'
59
+ - 'lib/suma/processor.rb'
60
+ - 'lib/suma/register_manifest_generator.rb'
146
61
  - 'lib/suma/schema_comparer.rb'
147
- - 'lib/suma/schema_compiler.rb'
148
- - 'lib/suma/schema_manifest_generator.rb'
149
62
  - 'lib/suma/schema_naming.rb'
150
- - 'lib/suma/svg_quality/formatters.rb'
151
- - 'lib/suma/term_extractor.rb'
63
+ - 'lib/suma/staged_collection_builder.rb'
64
+ - 'lib/suma/svg_quality/formatters/terminal_formatter.rb'
65
+ - 'lib/suma/thor_ext.rb'
66
+ - 'spec/suma/cli/build_spec.rb'
67
+ - 'spec/suma/cli/export_spec.rb'
68
+ - 'spec/suma/cli/extract_terms_spec.rb'
69
+ - 'spec/suma/cli/generate_register_spec.rb'
70
+ - 'spec/suma/eengine_converter_spec.rb'
71
+ - 'spec/suma/eengine_spec.rb'
72
+ - 'spec/suma/express_schema_spec.rb'
73
+ - 'spec/suma/jsdai/figure_spec.rb'
152
74
  - 'spec/suma/link_validator_spec.rb'
153
75
  - 'spec/suma/manifest_traverser_spec.rb'
76
+ - 'spec/suma/note_processor_spec.rb'
154
77
  - 'spec/suma/register_manifest_generator_spec.rb'
78
+ - 'spec/suma/schema_category_spec.rb'
155
79
  - 'spec/suma/schema_comparer_integration_spec.rb'
156
- - 'spec/suma/schema_comparer_spec.rb'
157
80
  - 'spec/suma/schema_discovery_spec.rb'
81
+ - 'spec/suma/schema_exporter_spec.rb'
82
+ - 'spec/suma/schema_index_spec.rb'
83
+ - 'spec/suma/schema_naming_spec.rb'
84
+ - 'spec/suma/schema_template_spec.rb'
85
+ - 'spec/suma/staged_collection_builder_spec.rb'
86
+ - 'spec/suma/term_classification_spec.rb'
158
87
  - 'spec/suma/term_extractor_spec.rb'
88
+ - 'spec/suma/urn_spec.rb'
89
+ - 'suma.gemspec'
159
90
 
160
- # Offense count: 4
91
+ # Offense count: 2
161
92
  # Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch.
162
93
  Lint/DuplicateBranch:
163
94
  Exclude:
164
95
  - 'lib/suma/jsdai/figure.rb'
165
- - 'lib/suma/term_extractor.rb'
166
96
 
167
97
  # Offense count: 1
168
98
  Lint/DuplicateMethods:
@@ -182,7 +112,7 @@ Lint/UnusedMethodArgument:
182
112
  Exclude:
183
113
  - 'lib/suma/svg_quality.rb'
184
114
 
185
- # Offense count: 32
115
+ # Offense count: 24
186
116
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
187
117
  Metrics/AbcSize:
188
118
  Exclude:
@@ -202,13 +132,14 @@ Metrics/AbcSize:
202
132
  - 'lib/suma/term_extractor.rb'
203
133
  - 'lib/suma/thor_ext.rb'
204
134
 
205
- # Offense count: 3
206
- # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
135
+ # Offense count: 2
136
+ # Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
207
137
  # AllowedMethods: refine
208
138
  Metrics/BlockLength:
209
- Max: 58
139
+ Exclude:
140
+ - 'lib/suma/term_extractor.rb'
210
141
 
211
- # Offense count: 14
142
+ # Offense count: 8
212
143
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
213
144
  Metrics/CyclomaticComplexity:
214
145
  Exclude:
@@ -217,32 +148,47 @@ Metrics/CyclomaticComplexity:
217
148
  - 'lib/suma/express_schema.rb'
218
149
  - 'lib/suma/jsdai/figure.rb'
219
150
  - 'lib/suma/jsdai/figure_image.rb'
220
- - 'lib/suma/link_validator.rb'
221
151
  - 'lib/suma/schema_comparer.rb'
222
152
  - 'lib/suma/svg_quality/formatters/terminal_formatter.rb'
223
- - 'lib/suma/term_extractor.rb'
224
153
  - 'lib/suma/thor_ext.rb'
225
154
 
226
- # Offense count: 31
227
- # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
155
+ # Offense count: 32
156
+ # Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns.
228
157
  Metrics/MethodLength:
229
- Max: 63
158
+ Exclude:
159
+ - 'spec/**/*'
160
+ - 'lib/suma/cli/check_svg_quality.rb'
161
+ - 'lib/suma/cli/core.rb'
162
+ - 'lib/suma/cli/reformat.rb'
163
+ - 'lib/suma/eengine/wrapper.rb'
164
+ - 'lib/suma/link_validation.rb'
165
+ - 'lib/suma/link_validator.rb'
166
+ - 'lib/suma/note_processor.rb'
167
+ - 'lib/suma/processor.rb'
168
+ - 'lib/suma/register_manifest_generator.rb'
169
+ - 'lib/suma/schema_collection.rb'
170
+ - 'lib/suma/schema_comparer.rb'
171
+ - 'lib/suma/schema_manifest_generator.rb'
172
+ - 'lib/suma/staged_collection_builder.rb'
173
+ - 'lib/suma/svg_quality/formatters/terminal_formatter.rb'
174
+ - 'lib/suma/term_extractor.rb'
230
175
 
231
176
  # Offense count: 3
232
- # Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
177
+ # Configuration parameters: Max, CountKeywordArgs, MaxOptionalParameters.
233
178
  Metrics/ParameterLists:
234
- Max: 9
179
+ Exclude:
180
+ - 'lib/suma/cli/check_svg_quality.rb'
181
+ - 'lib/suma/link_validator.rb'
182
+ - 'lib/suma/register_manifest_generator.rb'
235
183
 
236
- # Offense count: 8
184
+ # Offense count: 4
237
185
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
238
186
  Metrics/PerceivedComplexity:
239
187
  Exclude:
240
188
  - 'lib/suma/eengine/wrapper.rb'
241
189
  - 'lib/suma/jsdai/figure_image.rb'
242
- - 'lib/suma/link_validator.rb'
243
190
  - 'lib/suma/schema_comparer.rb'
244
191
  - 'lib/suma/svg_quality/formatters/terminal_formatter.rb'
245
- - 'lib/suma/term_extractor.rb'
246
192
 
247
193
  # Offense count: 1
248
194
  # Configuration parameters: Mode, AllowedMethods, AllowedPatterns, AllowBangMethods, WaywardPredicates.
@@ -252,17 +198,6 @@ Naming/PredicateMethod:
252
198
  Exclude:
253
199
  - 'lib/suma/eengine/wrapper.rb'
254
200
 
255
- # Offense count: 1
256
- # Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros, UseSorbetSigs.
257
- # NamePrefix: is_, has_, have_, does_
258
- # ForbiddenPrefixes: is_, has_, have_, does_
259
- # AllowedMethods: is_a?
260
- # MethodDefinitionMacros: define_method, define_singleton_method
261
- Naming/PredicatePrefix:
262
- Exclude:
263
- - 'spec/**/*'
264
- - 'lib/suma/term_extractor.rb'
265
-
266
201
  # Offense count: 2
267
202
  # Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns.
268
203
  # SupportedStyles: snake_case, normalcase, non_integer
@@ -286,10 +221,41 @@ RSpec/ContextWording:
286
221
  Exclude:
287
222
  - 'spec/suma/cli/export_spec.rb'
288
223
 
289
- # Offense count: 111
290
- # Configuration parameters: CountAsOne.
224
+ # Offense count: 136
225
+ # Configuration parameters: Max, CountAsOne.
291
226
  RSpec/ExampleLength:
292
- Max: 60
227
+ Exclude:
228
+ - 'spec/suma/cli/export_spec.rb'
229
+ - 'spec/suma/cli/extract_terms_spec.rb'
230
+ - 'spec/suma/cli/generate_register_spec.rb'
231
+ - 'spec/suma/cli/generate_schemas_spec.rb'
232
+ - 'spec/suma/cli/reformat_spec.rb'
233
+ - 'spec/suma/cli_spec.rb'
234
+ - 'spec/suma/collection_config_spec.rb'
235
+ - 'spec/suma/collection_manifest_spec.rb'
236
+ - 'spec/suma/eengine_converter_spec.rb'
237
+ - 'spec/suma/express_reformatter_spec.rb'
238
+ - 'spec/suma/express_schema_spec.rb'
239
+ - 'spec/suma/jsdai/figure_spec.rb'
240
+ - 'spec/suma/link_validation_spec.rb'
241
+ - 'spec/suma/link_validator/step_spec.rb'
242
+ - 'spec/suma/link_validator_spec.rb'
243
+ - 'spec/suma/manifest_traverser_spec.rb'
244
+ - 'spec/suma/note_processor_spec.rb'
245
+ - 'spec/suma/processor_spec.rb'
246
+ - 'spec/suma/register_manifest_generator_spec.rb'
247
+ - 'spec/suma/schema_category_spec.rb'
248
+ - 'spec/suma/schema_comparer_integration_spec.rb'
249
+ - 'spec/suma/schema_comparer_spec.rb'
250
+ - 'spec/suma/schema_compiler_spec.rb'
251
+ - 'spec/suma/schema_discovery_spec.rb'
252
+ - 'spec/suma/schema_exporter_spec.rb'
253
+ - 'spec/suma/schema_template_spec.rb'
254
+ - 'spec/suma/site_config/config_spec.rb'
255
+ - 'spec/suma/svg_quality/scanner_spec.rb'
256
+ - 'spec/suma/term_classification_spec.rb'
257
+ - 'spec/suma/term_extractor_spec.rb'
258
+ - 'spec/suma/urn_spec.rb'
293
259
 
294
260
  # Offense count: 4
295
261
  # Configuration parameters: Max, AllowedIdentifiers, AllowedPatterns.
@@ -311,20 +277,53 @@ RSpec/IteratedExpectation:
311
277
  - 'spec/suma/schema_comparer_integration_spec.rb'
312
278
 
313
279
  # Offense count: 1
314
- # Configuration parameters: EnforcedStyle.
280
+ # Configuration parameters: .
315
281
  # SupportedStyles: have_received, receive
316
282
  RSpec/MessageSpies:
317
- Exclude:
318
- - 'spec/suma/schema_comparer_integration_spec.rb'
283
+ EnforcedStyle: receive
319
284
 
320
- # Offense count: 87
285
+ # Offense count: 117
286
+ # Configuration parameters: Max.
321
287
  RSpec/MultipleExpectations:
322
- Max: 21
288
+ Exclude:
289
+ - 'spec/suma/cli/build_spec.rb'
290
+ - 'spec/suma/cli/export_spec.rb'
291
+ - 'spec/suma/cli/expressir_spec.rb'
292
+ - 'spec/suma/cli/extract_terms_spec.rb'
293
+ - 'spec/suma/cli/reformat_spec.rb'
294
+ - 'spec/suma/cli_spec.rb'
295
+ - 'spec/suma/collection_config_spec.rb'
296
+ - 'spec/suma/collection_manifest_spec.rb'
297
+ - 'spec/suma/eengine_converter_spec.rb'
298
+ - 'spec/suma/eengine_spec.rb'
299
+ - 'spec/suma/express_reformatter_spec.rb'
300
+ - 'spec/suma/express_schema_spec.rb'
301
+ - 'spec/suma/jsdai/figure_spec.rb'
302
+ - 'spec/suma/link_validation_spec.rb'
303
+ - 'spec/suma/link_validator/step_spec.rb'
304
+ - 'spec/suma/link_validator_spec.rb'
305
+ - 'spec/suma/manifest_traverser_spec.rb'
306
+ - 'spec/suma/note_processor_spec.rb'
307
+ - 'spec/suma/processor_spec.rb'
308
+ - 'spec/suma/register_manifest_generator_spec.rb'
309
+ - 'spec/suma/schema_category_spec.rb'
310
+ - 'spec/suma/schema_comparer_integration_spec.rb'
311
+ - 'spec/suma/schema_compiler_spec.rb'
312
+ - 'spec/suma/schema_discovery_spec.rb'
313
+ - 'spec/suma/schema_exporter_spec.rb'
314
+ - 'spec/suma/schema_index_spec.rb'
315
+ - 'spec/suma/schema_template_spec.rb'
316
+ - 'spec/suma/site_config/config_spec.rb'
317
+ - 'spec/suma/staged_collection_builder_spec.rb'
318
+ - 'spec/suma/svg_quality/scanner_spec.rb'
319
+ - 'spec/suma/term_classification_spec.rb'
320
+ - 'spec/suma/term_extractor_spec.rb'
323
321
 
324
322
  # Offense count: 3
325
- # Configuration parameters: AllowedGroups.
323
+ # Configuration parameters: Max, AllowedGroups.
326
324
  RSpec/NestedGroups:
327
- Max: 4
325
+ Exclude:
326
+ - 'spec/suma/express_schema_spec.rb'
328
327
 
329
328
  # Offense count: 1
330
329
  # Configuration parameters: CustomTransform, IgnoreMethods, IgnoreMetadata, InflectorPath, EnforcedInflector.
@@ -338,31 +337,3 @@ RSpec/SpecFilePathFormat:
338
337
  RSpec/StubbedMock:
339
338
  Exclude:
340
339
  - 'spec/suma/schema_comparer_integration_spec.rb'
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
-
363
- # Offense count: 1
364
- # Configuration parameters: AllowedMethods.
365
- # AllowedMethods: respond_to_missing?
366
- Style/OptionalBooleanParameter:
367
- Exclude:
368
- - 'lib/suma/cli/check_svg_quality.rb'
data/Gemfile CHANGED
@@ -6,7 +6,11 @@ source "https://rubygems.org"
6
6
  gemspec
7
7
 
8
8
  gem "canon"
9
- # gem "metanorma", github: "metanorma/metanorma", branch: "main"
9
+ # Staged build (suma#94) needs the preserve_unresolved: / artifact_store_dir: /
10
+ # reinflate: render options from metanorma#578 (metanorma 2.5.0). Point at the
11
+ # feature branch until it is released; drop this once 2.5.0 is on rubygems.
12
+ gem "metanorma", github: "metanorma/metanorma",
13
+ branch: "feature/collection-incremental-resumable"
10
14
  # gem "metanorma-plugin-lutaml", github: "metanorma/metanorma-plugin-lutaml", branch: "main"
11
15
  # gem "metanorma-standoc", github: "metanorma/metanorma-standoc", branch: "main"
12
16
  gem "nokogiri"
@@ -12,6 +12,10 @@ module Suma
12
12
  desc: "Compile or skip compile of collection"
13
13
  option :schemas_all_path, type: :string, aliases: "-s",
14
14
  desc: "Generate file that contains all schemas in the collection."
15
+ option :staged, type: :boolean, default: false,
16
+ desc: "Memory-bounded staged build: compile each member in " \
17
+ "its own process (sequential) and reinflate. For large " \
18
+ "collections that OOM a single-process build (suma#94)."
15
19
 
16
20
  def build(metanorma_site_manifest)
17
21
  unless File.exist?(metanorma_site_manifest)
@@ -34,6 +38,7 @@ module Suma
34
38
  schemas_all_path: schemas_all_path,
35
39
  compile: options[:compile],
36
40
  output_directory: "_site",
41
+ staged: options[:staged],
37
42
  ).run
38
43
  end
39
44
 
@@ -4,15 +4,21 @@ require "metanorma"
4
4
 
5
5
  module Suma
6
6
  class Processor
7
+ # Emitted collection manifest that both the normal and staged builds render.
8
+ COLLECTION_OUTPUT_PATH = "collection-output.yaml"
9
+
7
10
  attr_reader :metanorma_yaml_path, :output_directory, :schemas_all_path,
8
11
  :compile_flag
9
12
 
10
13
  def initialize(metanorma_yaml_path:, schemas_all_path:, compile: true,
11
- output_directory: "_site")
14
+ output_directory: "_site", staged: false)
12
15
  @metanorma_yaml_path = metanorma_yaml_path
13
16
  @schemas_all_path = schemas_all_path
14
17
  @compile_flag = compile
15
18
  @output_directory = output_directory
19
+ # Opt-in memory-bounded staged build (metanorma/suma#94); the default
20
+ # single-process build below is unchanged when false.
21
+ @staged = staged
16
22
  end
17
23
 
18
24
  def run
@@ -64,11 +70,21 @@ module Suma
64
70
  collection_config, output_directory
65
71
  )
66
72
 
67
- metanorma_collection.render(collection_opts)
73
+ if @staged
74
+ # build_collection has written the emitted manifest; stage each member in
75
+ # its own process, then reinflate. Bounds peak memory to a single member.
76
+ StagedCollectionBuilder.new(
77
+ collection_config_path: COLLECTION_OUTPUT_PATH,
78
+ output_directory: output_directory,
79
+ coverpage: collection_opts[:coverpage],
80
+ ).build
81
+ else
82
+ metanorma_collection.render(collection_opts)
83
+ end
68
84
  end
69
85
 
70
86
  def build_collection(collection_config, output_directory)
71
- new_collection_config_path = "collection-output.yaml"
87
+ new_collection_config_path = COLLECTION_OUTPUT_PATH
72
88
  ManifestTraverser.new(collection_config.manifest).remove_schemas_only_sources
73
89
  collection_config.to_file(new_collection_config_path)
74
90
 
@@ -0,0 +1,188 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "metanorma"
4
+ require "yaml"
5
+ require "fileutils"
6
+
7
+ module Suma
8
+ # Memory-bounded, resumable staged collection build (metanorma/suma#94).
9
+ #
10
+ # A normal collection build renders every member document in one OS process, so
11
+ # peak memory accumulates across the whole collection and a large collection
12
+ # (e.g. the STEP SRL) OOMs. This builder instead:
13
+ #
14
+ # 1. compiles each member in its OWN fresh OS process, preserving that
15
+ # member's unresolved cross-document references as stubs and writing the
16
+ # stub-bearing Semantic XML + anchors to a durable content-addressed store
17
+ # (the metanorma engine's +preserve_unresolved:+ / +artifact_store_dir:+
18
+ # render options, metanorma/metanorma#576);
19
+ # 2. runs those per-member processes SEQUENTIALLY (never in parallel --
20
+ # parallelism reintroduces the cross-linking / sectionsplit races that are
21
+ # deliberately avoided); each process exits and the OS reclaims its memory
22
+ # before the next, so peak memory is bounded by a single member; then
23
+ # 3. REINFLATES: a final pass assembles a manifest of the stored stubs and
24
+ # resolves them into real cross-document links (+reinflate:+), producing
25
+ # the same output an all-present build would.
26
+ #
27
+ # The empirical case (metanorma/metanorma#576): on the real SRL a single-process
28
+ # build peaks ~4.1 GB and OOMs; each member compiled in isolation peaks ~1 GB,
29
+ # so process isolation is a ~4x peak reduction that converts the OOM into a
30
+ # bounded footprint.
31
+ #
32
+ # This is opt-in; +Suma::Processor+ uses the normal single-process build unless
33
+ # staging is requested.
34
+ class StagedCollectionBuilder
35
+ STORE_DIRNAME = ".metanorma-collection-cache"
36
+
37
+ # +collection_config_path+ is the emitted collection manifest (the same
38
+ # +collection-output.yaml+ the normal build renders). Member filerefs are
39
+ # relative to its directory, so all per-member manifests are written there.
40
+ def initialize(collection_config_path:, output_directory:, coverpage: nil,
41
+ store_dir: nil, formats: %i[xml html])
42
+ @config_path = collection_config_path
43
+ @config_dir = File.dirname(File.expand_path(collection_config_path))
44
+ @output_directory = output_directory
45
+ @coverpage = coverpage
46
+ @store_dir = store_dir || File.join(output_directory, STORE_DIRNAME)
47
+ @formats = formats
48
+ end
49
+
50
+ def build
51
+ FileUtils.mkdir_p(@output_directory)
52
+ FileUtils.mkdir_p(@store_dir)
53
+ members = collection_members
54
+ Utils.log "[staged] #{members.size} members; one process per member, " \
55
+ "sequential; store: #{@store_dir}"
56
+ members.each_with_index { |member, i| stage_member(member, i) }
57
+ reinflate(members)
58
+ end
59
+
60
+ private
61
+
62
+ def manifest
63
+ @manifest ||= YAML.load_file(@config_path)
64
+ end
65
+
66
+ # Every document member of the manifest tree, in order: any node carrying a
67
+ # file reference (+fileref+ or legacy +file+) that is not an attachment.
68
+ def collection_members
69
+ members = []
70
+ walk_members(manifest["manifest"]) { |member| members << member }
71
+ members
72
+ end
73
+
74
+ def walk_members(node, &block)
75
+ case node
76
+ when Array then node.each { |child| walk_members(child, &block) }
77
+ when Hash then walk_member_hash(node, &block)
78
+ end
79
+ end
80
+
81
+ def walk_member_hash(node, &block)
82
+ ref = node["fileref"] || node["file"]
83
+ ref && !truthy?(node["attachment"]) and
84
+ yield({ "fileref" => ref, "identifier" => node["identifier"],
85
+ "sectionsplit" => node["sectionsplit"] }.compact)
86
+ node.each_value { |value| walk_members(value, &block) }
87
+ end
88
+
89
+ # Stage one member in its own process: a single-member manifest rendered with
90
+ # preserve + store. Written beside the collection config so relative filerefs
91
+ # resolve; removed afterwards.
92
+ def stage_member(member, idx)
93
+ one_path = File.join(@config_dir, "._suma_staged_#{idx}.yml")
94
+ File.write(one_path, single_member_manifest(member).to_yaml)
95
+ out = File.join(@output_directory, "._staged_out_#{idx}")
96
+ run_render(
97
+ manifest_path: one_path,
98
+ opts: { format: [:xml], output_folder: out,
99
+ preserve_unresolved: true, artifact_store_dir: @store_dir,
100
+ compile: { install_fonts: false } },
101
+ )
102
+ ensure
103
+ FileUtils.rm_f(one_path)
104
+ FileUtils.rm_rf(File.join(@output_directory, "._staged_out_#{idx}"))
105
+ end
106
+
107
+ # Assemble a manifest of the stored stubs and reinflate them into the site.
108
+ def reinflate(members)
109
+ reinf_dir = File.join(@output_directory, "_staged_reinflate")
110
+ FileUtils.mkdir_p(reinf_dir)
111
+ docrefs = stored_docrefs(members, reinf_dir)
112
+ reinf_path = File.join(reinf_dir, "reinflate.yml")
113
+ File.write(reinf_path,
114
+ base_manifest.merge("manifest" => collection_manifest(docrefs)).to_yaml)
115
+ Utils.log "[staged] reinflating #{docrefs.size} stored members -> " \
116
+ "#{@output_directory}"
117
+ run_render(
118
+ manifest_path: reinf_path,
119
+ opts: { format: @formats, output_folder: @output_directory,
120
+ reinflate: true, coverpage: @coverpage,
121
+ compile: { install_fonts: false } }.compact,
122
+ )
123
+ end
124
+
125
+ # Copy each member's stored stub into +dir+ and return docref entries pointing
126
+ # at the copies, keyed by real docid (as the store keys them).
127
+ def stored_docrefs(members, dir)
128
+ members.map.with_index do |member, i|
129
+ stored = stored_semantic(member["identifier"]) or
130
+ raise "[staged] no stored artefact for #{member['identifier'].inspect}"
131
+ name = "member_#{i}.xml"
132
+ FileUtils.cp(stored, File.join(dir, name))
133
+ dr = { "fileref" => name, "identifier" => member["identifier"] }
134
+ dr["sectionsplit"] = true if truthy?(member["sectionsplit"])
135
+ dr
136
+ end
137
+ end
138
+
139
+ # A minimal single-member manifest reusing the collection's directives and
140
+ # bibdata, so the isolated render carries the right collection identity.
141
+ def single_member_manifest(member)
142
+ base_manifest.merge("manifest" => collection_manifest([member]))
143
+ end
144
+
145
+ def collection_manifest(docrefs)
146
+ { "level" => "collection", "title" => "Collection",
147
+ "manifest" => [{ "level" => "subcollection", "title" => "Members",
148
+ "docref" => docrefs }] }
149
+ end
150
+
151
+ def base_manifest
152
+ { "directives" => manifest["directives"] || ["documents-inline"],
153
+ "bibdata" => manifest["bibdata"] }.compact
154
+ end
155
+
156
+ def stored_semantic(identifier)
157
+ Dir[File.join(@store_dir, "#{slug(identifier)}.*.semantic.xml")]
158
+ .max_by { |f| File.mtime(f) }
159
+ end
160
+
161
+ # Mirrors the store's filename slug (metanorma ArtifactStore#slug).
162
+ def slug(identifier)
163
+ identifier.to_s.gsub(/[^A-Za-z0-9._-]+/, "-")
164
+ .gsub(/-{2,}/, "-").gsub(/\A-|-\z/, "")
165
+ end
166
+
167
+ # Render a manifest in a FRESH child process so its memory is reclaimed on
168
+ # exit. Under +bundle exec+, the child inherits the bundle. Raises on failure.
169
+ def run_render(manifest_path:, opts:)
170
+ script = <<~RUBY
171
+ require "metanorma"
172
+ opts = Marshal.load(STDIN.read)
173
+ Metanorma::Collection.parse(#{manifest_path.inspect}).render(opts)
174
+ RUBY
175
+ IO.popen([RbConfig.ruby, "-e", script], "wb") do |io|
176
+ io.write(Marshal.dump(opts))
177
+ io.close_write
178
+ end
179
+ return if $?.success?
180
+
181
+ raise "[staged] render subprocess failed for #{manifest_path}"
182
+ end
183
+
184
+ def truthy?(val)
185
+ [true, "true"].include?(val)
186
+ end
187
+ end
188
+ end
data/lib/suma/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Suma
4
- VERSION = "0.5.0"
4
+ VERSION = "0.5.1"
5
5
  end
data/lib/suma.rb CHANGED
@@ -29,6 +29,7 @@ module Suma
29
29
  autoload :SchemaNaming, "suma/schema_naming"
30
30
  autoload :SchemaTemplate, "suma/schema_template"
31
31
  autoload :SiteConfig, "suma/site_config"
32
+ autoload :StagedCollectionBuilder, "suma/staged_collection_builder"
32
33
  autoload :SvgQuality, "suma/svg_quality"
33
34
  autoload :TermClassification, "suma/term_classification"
34
35
  autoload :TermExtractor, "suma/term_extractor"
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: suma
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2026-07-05 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: expressir
@@ -232,6 +231,7 @@ files:
232
231
  - lib/suma/schema_template/document.rb
233
232
  - lib/suma/schema_template/plain.rb
234
233
  - lib/suma/site_config.rb
234
+ - lib/suma/staged_collection_builder.rb
235
235
  - lib/suma/svg_quality.rb
236
236
  - lib/suma/svg_quality/batch_report.rb
237
237
  - lib/suma/svg_quality/formatters.rb
@@ -253,7 +253,6 @@ licenses:
253
253
  - BSD-2-Clause
254
254
  metadata:
255
255
  rubygems_mfa_required: 'true'
256
- post_install_message:
257
256
  rdoc_options: []
258
257
  require_paths:
259
258
  - lib
@@ -268,8 +267,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
268
267
  - !ruby/object:Gem::Version
269
268
  version: '0'
270
269
  requirements: []
271
- rubygems_version: 3.5.22
272
- signing_key:
270
+ rubygems_version: 4.0.10
273
271
  specification_version: 4
274
272
  summary: Utility for SUMA (STEP Unified Model-Based Standards Architecture)
275
273
  test_files: []