coradoc 2.0.5 → 2.0.6

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 (116) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +82 -36
  3. data/coradoc-adoc/lib/coradoc/asciidoc/model/document.rb +2 -2
  4. data/coradoc-adoc/lib/coradoc/asciidoc/model/include.rb +2 -2
  5. data/coradoc-adoc/lib/coradoc/asciidoc/model.rb +6 -4
  6. data/coradoc-adoc/lib/coradoc/asciidoc/parser/block.rb +5 -4
  7. data/coradoc-adoc/lib/coradoc/asciidoc/parser/content.rb +4 -2
  8. data/coradoc-adoc/lib/coradoc/asciidoc/transform/from_core_model.rb +84 -13
  9. data/coradoc-adoc/lib/coradoc/asciidoc/transform/to_core_model.rb +94 -25
  10. data/coradoc-adoc/lib/coradoc/asciidoc/transform/to_core_model_registrations.rb +42 -18
  11. data/coradoc-adoc/lib/coradoc/asciidoc/transformer/structural_rules.rb +2 -1
  12. data/coradoc-adoc/lib/coradoc/asciidoc.rb +7 -2
  13. data/coradoc-adoc/spec/coradoc/asciidoc/integration_pipeline_spec.rb +1 -3
  14. data/coradoc-adoc/spec/coradoc/asciidoc/round_trip_spec.rb +0 -1
  15. data/coradoc-adoc/spec/coradoc/asciidoc/transform/from_core_model_spec.rb +3 -2
  16. data/coradoc-adoc/spec/coradoc/developer_experience_spec.rb +0 -1
  17. data/coradoc-adoc/spec/transform/from_core_model_spec.rb +3 -3
  18. data/coradoc-adoc/spec/transform/to_core_model_spec.rb +1 -0
  19. data/coradoc-html/lib/coradoc/html/converters/base.rb +41 -17
  20. data/coradoc-html/lib/coradoc/html/converters/example.rb +1 -2
  21. data/coradoc-html/lib/coradoc/html/converters/listing.rb +1 -2
  22. data/coradoc-html/lib/coradoc/html/converters/literal.rb +1 -2
  23. data/coradoc-html/lib/coradoc/html/converters/open.rb +1 -2
  24. data/coradoc-html/lib/coradoc/html/converters/quote.rb +2 -3
  25. data/coradoc-html/lib/coradoc/html/converters/sidebar.rb +1 -2
  26. data/coradoc-html/lib/coradoc/html/converters/source.rb +1 -2
  27. data/coradoc-html/lib/coradoc/html/converters/source_code.rb +1 -2
  28. data/coradoc-html/lib/coradoc/html/converters/term.rb +1 -2
  29. data/coradoc-html/lib/coradoc/html/converters/verse.rb +2 -3
  30. data/coradoc-html/lib/coradoc/html/input/converters/aside.rb +1 -1
  31. data/coradoc-html/lib/coradoc/html/input/converters/audio.rb +1 -1
  32. data/coradoc-html/lib/coradoc/html/input/converters/blockquote.rb +2 -3
  33. data/coradoc-html/lib/coradoc/html/input/converters/div.rb +1 -2
  34. data/coradoc-html/lib/coradoc/html/input/converters/figure.rb +2 -3
  35. data/coradoc-html/lib/coradoc/html/input/converters/hr.rb +1 -1
  36. data/coradoc-html/lib/coradoc/html/input/converters/p.rb +2 -1
  37. data/coradoc-html/lib/coradoc/html/input/converters/pre.rb +14 -10
  38. data/coradoc-html/lib/coradoc/html/input/converters/video.rb +1 -1
  39. data/coradoc-html/lib/coradoc/html/renderer.rb +50 -2
  40. data/coradoc-html/lib/coradoc/html/spa.rb +2 -2
  41. data/coradoc-html/lib/coradoc/html/static.rb +2 -2
  42. data/coradoc-html/lib/coradoc/html/templates/core_model/definition_list.liquid +11 -0
  43. data/coradoc-html/lib/coradoc/html/theme/modern/javascript_generator.rb +2 -2
  44. data/coradoc-html/lib/coradoc/html/theme/modern/serializers/document_serializer.rb +7 -11
  45. data/coradoc-html/lib/coradoc/html/theme/modern_renderer.rb +6 -7
  46. data/coradoc-html/lib/coradoc/html.rb +5 -15
  47. data/coradoc-html/spec/input/converters/converters_spec.rb +1 -1
  48. data/coradoc-markdown/lib/coradoc/markdown/model/attribute_list.rb +0 -3
  49. data/coradoc-markdown/lib/coradoc/markdown/model/definition_list.rb +0 -3
  50. data/coradoc-markdown/lib/coradoc/markdown/model/extension.rb +0 -2
  51. data/coradoc-markdown/lib/coradoc/markdown/model/highlight.rb +0 -1
  52. data/coradoc-markdown/lib/coradoc/markdown/model/math.rb +0 -1
  53. data/coradoc-markdown/lib/coradoc/markdown/model/strikethrough.rb +0 -1
  54. data/coradoc-markdown/lib/coradoc/markdown/parser/ast_processor.rb +2 -2
  55. data/coradoc-markdown/lib/coradoc/markdown/parser/block_parser.rb +2 -2
  56. data/coradoc-markdown/lib/coradoc/markdown/parser/inline_parser.rb +3 -3
  57. data/coradoc-markdown/lib/coradoc/markdown/parser.rb +9 -3
  58. data/coradoc-markdown/lib/coradoc/markdown/toc_generator.rb +6 -4
  59. data/coradoc-markdown/lib/coradoc/markdown/transform/from_core_model.rb +27 -6
  60. data/coradoc-markdown/lib/coradoc/markdown/transform/to_core_model.rb +5 -9
  61. data/coradoc-markdown/lib/coradoc/markdown/transformer.rb +2 -1
  62. data/coradoc-markdown/spec/transform/to_core_model_spec.rb +6 -8
  63. data/exe/coradoc +1 -0
  64. data/lib/coradoc/coradoc.rb +6 -7
  65. data/lib/coradoc/core_model/annotation_block.rb +0 -2
  66. data/lib/coradoc/core_model/block.rb +92 -32
  67. data/lib/coradoc/core_model/builder/block_builder.rb +20 -2
  68. data/lib/coradoc/core_model/builder/detection.rb +0 -8
  69. data/lib/coradoc/core_model/builder.rb +6 -7
  70. data/lib/coradoc/core_model/example_block.rb +12 -0
  71. data/lib/coradoc/core_model/listing_block.rb +15 -0
  72. data/lib/coradoc/core_model/literal_block.rb +12 -0
  73. data/lib/coradoc/core_model/open_block.rb +12 -0
  74. data/lib/coradoc/core_model/pass_block.rb +12 -0
  75. data/lib/coradoc/core_model/quote_block.rb +14 -0
  76. data/lib/coradoc/core_model/reviewer_block.rb +12 -0
  77. data/lib/coradoc/core_model/sidebar_block.rb +12 -0
  78. data/lib/coradoc/core_model/source_block.rb +22 -0
  79. data/lib/coradoc/core_model/verse_block.rb +14 -0
  80. data/lib/coradoc/core_model.rb +10 -0
  81. data/lib/coradoc/processor_registry.rb +0 -2
  82. data/lib/coradoc/version.rb +1 -1
  83. metadata +12 -34
  84. data/coradoc-markdown/coverage/.last_run.json +0 -5
  85. data/coradoc-markdown/coverage/.resultset.json +0 -6322
  86. data/coradoc-markdown/coverage/.resultset.json.lock +0 -0
  87. data/coradoc-markdown/coverage/assets/0.13.2/DataTables-1.10.20/images/sort_asc.png +0 -0
  88. data/coradoc-markdown/coverage/assets/0.13.2/DataTables-1.10.20/images/sort_asc_disabled.png +0 -0
  89. data/coradoc-markdown/coverage/assets/0.13.2/DataTables-1.10.20/images/sort_both.png +0 -0
  90. data/coradoc-markdown/coverage/assets/0.13.2/DataTables-1.10.20/images/sort_desc.png +0 -0
  91. data/coradoc-markdown/coverage/assets/0.13.2/DataTables-1.10.20/images/sort_desc_disabled.png +0 -0
  92. data/coradoc-markdown/coverage/assets/0.13.2/application.css +0 -1
  93. data/coradoc-markdown/coverage/assets/0.13.2/application.js +0 -7
  94. data/coradoc-markdown/coverage/assets/0.13.2/colorbox/border.png +0 -0
  95. data/coradoc-markdown/coverage/assets/0.13.2/colorbox/controls.png +0 -0
  96. data/coradoc-markdown/coverage/assets/0.13.2/colorbox/loading.gif +0 -0
  97. data/coradoc-markdown/coverage/assets/0.13.2/colorbox/loading_background.png +0 -0
  98. data/coradoc-markdown/coverage/assets/0.13.2/favicon_green.png +0 -0
  99. data/coradoc-markdown/coverage/assets/0.13.2/favicon_red.png +0 -0
  100. data/coradoc-markdown/coverage/assets/0.13.2/favicon_yellow.png +0 -0
  101. data/coradoc-markdown/coverage/assets/0.13.2/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  102. data/coradoc-markdown/coverage/assets/0.13.2/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  103. data/coradoc-markdown/coverage/assets/0.13.2/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  104. data/coradoc-markdown/coverage/assets/0.13.2/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  105. data/coradoc-markdown/coverage/assets/0.13.2/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  106. data/coradoc-markdown/coverage/assets/0.13.2/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  107. data/coradoc-markdown/coverage/assets/0.13.2/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  108. data/coradoc-markdown/coverage/assets/0.13.2/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  109. data/coradoc-markdown/coverage/assets/0.13.2/images/ui-icons_222222_256x240.png +0 -0
  110. data/coradoc-markdown/coverage/assets/0.13.2/images/ui-icons_2e83ff_256x240.png +0 -0
  111. data/coradoc-markdown/coverage/assets/0.13.2/images/ui-icons_454545_256x240.png +0 -0
  112. data/coradoc-markdown/coverage/assets/0.13.2/images/ui-icons_888888_256x240.png +0 -0
  113. data/coradoc-markdown/coverage/assets/0.13.2/images/ui-icons_cd0a0a_256x240.png +0 -0
  114. data/coradoc-markdown/coverage/assets/0.13.2/loading.gif +0 -0
  115. data/coradoc-markdown/coverage/assets/0.13.2/magnify.png +0 -0
  116. data/coradoc-markdown/coverage/index.html +0 -66032
@@ -35,25 +35,30 @@ module Coradoc
35
35
  end
36
36
 
37
37
  def register_block_transformers!
38
- [
39
- [Coradoc::AsciiDoc::Model::Block::SourceCode, 'source'],
40
- [Coradoc::AsciiDoc::Model::Block::Quote, 'quote'],
41
- [Coradoc::AsciiDoc::Model::Block::Example, 'example'],
42
- [Coradoc::AsciiDoc::Model::Block::Side, 'sidebar'],
43
- [Coradoc::AsciiDoc::Model::Block::Literal, 'literal'],
44
- [Coradoc::AsciiDoc::Model::Block::Open, 'open'],
45
- [Coradoc::AsciiDoc::Model::Block::Pass, 'pass']
46
- ].each do |block_class, delimiter_type|
38
+ Registry.register_with_priority(
39
+ Coradoc::AsciiDoc::Model::Block::SourceCode,
40
+ METHOD_DISPATCH[:transform_source_block],
41
+ priority: 10
42
+ )
43
+
44
+ {
45
+ Coradoc::AsciiDoc::Model::Block::Quote => Coradoc::CoreModel::QuoteBlock,
46
+ Coradoc::AsciiDoc::Model::Block::Example => Coradoc::CoreModel::ExampleBlock,
47
+ Coradoc::AsciiDoc::Model::Block::Side => Coradoc::CoreModel::SidebarBlock,
48
+ Coradoc::AsciiDoc::Model::Block::Literal => Coradoc::CoreModel::LiteralBlock,
49
+ Coradoc::AsciiDoc::Model::Block::Open => Coradoc::CoreModel::OpenBlock,
50
+ Coradoc::AsciiDoc::Model::Block::Pass => Coradoc::CoreModel::PassBlock
51
+ }.each do |block_class, core_model_class|
47
52
  Registry.register_with_priority(
48
53
  block_class,
49
- block_wrapper(delimiter_type),
54
+ typed_block_wrapper(core_model_class),
50
55
  priority: 10
51
56
  )
52
57
  end
53
58
 
54
59
  Registry.register(
55
60
  Coradoc::AsciiDoc::Model::Block::Core,
56
- block_wrapper(nil) # uses model.delimiter at call time
61
+ block_model_wrapper
57
62
  )
58
63
 
59
64
  Registry.register(
@@ -200,16 +205,35 @@ module Coradoc
200
205
  end
201
206
  end
202
207
 
208
+ METHOD_DISPATCH = {
209
+ transform_document: ->(model) { ToCoreModel.transform_document(model) },
210
+ transform_section: ->(model) { ToCoreModel.transform_section(model) },
211
+ transform_paragraph: ->(model) { ToCoreModel.transform_paragraph(model) },
212
+ transform_source_block: ->(model) { ToCoreModel.transform_source_block(model) },
213
+ transform_link: ->(model) { ToCoreModel.transform_link(model) },
214
+ transform_cross_reference: ->(model) { ToCoreModel.transform_cross_reference(model) },
215
+ transform_inline_footnote: ->(model) { ToCoreModel.transform_inline_footnote(model) },
216
+ transform_stem: ->(model) { ToCoreModel.transform_stem(model) },
217
+ transform_table: ->(model) { ToCoreModel.transform_table(model) },
218
+ transform_table_row: ->(model) { ToCoreModel.transform_table_row(model) },
219
+ transform_table_cell: ->(model) { ToCoreModel.transform_table_cell(model) },
220
+ transform_term: ->(model) { ToCoreModel.transform_term(model) },
221
+ transform_admonition: ->(model) { ToCoreModel.transform_admonition(model) },
222
+ transform_image: ->(model) { ToCoreModel.transform_image(model) },
223
+ transform_bibliography: ->(model) { ToCoreModel.transform_bibliography(model) },
224
+ transform_bibliography_entry: ->(model) { ToCoreModel.transform_bibliography_entry(model) }
225
+ }.freeze
226
+
203
227
  def method_wrapper(method_name)
204
- ->(model) { ToCoreModel.public_send(method_name, model) }
228
+ METHOD_DISPATCH.fetch(method_name)
205
229
  end
206
230
 
207
- def block_wrapper(delimiter_type)
208
- if delimiter_type
209
- ->(model) { ToCoreModel.transform_block(model, delimiter_type) }
210
- else
211
- ->(model) { ToCoreModel.transform_block(model, model.delimiter) }
212
- end
231
+ def typed_block_wrapper(klass)
232
+ ->(model) { ToCoreModel.transform_typed_block(model, klass) }
233
+ end
234
+
235
+ def block_model_wrapper
236
+ ->(model) { ToCoreModel.transform_block(model, model.delimiter.to_s) }
213
237
  end
214
238
 
215
239
  def list_wrapper(marker_type)
@@ -123,7 +123,8 @@ module Coradoc
123
123
  delim_char: simple(:delim_char),
124
124
  rows: sequence(:rows)
125
125
  ) do
126
- Model::Table.new(id: id.to_s, title: title.to_s, rows: Transformer.regroup_table_rows(rows, attrs), attrs: attrs)
126
+ Model::Table.new(id: id.to_s, title: title.to_s, rows: Transformer.regroup_table_rows(rows, attrs),
127
+ attrs: attrs)
127
128
  end
128
129
 
129
130
  # Table with id and title (no attributes)
@@ -15,9 +15,14 @@ module Coradoc
15
15
  end
16
16
  end
17
17
 
18
- # Load version and parse_error (small files, needed immediately)
18
+ # Autoload version and parse error
19
19
  require_relative 'asciidoc/version'
20
- require_relative 'asciidoc/parse_error'
20
+
21
+ module Coradoc
22
+ module AsciiDoc
23
+ autoload :ParseError, "#{__dir__}/asciidoc/parse_error"
24
+ end
25
+ end
21
26
 
22
27
  # Autoload main components (lazy loading)
23
28
  module Coradoc
@@ -320,9 +320,7 @@ RSpec.describe 'Integration pipeline fixes' do
320
320
  el.children
321
321
  end
322
322
 
323
- if children
324
- children.each { |c| xrefs.concat(find_all_xrefs(c)) }
325
- end
323
+ children&.each { |c| xrefs.concat(find_all_xrefs(c)) }
326
324
 
327
325
  xrefs
328
326
  end
@@ -257,4 +257,3 @@ RSpec.describe 'Round-Trip Conversion' do
257
257
  end
258
258
  end
259
259
  end
260
- # rubocop:enable RSpec/DescribeClass
@@ -32,15 +32,16 @@ RSpec.describe Coradoc::AsciiDoc::Transform::FromCoreModel do
32
32
  end
33
33
 
34
34
  context 'with Block' do
35
- it 'transforms a CoreModel Block to AsciiDoc Block' do
35
+ it 'transforms a CoreModel Block to AsciiDoc Example Block' do
36
36
  core_block = Coradoc::CoreModel::Block.new(
37
+ block_semantic_type: :example,
37
38
  delimiter_type: '====',
38
39
  content: 'Example content'
39
40
  )
40
41
 
41
42
  result = described_class.transform(core_block)
42
43
 
43
- expect(result).to be_a(Coradoc::AsciiDoc::Model::Block::Core)
44
+ expect(result).to be_a(Coradoc::AsciiDoc::Model::Block::Example)
44
45
  end
45
46
  end
46
47
 
@@ -120,4 +120,3 @@ RSpec.describe 'Developer Experience API' do
120
120
  end
121
121
  end
122
122
  end
123
- # rubocop:enable RSpec/DescribeClass
@@ -41,18 +41,18 @@ RSpec.describe Coradoc::AsciiDoc::Transform::FromCoreModel do
41
41
  end
42
42
 
43
43
  context 'when transforming a block' do
44
- it 'transforms a CoreModel block to AsciiDoc' do
44
+ it 'transforms a CoreModel example block to AsciiDoc' do
45
45
  block = Coradoc::CoreModel::Block.new(
46
46
  id: 'example-1',
47
+ block_semantic_type: :example,
47
48
  delimiter_type: '====',
48
49
  content: "Line 1\nLine 2"
49
50
  )
50
51
 
51
52
  result = transformer.transform(block)
52
53
 
53
- expect(result).to be_a(Coradoc::AsciiDoc::Model::Block::Core)
54
+ expect(result).to be_a(Coradoc::AsciiDoc::Model::Block::Example)
54
55
  expect(result.id).to eq('example-1')
55
- expect(result.delimiter).to eq('====')
56
56
  end
57
57
  end
58
58
 
@@ -54,6 +54,7 @@ RSpec.describe Coradoc::AsciiDoc::Transform::ToCoreModel do
54
54
  result = transformer.transform(block)
55
55
 
56
56
  expect(result).to be_a(Coradoc::CoreModel::Block)
57
+ expect(result.block_semantic_type).to eq('example')
57
58
  expect(result.delimiter_type).to eq('====')
58
59
  expect(result.content).to eq("Line 1\nLine 2")
59
60
  end
@@ -169,40 +169,64 @@ module Coradoc
169
169
  # Get renderable content (children if present, otherwise content)
170
170
  renderable = block.renderable_content
171
171
 
172
- # Check element_type first for paragraph handling
173
- case block.element_type
174
- when 'paragraph'
172
+ semantic = resolve_block_semantic_type(block)
173
+
174
+ case semantic
175
+ when :paragraph
175
176
  content = convert_content_to_html(renderable, state)
176
177
  return "<p#{attrs}>#{content}</p>" if content && !content.empty?
177
178
 
178
179
  ''
179
- end
180
-
181
- # Then check delimiter_type for special blocks
182
- case block.delimiter_type
183
- when '----', 'source'
180
+ when :source_code
184
181
  lang = block.language || block.metadata&.dig(:language)
185
182
  lang_attr = lang ? " data-lang=\"#{escape_attribute(lang)}\"" : ''
186
183
  "<pre#{attrs}><code#{lang_attr}>#{escape_html(block.flat_text)}</code></pre>"
187
- when '____'
184
+ when :quote, :verse
188
185
  "<blockquote#{attrs}>#{convert_content_to_html(renderable, state)}</blockquote>"
189
- when '===='
186
+ when :example
190
187
  "<div class=\"example\"#{attrs}>#{convert_content_to_html(renderable, state)}</div>"
191
- when '****'
188
+ when :sidebar
192
189
  "<aside class=\"sidebar\"#{attrs}>#{convert_content_to_html(renderable, state)}</aside>"
193
- when '....'
190
+ when :literal
194
191
  "<pre class=\"literal\"#{attrs}>#{escape_html(block.flat_text)}</pre>"
195
- when '++++'
196
- block.flat_text # Pass through
197
- when 'comment'
198
- '' # Skip comments in output
199
- when '***', '---', '___'
192
+ when :pass
193
+ block.flat_text
194
+ when :listing
195
+ "<pre#{attrs}>#{escape_html(block.flat_text)}</pre>"
196
+ when :open
197
+ "<div#{attrs}>#{convert_content_to_html(renderable, state)}</div>"
198
+ when :verse
199
+ "<blockquote#{attrs}>#{convert_content_to_html(renderable, state)}</blockquote>"
200
+ when :comment, :reviewer
201
+ ''
202
+ when :horizontal_rule
200
203
  "<hr#{attrs}>"
201
204
  else
202
205
  "<div#{attrs}>#{convert_content_to_html(renderable, state)}</div>"
203
206
  end
204
207
  end
205
208
 
209
+ # Resolve the semantic type from a block via polymorphic dispatch.
210
+ # Block#resolve_semantic_type handles class-level semantic_type →
211
+ # block_semantic_type attribute → element_type → delimiter fallback.
212
+ def resolve_block_semantic_type(block)
213
+ block.resolve_semantic_type ||
214
+ resolve_format_specific_semantic(block)
215
+ end
216
+
217
+ # Format-specific semantic mappings not covered by the core model
218
+ def resolve_format_specific_semantic(block)
219
+ delim = block.delimiter_type
220
+ return nil unless delim && !delim.empty?
221
+
222
+ case delim
223
+ when "'''", '---', '___', '***' then :horizontal_rule
224
+ when '[verse]' then :verse
225
+ when 'comment' then :comment
226
+ when 'paragraph' then :paragraph
227
+ end
228
+ end
229
+
206
230
  # Render CoreModel structural element
207
231
  def render_core_structural_element(element, state = {})
208
232
  attrs = build_html_attributes(element.id, nil)
@@ -47,8 +47,7 @@ module Coradoc
47
47
  # Extract ID if present
48
48
  id = element['id']
49
49
 
50
- Coradoc::CoreModel::Block.new(
51
- delimiter_type: '====',
50
+ Coradoc::CoreModel::ExampleBlock.new(
52
51
  content: content,
53
52
  title: title,
54
53
  id: id
@@ -55,8 +55,7 @@ module Coradoc
55
55
  # Extract ID if present
56
56
  id = pre_elem['id'] || element['id']
57
57
 
58
- Coradoc::CoreModel::Block.new(
59
- delimiter_type: '----',
58
+ Coradoc::CoreModel::SourceBlock.new(
60
59
  content: content,
61
60
  title: title,
62
61
  id: id
@@ -58,8 +58,7 @@ module Coradoc
58
58
  # Extract ID if present
59
59
  id = pre_elem['id'] || element['id']
60
60
 
61
- Coradoc::CoreModel::Block.new(
62
- delimiter_type: '....',
61
+ Coradoc::CoreModel::LiteralBlock.new(
63
62
  content: content,
64
63
  title: title,
65
64
  id: id
@@ -39,8 +39,7 @@ module Coradoc
39
39
  # Extract ID if present
40
40
  id = element['id']
41
41
 
42
- Coradoc::CoreModel::Block.new(
43
- delimiter_type: '--',
42
+ Coradoc::CoreModel::OpenBlock.new(
44
43
  content: content,
45
44
  id: id
46
45
  )
@@ -43,11 +43,10 @@ module Coradoc
43
43
  # Extract ID if present
44
44
  id = element['id']
45
45
 
46
- Coradoc::CoreModel::Block.new(
47
- delimiter_type: '____',
46
+ Coradoc::CoreModel::QuoteBlock.new(
48
47
  content: content,
49
48
  id: id,
50
- metadata: attribution ? { attribution: attribution } : {}
49
+ attribution: attribution
51
50
  )
52
51
  end
53
52
 
@@ -46,8 +46,7 @@ module Coradoc
46
46
  # Extract ID if present
47
47
  id = element['id']
48
48
 
49
- Coradoc::CoreModel::Block.new(
50
- delimiter_type: '****',
49
+ Coradoc::CoreModel::SidebarBlock.new(
51
50
  content: content,
52
51
  title: title,
53
52
  id: id
@@ -63,8 +63,7 @@ module Coradoc
63
63
  # Extract ID if present
64
64
  id = code_elem['id'] || element['id']
65
65
 
66
- Coradoc::CoreModel::Block.new(
67
- delimiter_type: '----',
66
+ Coradoc::CoreModel::SourceBlock.new(
68
67
  content: content,
69
68
  title: title,
70
69
  id: id,
@@ -1,10 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
-
5
3
  module Coradoc
6
4
  module Html
7
5
  module Converters
6
+ autoload :Base, "#{__dir__}/base"
8
7
  # Converter for SourceCode blocks
9
8
  #
10
9
  # SourceCode models use the `lines` attribute, while Source models use `content`.
@@ -1,10 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
4
-
5
3
  module Coradoc
6
4
  module Html
7
5
  module Converters
6
+ autoload :Base, "#{__dir__}/base"
8
7
  # Converter for CoreModel::InlineElement (term) elements
9
8
  #
10
9
  # Terms are used in definition lists and can have types like "acronym",
@@ -50,12 +50,11 @@ module Coradoc
50
50
  # Extract ID if present
51
51
  id = element['id']
52
52
 
53
- Coradoc::CoreModel::Block.new(
54
- delimiter_type: '[verse]',
53
+ Coradoc::CoreModel::VerseBlock.new(
55
54
  content: content,
56
55
  title: title,
57
56
  id: id,
58
- metadata: attribution ? { attribution: attribution } : {}
57
+ attribution: attribution
59
58
  )
60
59
  end
61
60
 
@@ -10,7 +10,7 @@ module Coradoc
10
10
  # Use AnnotationBlock with annotation_type: "sidebar" for aside elements
11
11
  Coradoc::CoreModel::AnnotationBlock.new(
12
12
  annotation_type: 'sidebar',
13
- delimiter_type: '****',
13
+ block_semantic_type: :sidebar,
14
14
  children: content
15
15
  )
16
16
  end
@@ -16,7 +16,7 @@ module Coradoc
16
16
  # with element_attributes to store audio-specific data
17
17
  Coradoc::CoreModel::Block.new(
18
18
  element_type: 'audio',
19
- delimiter_type: 'audio',
19
+ block_semantic_type: :audio,
20
20
  content: src,
21
21
  title: title,
22
22
  id: id,
@@ -10,11 +10,10 @@ module Coradoc
10
10
  cite = node['cite']
11
11
  content = treat_children_coradoc(node, state)
12
12
 
13
- Coradoc::CoreModel::Block.new(
14
- delimiter_type: '____',
13
+ Coradoc::CoreModel::QuoteBlock.new(
15
14
  content: content,
16
15
  id: id,
17
- metadata: cite ? { attribution: cite } : {}
16
+ attribution: cite
18
17
  )
19
18
  end
20
19
  end
@@ -9,8 +9,7 @@ module Coradoc
9
9
  id = node['id']
10
10
  contents = treat_children_coradoc(node, state)
11
11
 
12
- Coradoc::CoreModel::Block.new(
13
- delimiter_type: '--',
12
+ Coradoc::CoreModel::OpenBlock.new(
14
13
  content: contents,
15
14
  id: id
16
15
  )
@@ -10,9 +10,8 @@ module Coradoc
10
10
  title_content = extract_title(node)
11
11
  content = treat_children_coradoc(node, state)
12
12
 
13
- # Use CoreModel::Block with delimiter_type "====" for example/figure
14
- Coradoc::CoreModel::Block.new(
15
- delimiter_type: '====',
13
+ # Use CoreModel::ExampleBlock for example/figure
14
+ Coradoc::CoreModel::ExampleBlock.new(
16
15
  title: extract_text_from_content(title_content),
17
16
  children: content,
18
17
  id: id
@@ -8,7 +8,7 @@ module Coradoc
8
8
  def to_coradoc(_node, _state = {})
9
9
  Coradoc::CoreModel::Block.new(
10
10
  element_type: 'thematic_break',
11
- delimiter_type: "'''"
11
+ block_semantic_type: :horizontal_rule
12
12
  )
13
13
  end
14
14
  end
@@ -13,7 +13,8 @@ module Coradoc
13
13
  content = strip_fullwidth_spaces(content)
14
14
 
15
15
  Coradoc::CoreModel::Block.new(
16
- delimiter_type: 'paragraph',
16
+ block_semantic_type: :paragraph,
17
+ element_type: 'paragraph',
17
18
  children: content,
18
19
  id: id
19
20
  )
@@ -10,16 +10,20 @@ module Coradoc
10
10
  lang = language(node)
11
11
  content = extract_text_content(node)
12
12
 
13
- delimiter_type = lang ? '----' : '....'
14
- element_type = lang ? 'source' : 'literal'
15
-
16
- Coradoc::CoreModel::Block.new(
17
- element_type: element_type,
18
- delimiter_type: delimiter_type,
19
- content: content,
20
- id: id,
21
- language: lang
22
- )
13
+ if lang
14
+ Coradoc::CoreModel::SourceBlock.new(
15
+ element_type: 'source',
16
+ content: content,
17
+ id: id,
18
+ language: lang
19
+ )
20
+ else
21
+ Coradoc::CoreModel::LiteralBlock.new(
22
+ element_type: 'literal',
23
+ content: content,
24
+ id: id
25
+ )
26
+ end
23
27
  end
24
28
 
25
29
  private
@@ -16,7 +16,7 @@ module Coradoc
16
16
  # with element_attributes to store video-specific data
17
17
  Coradoc::CoreModel::Block.new(
18
18
  element_type: 'video',
19
- delimiter_type: 'video',
19
+ block_semantic_type: :video,
20
20
  content: src,
21
21
  title: title,
22
22
  id: id,
@@ -42,13 +42,23 @@ module Coradoc
42
42
  'Coradoc::CoreModel::BibliographyEntry' => 'bibliography_entry',
43
43
  'Coradoc::CoreModel::StructuralElement' => 'structural_element',
44
44
  'Coradoc::CoreModel::Block' => 'block',
45
+ 'Coradoc::CoreModel::SourceBlock' => 'source_block',
46
+ 'Coradoc::CoreModel::ExampleBlock' => 'example_block',
47
+ 'Coradoc::CoreModel::QuoteBlock' => 'quote_block',
48
+ 'Coradoc::CoreModel::SidebarBlock' => 'sidebar_block',
49
+ 'Coradoc::CoreModel::LiteralBlock' => 'literal_block',
50
+ 'Coradoc::CoreModel::PassBlock' => 'pass_block',
51
+ 'Coradoc::CoreModel::ListingBlock' => 'listing_block',
52
+ 'Coradoc::CoreModel::OpenBlock' => 'open_block',
53
+ 'Coradoc::CoreModel::VerseBlock' => 'verse_block',
54
+ 'Coradoc::CoreModel::ReviewerBlock' => 'reviewer_block',
55
+ 'Coradoc::CoreModel::AnnotationBlock' => 'annotation_block',
45
56
  'Coradoc::CoreModel::ListBlock' => 'list_block',
46
57
  'Coradoc::CoreModel::ListItem' => 'list_item',
47
58
  'Coradoc::CoreModel::Table' => 'table',
48
59
  'Coradoc::CoreModel::TableRow' => 'table_row',
49
60
  'Coradoc::CoreModel::TableCell' => 'table_cell',
50
61
  'Coradoc::CoreModel::Image' => 'image',
51
- 'Coradoc::CoreModel::AnnotationBlock' => 'annotation_block',
52
62
  'Coradoc::CoreModel::InlineElement' => 'inline_element',
53
63
  'Coradoc::CoreModel::Paragraph' => 'paragraph',
54
64
  'Coradoc::CoreModel::Term' => 'term',
@@ -125,6 +135,37 @@ module Coradoc
125
135
  end
126
136
  end
127
137
 
138
+ # Render a CoreModel element as a complete HTML5 document
139
+ #
140
+ # Wraps the fragment output of #render in a proper HTML5 document
141
+ # with DOCTYPE, charset, and viewport meta tags.
142
+ #
143
+ # @param element [Coradoc::CoreModel::Base] The element to render
144
+ # @param options [Hash] Document-level options
145
+ # @option options [String] :lang Document language (default: "en")
146
+ # @option options [String] :title Document title (default: extracted from element)
147
+ # @return [String] Complete HTML5 document
148
+ def render_html5(element, options = {})
149
+ body_html = render(element)
150
+
151
+ lang = options[:lang] || 'en'
152
+ title = options[:title] || extract_title(element) || 'Untitled Document'
153
+
154
+ <<~HTML
155
+ <!DOCTYPE html>
156
+ <html lang="#{lang}">
157
+ <head>
158
+ <meta charset="UTF-8">
159
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
160
+ <title>#{escape_html(title)}</title>
161
+ </head>
162
+ <body>
163
+ #{body_html}
164
+ </body>
165
+ </html>
166
+ HTML
167
+ end
168
+
128
169
  # Get list of all available template names
129
170
  #
130
171
  # @return [Array<String>] List of template names (without .liquid extension)
@@ -318,7 +359,7 @@ module Coradoc
318
359
  assigns = {}
319
360
 
320
361
  # Common attributes that most CoreModel types have
321
- %w[id title content children element_type language lines
362
+ %w[id title content children element_type block_semantic_type language lines
322
363
  delimiter_type delimiter_length metadata_entries element_attributes
323
364
  text href alt src level entries items rows cells
324
365
  anchor term definition abbreviations].each do |key|
@@ -353,6 +394,13 @@ module Coradoc
353
394
  .gsub(/"/, '&quot;')
354
395
  .gsub(/'/, '&#39;')
355
396
  end
397
+
398
+ def extract_title(element)
399
+ return nil unless element
400
+ return element.title if element.is_a?(Coradoc::CoreModel::StructuralElement) && element.title
401
+
402
+ nil
403
+ end
356
404
  end
357
405
 
358
406
  # Backwards compatibility alias
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'converter_base'
4
-
5
3
  module Coradoc
6
4
  module Html
5
+ autoload :ConverterBase, "#{__dir__}/converter_base"
6
+
7
7
  # SPA (Single Page Application) HTML converter
8
8
  #
9
9
  # Converts Coradoc::CoreModel::StructuralElement to a modern Vue.js + Tailwind CSS
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'converter_base'
4
-
5
3
  module Coradoc
6
4
  module Html
5
+ autoload :ConverterBase, "#{__dir__}/converter_base"
6
+
7
7
  # Static HTML converter
8
8
  #
9
9
  # Converts CoreModel documents to static HTML5 output.
@@ -0,0 +1,11 @@
1
+ {%- comment -%}
2
+ Definition list template
3
+ {%- endcomment -%}
4
+ <dl id="{{ id }}" class="definition-list">
5
+ {%- for item in items -%}
6
+ <dt>{{ item.term }}</dt>
7
+ {%- for def in item.definitions -%}
8
+ <dd>{{ def }}</dd>
9
+ {%- endfor -%}
10
+ {%- endfor -%}
11
+ </dl>