metanorma-document 0.2.1 → 0.2.2

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: a15c5f341f9fbc477322f57c757f26896b1ba2bd3e80a89815ba6942a44c5c6c
4
- data.tar.gz: 95f0e2d121bc523f38600fe0d5e3e058f7c6b8212b4e5e8b4ab4654d06b10a83
3
+ metadata.gz: d03f7b4977f3220a59c871eb1e62e2f00042fd2b56164a41ed6361b18ddb1fd2
4
+ data.tar.gz: 274a96e49ab7923362edbcf4733214f7fdca6aa75699623da8c065c8958d5cb3
5
5
  SHA512:
6
- metadata.gz: 01eee74753ce15ebf8bd68a3523130d7231eee75c42c2bb3551b67b30fd79e022c8e12858a1aae6d6fc03baf6bbac511b5b5e62db0b054487ee5c1bb62650c2c
7
- data.tar.gz: 499dc86b2c426e22f107443b8939eead6e2861ab985b9dd427c54a2572531f11ab9c09114b7aa44e9c2fd0dd16eb5dfd36366dbc4f8b2c7c2c713994d6e53aa2
6
+ metadata.gz: 06a95eb083a619c0eb43c0acd394e171fa812d2e9eb9b592fa0f551568f6eae25f5ec824e787354d8e1c2bb95ad10aedaa10615e0bcb31b2a022bde8f212025a
7
+ data.tar.gz: da8eb0c5a86def7f9cd05e173957404a1ca047270d4ee12043cf696687e9ae9a38b01c91fbec7097af074ed3df697e75bf46d934d9a22d1ed0b74a957ee29b1d
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-04-22 12:28:09 UTC using RuboCop version 1.86.1.
3
+ # on 2026-05-06 04:06:53 UTC using RuboCop version 1.86.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
@@ -13,114 +13,220 @@ Gemspec/RequiredRubyVersion:
13
13
 
14
14
  # Offense count: 1
15
15
  # This cop supports safe autocorrection (--autocorrect).
16
- Layout/ClosingParenthesisIndentation:
16
+ # Configuration parameters: EnforcedStyle, IndentationWidth.
17
+ # SupportedStyles: with_first_argument, with_fixed_indentation
18
+ Layout/ArgumentAlignment:
17
19
  Exclude:
18
- - 'lib/metanorma/html/renderer.rb'
20
+ - 'lib/metanorma/html/component/index_term_collector.rb'
19
21
 
20
- # Offense count: 1
22
+ # Offense count: 5
21
23
  # This cop supports safe autocorrection (--autocorrect).
22
- # Configuration parameters: EnforcedStyle, IndentationWidth.
23
- # SupportedStyles: consistent, consistent_relative_to_receiver, special_for_inner_method_call, special_for_inner_method_call_in_parentheses
24
- Layout/FirstArgumentIndentation:
24
+ Layout/EmptyLineAfterGuardClause:
25
25
  Exclude:
26
- - 'lib/metanorma/html/renderer.rb'
26
+ - 'lib/metanorma/html/generator.rb'
27
+ - 'lib/metanorma/iso_document/metadata/iso_localized_title.rb'
27
28
 
28
- # Offense count: 580
29
+ # Offense count: 11
30
+ # This cop supports safe autocorrection (--autocorrect).
31
+ # Configuration parameters: EnforcedStyle.
32
+ # SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines, beginning_only, ending_only
33
+ Layout/EmptyLinesAroundClassBody:
34
+ Exclude:
35
+ - 'lib/metanorma/html/bipm_renderer.rb'
36
+ - 'lib/metanorma/html/cc_renderer.rb'
37
+ - 'lib/metanorma/html/iec_renderer.rb'
38
+ - 'lib/metanorma/html/ieee_renderer.rb'
39
+ - 'lib/metanorma/html/ietf_renderer.rb'
40
+ - 'lib/metanorma/html/iho_renderer.rb'
41
+ - 'lib/metanorma/html/itu_renderer.rb'
42
+ - 'lib/metanorma/html/ogc_renderer.rb'
43
+ - 'lib/metanorma/html/oiml_renderer.rb'
44
+ - 'lib/metanorma/html/pdfa_renderer.rb'
45
+ - 'lib/metanorma/html/ribose_renderer.rb'
46
+
47
+ # Offense count: 5
48
+ # This cop supports safe autocorrection (--autocorrect).
49
+ # Configuration parameters: AllowForAlignment, AllowBeforeTrailingComments, ForceEqualSignAlignment.
50
+ Layout/ExtraSpacing:
51
+ Exclude:
52
+ - 'lib/metanorma/html/bipm_renderer.rb'
53
+ - 'lib/metanorma/html/generator.rb'
54
+ - 'lib/metanorma/html/iho_renderer.rb'
55
+ - 'lib/metanorma/html/theme.rb'
56
+
57
+ # Offense count: 718
29
58
  # This cop supports safe autocorrection (--autocorrect).
30
59
  # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
31
60
  # URISchemes: http, https
32
61
  Layout/LineLength:
33
62
  Enabled: false
34
63
 
35
- # Offense count: 1
64
+ # Offense count: 3
36
65
  # This cop supports safe autocorrection (--autocorrect).
37
- # Configuration parameters: EnforcedStyle.
38
- # SupportedStyles: symmetrical, new_line, same_line
39
- Layout/MultilineMethodCallBraceLayout:
66
+ # Configuration parameters: AllowForAlignment, EnforcedStyleForExponentOperator, EnforcedStyleForRationalLiterals.
67
+ # SupportedStylesForExponentOperator: space, no_space
68
+ # SupportedStylesForRationalLiterals: space, no_space
69
+ Layout/SpaceAroundOperators:
40
70
  Exclude:
41
- - 'lib/metanorma/html/renderer.rb'
71
+ - 'lib/metanorma/html/bipm_renderer.rb'
72
+ - 'lib/metanorma/html/iho_renderer.rb'
73
+ - 'lib/metanorma/html/theme.rb'
42
74
 
43
- # Offense count: 2
75
+ # Offense count: 1
76
+ # Configuration parameters: AllowedMethods.
77
+ # AllowedMethods: enums
78
+ Lint/ConstantDefinitionInBlock:
79
+ Exclude:
80
+ - 'spec/metanorma/html/renderer/class_ownership_spec.rb'
81
+
82
+ # Offense count: 4
44
83
  # Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch.
45
84
  Lint/DuplicateBranch:
46
85
  Exclude:
47
- - 'lib/metanorma/html/index_generator.rb'
48
- - 'lib/metanorma/html/renderer.rb'
86
+ - 'lib/metanorma/html/base_renderer.rb'
49
87
 
50
- # Offense count: 2
88
+ # Offense count: 3
51
89
  # Configuration parameters: AllowComments, AllowEmptyLambdas.
52
90
  Lint/EmptyBlock:
53
91
  Exclude:
92
+ - 'lib/metanorma/html/drops/formula_drop.rb'
54
93
  - 'spec/metanorma/iso_document/metadata/title_roundtrip_spec.rb'
55
94
 
95
+ # Offense count: 2
96
+ # Configuration parameters: AllowedParentClasses.
97
+ Lint/MissingSuper:
98
+ Exclude:
99
+ - 'lib/metanorma/html/drops/block_element_drop.rb'
100
+ - 'lib/metanorma/html/drops/footnote_drop.rb'
101
+
56
102
  # Offense count: 1
57
- # Configuration parameters: AllowedPatterns.
58
- # AllowedPatterns: (?-mix:(exactly|at_least|at_most)\(\d+\)\.times)
59
- Lint/UnreachableLoop:
103
+ Lint/StructNewOverride:
104
+ Exclude:
105
+ - 'lib/metanorma/html/component/index_term_collector.rb'
106
+
107
+ # Offense count: 2
108
+ # This cop supports safe autocorrection (--autocorrect).
109
+ # Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods, NotImplementedExceptions.
110
+ # NotImplementedExceptions: NotImplementedError
111
+ Lint/UnusedMethodArgument:
60
112
  Exclude:
61
- - 'lib/metanorma/html/renderer.rb'
113
+ - 'lib/metanorma/html/component/index_section.rb'
114
+ - 'lib/metanorma/html/generator.rb'
62
115
 
63
116
  # Offense count: 1
64
117
  Lint/UselessConstantScoping:
65
118
  Exclude:
66
- - 'lib/metanorma/html/renderer.rb'
119
+ - 'lib/metanorma/html/base_renderer.rb'
67
120
 
68
- # Offense count: 26
121
+ # Offense count: 85
69
122
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
70
123
  Metrics/AbcSize:
71
- Exclude:
72
- - 'lib/metanorma/document/components/lists/list_item.rb'
73
- - 'lib/metanorma/html/index_generator.rb'
74
- - 'lib/metanorma/html/renderer.rb'
75
- - 'lib/metanorma/html/transformer.rb'
124
+ Enabled: false
76
125
 
77
- # Offense count: 11
126
+ # Offense count: 22
78
127
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
79
128
  # AllowedMethods: refine
80
129
  Metrics/BlockLength:
81
- Max: 139
130
+ Max: 66
82
131
 
83
132
  # Offense count: 2
84
133
  # Configuration parameters: CountBlocks, CountModifierForms.
85
134
  Metrics/BlockNesting:
86
135
  Max: 4
87
136
 
88
- # Offense count: 31
137
+ # Offense count: 64
89
138
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
90
139
  Metrics/CyclomaticComplexity:
91
140
  Exclude:
92
141
  - 'lib/metanorma/document/components/lists/list_item.rb'
93
- - 'lib/metanorma/html/index_generator.rb'
94
- - 'lib/metanorma/html/renderer.rb'
95
- - 'lib/metanorma/html/transformer.rb'
142
+ - 'lib/metanorma/html/base_renderer.rb'
143
+ - 'lib/metanorma/html/bipm_renderer.rb'
144
+ - 'lib/metanorma/html/component/index_term_collector.rb'
145
+ - 'lib/metanorma/html/drops/example_drop.rb'
146
+ - 'lib/metanorma/html/drops/figure_drop.rb'
147
+ - 'lib/metanorma/html/drops/formula_drop.rb'
148
+ - 'lib/metanorma/html/drops/note_drop.rb'
149
+ - 'lib/metanorma/html/generator.rb'
150
+ - 'lib/metanorma/html/iso_renderer.rb'
151
+ - 'lib/metanorma/html/ogc_renderer.rb'
152
+ - 'lib/metanorma/html/standard_renderer.rb'
153
+ - 'lib/metanorma/html/theme.rb'
96
154
  - 'lib/metanorma/iso_document/metadata/iso_localized_title.rb'
97
155
 
98
- # Offense count: 33
156
+ # Offense count: 89
99
157
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
100
158
  Metrics/MethodLength:
101
- Max: 141
159
+ Max: 104
102
160
 
103
- # Offense count: 24
161
+ # Offense count: 1
162
+ # Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
163
+ Metrics/ParameterLists:
164
+ Max: 7
165
+
166
+ # Offense count: 55
104
167
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
105
168
  Metrics/PerceivedComplexity:
106
169
  Exclude:
107
170
  - 'lib/metanorma/document/components/lists/list_item.rb'
108
- - 'lib/metanorma/html/index_generator.rb'
109
- - 'lib/metanorma/html/renderer.rb'
110
- - 'lib/metanorma/html/transformer.rb'
171
+ - 'lib/metanorma/html/base_renderer.rb'
172
+ - 'lib/metanorma/html/bipm_renderer.rb'
173
+ - 'lib/metanorma/html/component/index_term_collector.rb'
174
+ - 'lib/metanorma/html/drops/example_drop.rb'
175
+ - 'lib/metanorma/html/drops/figure_drop.rb'
176
+ - 'lib/metanorma/html/drops/formula_drop.rb'
177
+ - 'lib/metanorma/html/drops/note_drop.rb'
178
+ - 'lib/metanorma/html/generator.rb'
179
+ - 'lib/metanorma/html/iso_renderer.rb'
180
+ - 'lib/metanorma/html/ogc_renderer.rb'
181
+ - 'lib/metanorma/html/standard_renderer.rb'
182
+ - 'lib/metanorma/html/theme.rb'
183
+ - 'lib/metanorma/iso_document/metadata/iso_localized_title.rb'
111
184
 
112
- # Offense count: 1
185
+ # Offense count: 2
186
+ # This cop supports safe autocorrection (--autocorrect).
187
+ # Configuration parameters: EnforcedStyle, BlockForwardingName.
188
+ # SupportedStyles: anonymous, explicit
189
+ Naming/BlockForwarding:
190
+ Exclude:
191
+ - 'lib/metanorma/html/component/footnote_collector.rb'
192
+
193
+ # Offense count: 22
113
194
  # Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
114
195
  # AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to
115
196
  Naming/MethodParameterName:
116
197
  Exclude:
117
- - 'lib/metanorma/html/renderer.rb'
198
+ - 'lib/metanorma/html/base_renderer.rb'
199
+ - 'lib/metanorma/html/component/footnote_collector.rb'
200
+ - 'lib/metanorma/html/drops/sourcecode_drop.rb'
201
+ - 'lib/metanorma/html/iso_renderer.rb'
202
+ - 'spec/metanorma/html/renderer/footnote_collector_spec.rb'
203
+
204
+ # Offense count: 2
205
+ # Configuration parameters: Mode, AllowedMethods, AllowedPatterns, AllowBangMethods, WaywardPredicates.
206
+ # AllowedMethods: call
207
+ # WaywardPredicates: infinite?, nonzero?
208
+ Naming/PredicateMethod:
209
+ Exclude:
210
+ - 'lib/metanorma/html/base_renderer.rb'
118
211
 
119
- # Offense count: 10
212
+ # Offense count: 1
213
+ # Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros, UseSorbetSigs.
214
+ # NamePrefix: is_, has_, have_, does_
215
+ # ForbiddenPrefixes: is_, has_, have_, does_
216
+ # AllowedMethods: is_a?
217
+ # MethodDefinitionMacros: define_method, define_singleton_method
218
+ Naming/PredicatePrefix:
219
+ Exclude:
220
+ - 'lib/metanorma/html/standard_renderer.rb'
221
+
222
+ # Offense count: 13
120
223
  # Configuration parameters: IgnoredMetadata.
121
224
  RSpec/DescribeClass:
122
225
  Exclude:
123
226
  - 'spec/metanorma/document_spec.rb'
227
+ - 'spec/metanorma/html/renderer/class_ownership_spec.rb'
228
+ - 'spec/metanorma/html/renderer/dead_code_removal_spec.rb'
229
+ - 'spec/metanorma/html/renderer/section_rendering_spec.rb'
124
230
  - 'spec/metanorma/iso_document/metadata/title_roundtrip_spec.rb'
125
231
  - 'spec/metanorma/iso_document/roundtrip/bipm_roundtrip_spec.rb'
126
232
  - 'spec/metanorma/iso_document/roundtrip/cc_roundtrip_spec.rb'
@@ -131,36 +237,108 @@ RSpec/DescribeClass:
131
237
  - 'spec/metanorma/iso_document/roundtrip/oiml_collection_roundtrip_spec.rb'
132
238
  - 'spec/metanorma/iso_document/roundtrip/oiml_roundtrip_spec.rb'
133
239
 
134
- # Offense count: 1
240
+ # Offense count: 4
135
241
  # Configuration parameters: CountAsOne.
136
242
  RSpec/ExampleLength:
137
- Max: 6
243
+ Max: 8
244
+
245
+ # Offense count: 1
246
+ RSpec/LeakyConstantDeclaration:
247
+ Exclude:
248
+ - 'spec/metanorma/html/renderer/class_ownership_spec.rb'
138
249
 
139
250
  # Offense count: 1
140
251
  RSpec/MultipleDescribes:
141
252
  Exclude:
142
253
  - 'spec/metanorma/document_spec.rb'
143
254
 
144
- # Offense count: 279
255
+ # Offense count: 286
145
256
  # Configuration parameters: AllowedPatterns.
146
257
  # AllowedPatterns: ^expect_, ^assert_
147
258
  RSpec/NoExpectationExample:
148
259
  Enabled: false
149
260
 
150
- # Offense count: 16
261
+ # Offense count: 25
151
262
  # Configuration parameters: CustomTransform, IgnoreMethods, IgnoreMetadata, InflectorPath, EnforcedInflector.
152
263
  # SupportedInflectors: default, active_support
153
264
  RSpec/SpecFilePathFormat:
154
265
  Enabled: false
155
266
 
156
267
  # Offense count: 2
268
+ # This cop supports safe autocorrection (--autocorrect).
269
+ # Configuration parameters: AllowOnlyRestArgument, UseAnonymousForwarding, RedundantRestArgumentNames, RedundantKeywordRestArgumentNames, RedundantBlockArgumentNames.
270
+ # RedundantRestArgumentNames: args, arguments
271
+ # RedundantKeywordRestArgumentNames: kwargs, options, opts
272
+ # RedundantBlockArgumentNames: blk, block, proc
273
+ Style/ArgumentsForwarding:
274
+ Exclude:
275
+ - 'lib/metanorma/html/component/footnote_collector.rb'
276
+
277
+ # Offense count: 1
278
+ # This cop supports safe autocorrection (--autocorrect).
279
+ # Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, AllowedMethods, AllowedPatterns, AllowBracesOnProceduralOneLiners, BracesRequiredMethods.
280
+ # SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces
281
+ # ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object
282
+ # FunctionalMethods: let, let!, subject, watch
283
+ # AllowedMethods: lambda, proc, it
284
+ Style/BlockDelimiters:
285
+ Exclude:
286
+ - 'lib/metanorma/iso_document/metadata/iso_bibliographic_item.rb'
287
+
288
+ # Offense count: 5
289
+ # This cop supports safe autocorrection (--autocorrect).
290
+ Style/ComparableClamp:
291
+ Exclude:
292
+ - 'lib/metanorma/html/base_renderer.rb'
293
+ - 'lib/metanorma/html/iso_renderer.rb'
294
+ - 'lib/metanorma/html/standard_renderer.rb'
295
+
296
+ # Offense count: 1
157
297
  # This cop supports unsafe autocorrection (--autocorrect-all).
158
- Style/IdenticalConditionalBranches:
298
+ # Configuration parameters: InverseMethods, InverseBlocks.
299
+ Style/InverseMethods:
159
300
  Exclude:
160
- - 'lib/metanorma/html/index_generator.rb'
301
+ - 'lib/metanorma/html/component/index_term_collector.rb'
161
302
 
162
303
  # Offense count: 1
163
- # Configuration parameters: Max.
164
- Style/SafeNavigationChainLength:
304
+ # This cop supports unsafe autocorrection (--autocorrect-all).
305
+ # Configuration parameters: EnforcedStyle.
306
+ # SupportedStyles: literals, strict
307
+ Style/MutableConstant:
308
+ Exclude:
309
+ - 'lib/metanorma/html/base_renderer.rb'
310
+
311
+ # Offense count: 1
312
+ # This cop supports safe autocorrection (--autocorrect).
313
+ Style/NegatedIfElseCondition:
314
+ Exclude:
315
+ - 'lib/metanorma/iso_document/metadata/iso_localized_title.rb'
316
+
317
+ # Offense count: 1
318
+ # This cop supports safe autocorrection (--autocorrect).
319
+ Style/RedundantRegexpArgument:
320
+ Exclude:
321
+ - 'lib/metanorma/html/bipm_renderer.rb'
322
+
323
+ # Offense count: 2
324
+ # This cop supports safe autocorrection (--autocorrect).
325
+ Style/RescueModifier:
326
+ Exclude:
327
+ - 'lib/metanorma/html/generator.rb'
328
+
329
+ # Offense count: 1
330
+ # This cop supports unsafe autocorrection (--autocorrect-all).
331
+ # Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods, MaxChainLength.
332
+ # AllowedMethods: present?, blank?, presence, try, try!
333
+ Style/SafeNavigation:
334
+ Exclude:
335
+ - 'lib/metanorma/html/bipm_renderer.rb'
336
+
337
+ # Offense count: 2
338
+ # This cop supports safe autocorrection (--autocorrect).
339
+ # Configuration parameters: EnforcedStyleForMultiline.
340
+ # SupportedStylesForMultiline: comma, consistent_comma, diff_comma, no_comma
341
+ Style/TrailingCommaInArguments:
165
342
  Exclude:
166
- - 'lib/metanorma/html/renderer.rb'
343
+ - 'lib/metanorma/html/component/footnote_collector.rb'
344
+ - 'lib/metanorma/html/component/index_term_collector.rb'
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Metanorma
4
4
  module Document
5
- VERSION = "0.2.1"
5
+ VERSION = "0.2.2"
6
6
  Version = VERSION
7
7
  end
8
8
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "liquid"
4
4
  require "nokogiri"
5
+ require "cgi"
5
6
  require_relative "drops/footnote_drop"
6
7
 
7
8
  module Metanorma
@@ -141,11 +142,14 @@ module Metanorma
141
142
 
142
143
  # --- Document Assembly ---
143
144
 
144
- TEMPLATE_CACHE = Hash.new { |h, k| h[k] = Liquid::Template.parse(File.read(k)) }
145
+ TEMPLATE_CACHE = {}
146
+ TEMPLATE_CACHE_MUTEX = Mutex.new
145
147
 
146
148
  def render_liquid(template_name, assigns)
147
149
  template_path = File.join(TEMPLATES_ROOT, template_name)
148
- template = TEMPLATE_CACHE[template_path]
150
+ template = TEMPLATE_CACHE_MUTEX.synchronize do
151
+ TEMPLATE_CACHE[template_path] ||= Liquid::Template.parse(File.read(template_path))
152
+ end
149
153
  assigns = assigns.transform_keys(&:to_s) if assigns.is_a?(Hash)
150
154
  template.render(assigns)
151
155
  end
@@ -192,11 +196,6 @@ module Metanorma
192
196
  raw.length > 60 ? "#{raw[0, 57]}..." : raw
193
197
  end
194
198
 
195
- # Reader controls — kept for backward compat with flavor renderers
196
- def build_reader_controls
197
- ""
198
- end
199
-
200
199
  def build_publisher_logos
201
200
  publishers = flavor_publishers(extract_primary_doc_id)
202
201
  logo_map = publisher_logo_map
@@ -216,10 +215,6 @@ module Metanorma
216
215
  end.join("\n")
217
216
  end
218
217
 
219
- def detect_publishers
220
- flavor_publishers(extract_primary_doc_id)
221
- end
222
-
223
218
  def load_logo_svg(filename, height: 32)
224
219
  path = File.join(LOGO_DIR, filename)
225
220
  return nil unless File.exist?(path)
@@ -989,7 +984,9 @@ module Metanorma
989
984
  end
990
985
 
991
986
  def raw_content_node?(node)
992
- node.is_a?(Metanorma::IsoDocument::RawParagraph)
987
+ node.is_a?(Lutaml::Model::Serializable) &&
988
+ node.respond_to?(:content) &&
989
+ node.content.is_a?(String)
993
990
  end
994
991
 
995
992
  # Iterate element_order directly, preserving whitespace text nodes
@@ -1427,32 +1424,34 @@ module Metanorma
1427
1424
  parts.join
1428
1425
  end
1429
1426
 
1427
+ BLOCK_TYPES = Set[
1428
+ Metanorma::Document::Components::Paragraphs::ParagraphBlock,
1429
+ Metanorma::Document::Components::Tables::TableBlock,
1430
+ Metanorma::Document::Components::Lists::UnorderedList,
1431
+ Metanorma::Document::Components::Lists::OrderedList,
1432
+ Metanorma::Document::Components::Lists::DefinitionList,
1433
+ Metanorma::Document::Components::AncillaryBlocks::FigureBlock,
1434
+ Metanorma::Document::Components::Blocks::NoteBlock,
1435
+ Metanorma::Document::Components::AncillaryBlocks::ExampleBlock,
1436
+ Metanorma::Document::Components::AncillaryBlocks::SourcecodeBlock,
1437
+ Metanorma::Document::Components::AncillaryBlocks::FormulaBlock,
1438
+ Metanorma::Document::Components::MultiParagraph::QuoteBlock,
1439
+ Metanorma::Document::Components::MultiParagraph::AdmonitionBlock,
1440
+ Metanorma::Document::Components::Sections::HierarchicalSection,
1441
+ Metanorma::Document::Components::Sections::BasicSection,
1442
+ Metanorma::Document::Components::Sections::ContentSection,
1443
+ ].freeze
1444
+
1430
1445
  def html_class_for_span(xml_class)
1431
1446
  SPAN_ROLE_CLASSES[xml_class] || "span-#{xml_class}"
1432
1447
  end
1433
1448
 
1434
1449
  def block_element?(obj)
1435
- obj.is_a?(Metanorma::Document::Components::Paragraphs::ParagraphBlock) ||
1436
- obj.is_a?(Metanorma::Document::Components::Tables::TableBlock) ||
1437
- obj.is_a?(Metanorma::Document::Components::Lists::UnorderedList) ||
1438
- obj.is_a?(Metanorma::Document::Components::Lists::OrderedList) ||
1439
- obj.is_a?(Metanorma::Document::Components::Lists::DefinitionList) ||
1440
- obj.is_a?(Metanorma::Document::Components::AncillaryBlocks::FigureBlock) ||
1441
- obj.is_a?(Metanorma::Document::Components::Blocks::NoteBlock) ||
1442
- obj.is_a?(Metanorma::Document::Components::AncillaryBlocks::ExampleBlock) ||
1443
- obj.is_a?(Metanorma::Document::Components::AncillaryBlocks::SourcecodeBlock) ||
1444
- obj.is_a?(Metanorma::Document::Components::AncillaryBlocks::FormulaBlock) ||
1445
- obj.is_a?(Metanorma::Document::Components::MultiParagraph::QuoteBlock) ||
1446
- obj.is_a?(Metanorma::Document::Components::MultiParagraph::AdmonitionBlock) ||
1447
- obj.is_a?(Metanorma::Document::Components::Sections::HierarchicalSection) ||
1448
- obj.is_a?(Metanorma::Document::Components::Sections::BasicSection) ||
1449
- obj.is_a?(Metanorma::Document::Components::Sections::ContentSection)
1450
+ BLOCK_TYPES.any? { |type| obj.is_a?(type) }
1450
1451
  end
1451
1452
 
1452
1453
  def safe_attr(obj, method_name)
1453
- obj.public_send(method_name)
1454
- rescue NoMethodError
1455
- nil
1454
+ obj.public_send(method_name) if obj.respond_to?(method_name)
1456
1455
  end
1457
1456
 
1458
1457
  def collect_index_term(element)
@@ -1504,14 +1503,7 @@ module Metanorma
1504
1503
  end
1505
1504
 
1506
1505
  def escape_html(text)
1507
- return "" if text.nil?
1508
-
1509
- text
1510
- .to_s
1511
- .gsub("&", "&")
1512
- .gsub("<", "&lt;")
1513
- .gsub(">", "&gt;")
1514
- .gsub('"', "&quot;")
1506
+ CGI.escapeHTML(text.to_s)
1515
1507
  end
1516
1508
 
1517
1509
  def extract_text_value(val)
@@ -5,7 +5,6 @@ module Metanorma
5
5
  # Renders BipmDocument components to HTML.
6
6
  # Extends IsoRenderer with BIPM-specific branding (institutional navy, scientific precision).
7
7
  class BipmRenderer < IsoRenderer
8
- registers_doc_type Metanorma::BipmDocument::Root
9
8
 
10
9
  def flavor_publishers(_doc_id)
11
10
  ["BIPM"]
@@ -5,7 +5,6 @@ module Metanorma
5
5
  # Renders CcDocument (CalConnect) components to HTML.
6
6
  # Extends IsoRenderer with CalConnect branding.
7
7
  class CcRenderer < IsoRenderer
8
- registers_doc_type Metanorma::CcDocument::Root
9
8
 
10
9
  def flavor_publishers(_doc_id)
11
10
  ["CalConnect"]
@@ -4,7 +4,6 @@ module Metanorma
4
4
  module Html
5
5
  # IEC brand: #0061a9 blue from logo
6
6
  class IecRenderer < IsoRenderer
7
- registers_doc_type Metanorma::IecDocument::Root
8
7
 
9
8
  def flavor_publishers(_doc_id)
10
9
  ["IEC"]
@@ -5,7 +5,6 @@ module Metanorma
5
5
  # Renders IeeeDocument components to HTML.
6
6
  # Extends IsoRenderer with IEEE branding.
7
7
  class IeeeRenderer < IsoRenderer
8
- registers_doc_type Metanorma::IeeeDocument::Root
9
8
 
10
9
  def flavor_publishers(_doc_id)
11
10
  ["IEEE"]
@@ -5,7 +5,6 @@ module Metanorma
5
5
  # Renders IetfDocument components to HTML.
6
6
  # Extends IsoRenderer with IETF/RFC branding.
7
7
  class IetfRenderer < IsoRenderer
8
- registers_doc_type Metanorma::IetfDocument::Root
9
8
 
10
9
  def flavor_publishers(_doc_id)
11
10
  ["IETF"]
@@ -4,7 +4,6 @@ module Metanorma
4
4
  module Html
5
5
  # IHO brand: #00AAA9 teal + #05164D navy + #FEDC5B gold from logo
6
6
  class IhoRenderer < IsoRenderer
7
- registers_doc_type Metanorma::IhoDocument::Root
8
7
 
9
8
  def flavor_publishers(_doc_id)
10
9
  ["IHO"]
@@ -8,22 +8,6 @@ module Metanorma
8
8
  # Extends StandardRenderer with ISO-specific cover page, boilerplate,
9
9
  # foreword, introduction, annex formatting, and ISO term entries.
10
10
  class IsoRenderer < StandardRenderer
11
- class << self
12
- def doc_types
13
- @doc_types ||= []
14
- if superclass <= IsoRenderer && superclass != IsoRenderer
15
- superclass.doc_types + @doc_types
16
- else
17
- @doc_types.dup
18
- end
19
- end
20
-
21
- def registers_doc_type(klass)
22
- @doc_types ||= []
23
- @doc_types << klass
24
- end
25
- end
26
-
27
11
  # --- Public hooks for flavor customization ---
28
12
 
29
13
  def flavor_publishers(_doc_id)
@@ -585,32 +569,6 @@ module Metanorma
585
569
  end
586
570
  end
587
571
 
588
- def render_term_note(note)
589
- attrs = element_attrs(id: safe_attr(note, :id), class: "note-block")
590
- tag("div", attrs) do
591
- label = extract_termnote_label(note)
592
- @output << "<p><span class=\"term-note-label\">#{escape_html(label)}: </span>"
593
- note.p&.each { |para| render_mixed_inline(para) }
594
- @output << "</p>"
595
- note.ul&.each { |ul| render_unordered_list(ul) }
596
- note.ol&.each { |ol| render_ordered_list(ol) }
597
- note.dl&.then { |dl| render_definition_list(dl) }
598
- end
599
- end
600
-
601
- def render_term_example(example)
602
- attrs = element_attrs(id: safe_attr(example, :id), class: "example")
603
- tag("div", attrs) do
604
- label = extract_block_label(example, "EXAMPLE")
605
- @output << "<p><span class=\"example-label\">#{escape_html(label)}</span>&nbsp;"
606
- example.p&.each { |para| render_mixed_inline(para) }
607
- @output << "</p>"
608
- example.ul&.each { |ul| render_unordered_list(ul) }
609
- example.ol&.each { |ol| render_ordered_list(ol) }
610
- example.dl&.then { |dl| render_definition_list(dl) }
611
- end
612
- end
613
-
614
572
  # --- Boilerplate rendering ---
615
573
 
616
574
  def render_boilerplate(boilerplate, **_opts)
@@ -685,45 +643,6 @@ module Metanorma
685
643
  @output << "</#{h}>"
686
644
  end
687
645
 
688
- # Collect all renderable children from a section, sorted by displayorder.
689
- # Uses element_order directly because each_mixed_content returns early
690
- # when the model class doesn't declare mixed_content (mixed? is false).
691
- def collect_ordered_children(section)
692
- children = gather_element_order_children(section)
693
-
694
- # Also gather typed attributes that may not appear in element_order
695
- %i[terms definitions].each do |attr|
696
- val = safe_attr(section, attr)
697
- next if val.nil?
698
-
699
- Array(val).each do |v|
700
- children << v unless children.include?(v)
701
- end
702
- end
703
-
704
- # Sort by displayorder (non-nil first, then nil at end)
705
- children.compact!
706
- children.sort_by do |node|
707
- order = begin
708
- node.displayorder
709
- rescue StandardError
710
- nil
711
- end
712
- order &&= order.to_i
713
- order || Float::INFINITY
714
- end
715
- end
716
-
717
- def render_ordered_content(section, level = 1)
718
- children = collect_ordered_children(section)
719
- children.each do |node|
720
- next if node.is_a?(String)
721
- next if is_title_element?(node, section)
722
-
723
- render(node, level: level + 1)
724
- end
725
- end
726
-
727
646
  # Collect all document-level children (sections, normative refs, annexes,
728
647
  # bibliography) sorted by displayorder for correct document order.
729
648
  # Top-level paragraphs in sections (title paragraphs) are excluded —
@@ -731,87 +650,19 @@ module Metanorma
731
650
  def collect_document_children(doc)
732
651
  items = []
733
652
 
734
- # Main sections children (clauses, terms, etc.)
735
653
  if doc.sections
736
- section_children = gather_element_order_children(doc.sections)
737
- # Title paragraphs are ParagraphBlock objects at the top level of
738
- # sections. They are rendered by render_doc_title, so skip them here.
654
+ section_children = collect_ordered_children(doc.sections)
739
655
  section_children.reject! do |node|
740
656
  node.is_a?(Metanorma::Document::Components::Paragraphs::ParagraphBlock)
741
657
  end
742
658
  items.concat(section_children)
743
- # Also add typed attributes that may not be in element_order
744
- %i[terms definitions].each do |attr|
745
- val = safe_attr(doc.sections, attr)
746
- next if val.nil?
747
-
748
- Array(val).each { |v| items << v unless items.include?(v) }
749
- end
750
659
  end
751
660
 
752
- # Normative references from bibliography (may have displayorder)
753
661
  doc.bibliography&.references&.each { |r| items << r }
754
-
755
- # Annexes
756
662
  doc.annex&.each { |a| items << a }
757
663
 
758
- # Non-normative bibliography (no displayorder = goes at end)
759
- if doc.bibliography&.references
760
- # Already included above; filter normative vs non-normative below
761
- end
762
-
763
664
  items.compact!
764
- items.sort_by do |node|
765
- order = begin
766
- node.displayorder
767
- rescue StandardError
768
- nil
769
- end
770
- order &&= order.to_i
771
- order || Float::INFINITY
772
- end
773
- end
774
-
775
- # Iterate element_order directly, bypassing each_mixed_content which
776
- # requires mixed?/ordered? to be true (many section models aren't).
777
- def gather_element_order_children(node)
778
- children = []
779
- return children unless node.is_a?(Lutaml::Model::Serializable)
780
- return children unless node.element_order && !node.element_order.empty?
781
-
782
- xml_mapping = node.class.mappings_for(:xml, node.lutaml_register)
783
- return children unless xml_mapping
784
-
785
- element_to_attr = {}
786
- xml_mapping.mapping_elements_hash.each_value do |rule_or_array|
787
- Array(rule_or_array).each do |rule|
788
- element_to_attr[rule.name] = rule.to
789
- element_to_attr[rule.name.to_s] = rule.to if rule.name.is_a?(Symbol)
790
- end
791
- end
792
-
793
- indices = Hash.new(0)
794
-
795
- node.element_order.each do |el|
796
- if el.text?
797
- children << el.text_content if el.text_content
798
- elsif el.element?
799
- attr_name = element_to_attr[el.name]
800
- next unless attr_name
801
-
802
- coll = node.send(attr_name)
803
- obj = if coll.is_a?(Array)
804
- idx = indices[attr_name]
805
- indices[attr_name] += 1
806
- coll[idx]
807
- else
808
- coll
809
- end
810
- children << obj if obj
811
- end
812
- end
813
-
814
- children
665
+ sort_by_displayorder(items)
815
666
  end
816
667
 
817
668
  def publisher_logos_html(_doc)
@@ -4,7 +4,6 @@ module Metanorma
4
4
  module Html
5
5
  # ITU brand: #0e99d5 blue from logo
6
6
  class ItuRenderer < IsoRenderer
7
- registers_doc_type Metanorma::ItuDocument::Root
8
7
 
9
8
  def flavor_publishers(_doc_id)
10
9
  ["ITU"]
@@ -5,7 +5,6 @@ module Metanorma
5
5
  # Renders OgcDocument components to HTML.
6
6
  # Extends IsoRenderer with OGC-specific branding (geospatial, OGC cyan-blue #00b1ff).
7
7
  class OgcRenderer < IsoRenderer
8
- registers_doc_type Metanorma::OgcDocument::Root
9
8
 
10
9
  def flavor_publishers(_doc_id)
11
10
  ["OGC"]
@@ -5,7 +5,6 @@ module Metanorma
5
5
  # Renders OimlDocument (OIML) components to HTML.
6
6
  # Extends IsoRenderer with OIML branding.
7
7
  class OimlRenderer < IsoRenderer
8
- registers_doc_type Metanorma::OimlDocument::Root
9
8
 
10
9
  def flavor_publishers(_doc_id)
11
10
  ["OIML"]
@@ -5,7 +5,6 @@ module Metanorma
5
5
  # Renders PDF Association (PDFA) taste documents to HTML.
6
6
  # PDFA brand: #cf9c1d gold + #d03544 red + #4992b2 steel blue from logo
7
7
  class PdfaRenderer < IsoRenderer
8
- registers_doc_type Metanorma::RiboseDocument::Root
9
8
 
10
9
  def flavor_publishers(_doc_id)
11
10
  ["PDF Association"]
@@ -5,7 +5,6 @@ module Metanorma
5
5
  # Renders RiboseDocument components to HTML.
6
6
  # Extends IsoRenderer with Ribose branding.
7
7
  class RiboseRenderer < IsoRenderer
8
- registers_doc_type Metanorma::RiboseDocument::Root
9
8
 
10
9
  def flavor_publishers(_doc_id)
11
10
  ["Ribose"]
@@ -138,63 +138,46 @@ module Metanorma
138
138
 
139
139
  # --- Section rendering ---
140
140
 
141
- def render_clause_section(clause, level: 1, **_opts)
142
- attrs = element_attrs(id: safe_attr(clause, :id))
141
+ def render_section(section, level: 1, title_class: nil, with_subsections: false, with_terms: false)
142
+ attrs = element_attrs(id: safe_attr(section, :id))
143
143
  tag("div", attrs) do
144
- render_standard_title(clause, level)
145
- render_standard_section_blocks(clause, level)
146
- render_subsections(clause, level)
144
+ if title_class
145
+ render_standard_title(section, level, default_class: title_class)
146
+ else
147
+ render_standard_title(section, level)
148
+ end
149
+ render_standard_section_blocks(section, level)
150
+ render_subsections(section, level) if with_subsections
151
+ section.terms&.each { |term| render_term(term) } if with_terms
147
152
  end
148
153
  end
149
154
 
150
- def render_annex_section(annex, level: 1, **_opts)
151
- attrs = element_attrs(id: safe_attr(annex, :id))
152
- tag("div", attrs) do
153
- render_standard_title(annex, level)
154
- render_standard_section_blocks(annex, level)
155
- render_subsections(annex, level)
156
- end
155
+ def render_clause_section(section, level: 1, **)
156
+ render_section(section, level: level, with_subsections: true)
157
157
  end
158
158
 
159
- def render_standard_section(section, level: 1, **_opts)
160
- attrs = element_attrs(id: safe_attr(section, :id))
161
- tag("div", attrs) do
162
- render_standard_title(section, level)
163
- render_standard_section_blocks(section, level)
164
- end
159
+ def render_annex_section(section, level: 1, **)
160
+ render_section(section, level: level, with_subsections: true)
165
161
  end
166
162
 
167
- def render_terms_section(terms, level: 1, **_opts)
168
- attrs = element_attrs(id: safe_attr(terms, :id))
169
- tag("div", attrs) do
170
- render_standard_title(terms, level)
171
- render_standard_section_blocks(terms, level)
172
- terms.terms&.each { |term| render_term(term) }
173
- end
163
+ def render_standard_section(section, level: 1, **)
164
+ render_section(section, level: level)
174
165
  end
175
166
 
176
- def render_abstract_section(section, level: 1, **_opts)
177
- attrs = element_attrs(id: safe_attr(section, :id))
178
- tag("div", attrs) do
179
- render_standard_title(section, level, default_class: "intro-title")
180
- render_standard_section_blocks(section, level)
181
- end
167
+ def render_terms_section(section, level: 1, **)
168
+ render_section(section, level: level, with_terms: true)
182
169
  end
183
170
 
184
- def render_foreword_section(section, level: 1, **_opts)
185
- attrs = element_attrs(id: safe_attr(section, :id))
186
- tag("div", attrs) do
187
- render_standard_title(section, level, default_class: "foreword-title")
188
- render_standard_section_blocks(section, level)
189
- end
171
+ def render_abstract_section(section, level: 1, **)
172
+ render_section(section, level: level, title_class: "intro-title")
190
173
  end
191
174
 
192
- def render_introduction_section(section, level: 1, **_opts)
193
- attrs = element_attrs(id: safe_attr(section, :id))
194
- tag("div", attrs) do
195
- render_standard_title(section, level, default_class: "intro-title")
196
- render_standard_section_blocks(section, level)
197
- end
175
+ def render_foreword_section(section, level: 1, **)
176
+ render_section(section, level: level, title_class: "foreword-title")
177
+ end
178
+
179
+ def render_introduction_section(section, level: 1, **)
180
+ render_section(section, level: level, title_class: "intro-title")
198
181
  end
199
182
 
200
183
  def render_floating_title(title_node, **_opts)
@@ -285,11 +268,7 @@ module Metanorma
285
268
  tag("div", attrs) do
286
269
  label = extract_termnote_label(note)
287
270
  @output << "<p><span class=\"term-note-label\">#{escape_html(label)}: </span>"
288
- if note.p && !note.p.empty?
289
- note.p.each do |para|
290
- render_mixed_inline(para)
291
- end
292
- end
271
+ note.p&.each { |para| render_mixed_inline(para) }
293
272
  @output << "</p>"
294
273
  note.ul&.each { |ul| render_unordered_list(ul) }
295
274
  note.ol&.each { |ol| render_ordered_list(ol) }
@@ -302,11 +281,7 @@ module Metanorma
302
281
  tag("div", attrs) do
303
282
  label = extract_block_label(example, "EXAMPLE")
304
283
  @output << "<p><span class=\"example-label\">#{escape_html(label)}</span>&nbsp;"
305
- if example.p && !example.p.empty?
306
- example.p.each do |para|
307
- render_mixed_inline(para)
308
- end
309
- end
284
+ example.p&.each { |para| render_mixed_inline(para) }
310
285
  @output << "</p>"
311
286
  example.ul&.each { |ul| render_unordered_list(ul) }
312
287
  example.ol&.each { |ol| render_ordered_list(ol) }
@@ -433,7 +408,7 @@ module Metanorma
433
408
  end
434
409
  if primary
435
410
  id_val = extract_text_value(primary)
436
- @output << "<span class=\"std-doc-number\">#{escape_html(id_val)}</span>" unless id_val.to_s.empty?
411
+ @output << "<span class=\"ref-doc-number\">#{escape_html(id_val)}</span>" unless id_val.to_s.empty?
437
412
  end
438
413
  end
439
414
 
@@ -442,7 +417,7 @@ module Metanorma
442
417
  date_on = date.is_a?(Metanorma::Document::Relaton::BibliographicDate) ? date.on : nil
443
418
  date_val = extract_text_value(date_on || safe_attr(date, :text))
444
419
  if date_val && !date_val.to_s.empty?
445
- @output << ":<span class=\"std-year\">#{escape_html(date_val.to_s)}</span>"
420
+ @output << ":<span class=\"ref-year\">#{escape_html(date_val.to_s)}</span>"
446
421
  end
447
422
  end
448
423
  end
@@ -8,7 +8,6 @@ module Metanorma
8
8
  autoload :Generator, "metanorma/html/generator"
9
9
  autoload :Theme, "metanorma/html/theme"
10
10
  autoload :AssetPipeline, "metanorma/html/asset_pipeline"
11
- autoload :ComponentRegistry, "metanorma/html/component_registry"
12
11
  autoload :Component, "metanorma/html/component"
13
12
  autoload :Drops, "metanorma/html/drops"
14
13
  autoload :StandardRenderer, "metanorma/html/standard_renderer"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metanorma-document
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-05-05 00:00:00.000000000 Z
11
+ date: 2026-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lutaml-model
@@ -481,7 +481,6 @@ files:
481
481
  - lib/metanorma/html/component/footnote_collector.rb
482
482
  - lib/metanorma/html/component/index_section.rb
483
483
  - lib/metanorma/html/component/index_term_collector.rb
484
- - lib/metanorma/html/component_registry.rb
485
484
  - lib/metanorma/html/drops.rb
486
485
  - lib/metanorma/html/drops/admonition_drop.rb
487
486
  - lib/metanorma/html/drops/block_element_drop.rb
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Metanorma
4
- module Html
5
- class ComponentRegistry
6
- def initialize
7
- @map = {}
8
- end
9
-
10
- def register(model_class, component_class)
11
- @map[model_class] = component_class
12
- end
13
-
14
- def lookup(model_class)
15
- @map[model_class] ||
16
- model_class.ancestors
17
- .drop(1)
18
- .filter_map { |a| @map[a] }
19
- .first ||
20
- nil
21
- end
22
-
23
- def component_for(renderer, model_class)
24
- component_class = lookup(model_class)
25
- component_class&.new(renderer)
26
- end
27
-
28
- def register_all(component_module)
29
- component_module.constants.each do |const|
30
- klass = component_module.const_get(const)
31
- next unless klass.is_a?(Class) && klass < Component::Base
32
- klass.register_in(self)
33
- end
34
- end
35
- end
36
- end
37
- end