coradoc-markdown 1.0.2 → 1.0.4

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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/lib/coradoc/markdown/model/admonition.rb +41 -0
  3. data/lib/coradoc/markdown/model/comment.rb +14 -0
  4. data/lib/coradoc/markdown/model/definition_term.rb +16 -6
  5. data/lib/coradoc/markdown/model/document.rb +9 -0
  6. data/lib/coradoc/markdown/model/example_block.rb +26 -0
  7. data/lib/coradoc/markdown/model/hard_line_break.rb +21 -0
  8. data/lib/coradoc/markdown/model/horizontal_rule.rb +1 -6
  9. data/lib/coradoc/markdown/model/list_item.rb +1 -1
  10. data/lib/coradoc/markdown/model/literal.rb +21 -0
  11. data/lib/coradoc/markdown/model/open_block.rb +22 -0
  12. data/lib/coradoc/markdown/model/paragraph.rb +2 -2
  13. data/lib/coradoc/markdown/model/pass.rb +21 -0
  14. data/lib/coradoc/markdown/model/sidebar.rb +22 -0
  15. data/lib/coradoc/markdown/model/verse.rb +27 -0
  16. data/lib/coradoc/markdown/parser/block_parser.rb +1 -1
  17. data/lib/coradoc/markdown/parser/frontmatter_parser.rb +23 -0
  18. data/lib/coradoc/markdown/serializer/builder.rb +57 -0
  19. data/lib/coradoc/markdown/serializer/config.rb +77 -0
  20. data/lib/coradoc/markdown/serializer/context.rb +66 -0
  21. data/lib/coradoc/markdown/serializer/element_serializer.rb +46 -0
  22. data/lib/coradoc/markdown/serializer/flavor.rb +82 -0
  23. data/lib/coradoc/markdown/serializer/registrations.rb +111 -0
  24. data/lib/coradoc/markdown/serializer/registry.rb +62 -0
  25. data/lib/coradoc/markdown/serializer/runner.rb +84 -0
  26. data/lib/coradoc/markdown/serializer/serializers/abbreviation.rb +19 -0
  27. data/lib/coradoc/markdown/serializer/serializers/admonition.rb +20 -0
  28. data/lib/coradoc/markdown/serializer/serializers/attribute_list.rb +25 -0
  29. data/lib/coradoc/markdown/serializer/serializers/blockquote.rb +19 -0
  30. data/lib/coradoc/markdown/serializer/serializers/code.rb +19 -0
  31. data/lib/coradoc/markdown/serializer/serializers/code_block.rb +19 -0
  32. data/lib/coradoc/markdown/serializer/serializers/comment.rb +31 -0
  33. data/lib/coradoc/markdown/serializer/serializers/cross_reference.rb +19 -0
  34. data/lib/coradoc/markdown/serializer/serializers/definition_list.rb +20 -0
  35. data/lib/coradoc/markdown/serializer/serializers/document.rb +22 -0
  36. data/lib/coradoc/markdown/serializer/serializers/emphasis.rb +19 -0
  37. data/lib/coradoc/markdown/serializer/serializers/example_block.rb +40 -0
  38. data/lib/coradoc/markdown/serializer/serializers/extension.rb +30 -0
  39. data/lib/coradoc/markdown/serializer/serializers/footnote.rb +20 -0
  40. data/lib/coradoc/markdown/serializer/serializers/footnote_reference.rb +19 -0
  41. data/lib/coradoc/markdown/serializer/serializers/hard_line_break.rb +22 -0
  42. data/lib/coradoc/markdown/serializer/serializers/heading.rb +19 -0
  43. data/lib/coradoc/markdown/serializer/serializers/highlight.rb +19 -0
  44. data/lib/coradoc/markdown/serializer/serializers/horizontal_rule.rb +19 -0
  45. data/lib/coradoc/markdown/serializer/serializers/image.rb +19 -0
  46. data/lib/coradoc/markdown/serializer/serializers/link.rb +29 -0
  47. data/lib/coradoc/markdown/serializer/serializers/list.rb +45 -0
  48. data/lib/coradoc/markdown/serializer/serializers/literal.rb +21 -0
  49. data/lib/coradoc/markdown/serializer/serializers/math.rb +23 -0
  50. data/lib/coradoc/markdown/serializer/serializers/open_block.rb +38 -0
  51. data/lib/coradoc/markdown/serializer/serializers/paragraph.rb +23 -0
  52. data/lib/coradoc/markdown/serializer/serializers/pass.rb +21 -0
  53. data/lib/coradoc/markdown/serializer/serializers/sidebar.rb +20 -0
  54. data/lib/coradoc/markdown/serializer/serializers/strikethrough.rb +19 -0
  55. data/lib/coradoc/markdown/serializer/serializers/strong.rb +19 -0
  56. data/lib/coradoc/markdown/serializer/serializers/subscript.rb +19 -0
  57. data/lib/coradoc/markdown/serializer/serializers/superscript.rb +19 -0
  58. data/lib/coradoc/markdown/serializer/serializers/table.rb +37 -0
  59. data/lib/coradoc/markdown/serializer/serializers/underline.rb +19 -0
  60. data/lib/coradoc/markdown/serializer/serializers/verse.rb +31 -0
  61. data/lib/coradoc/markdown/serializer/strategies/admonition/base.rb +41 -0
  62. data/lib/coradoc/markdown/serializer/strategies/admonition/container.rb +34 -0
  63. data/lib/coradoc/markdown/serializer/strategies/admonition/gfm_alert.rb +28 -0
  64. data/lib/coradoc/markdown/serializer/strategies/admonition/github.rb +27 -0
  65. data/lib/coradoc/markdown/serializer/strategies/admonition/html.rb +25 -0
  66. data/lib/coradoc/markdown/serializer/strategies/admonition/registry.rb +50 -0
  67. data/lib/coradoc/markdown/serializer/strategies/autolink/angle.rb +35 -0
  68. data/lib/coradoc/markdown/serializer/strategies/autolink/bare.rb +23 -0
  69. data/lib/coradoc/markdown/serializer/strategies/autolink/base.rb +33 -0
  70. data/lib/coradoc/markdown/serializer/strategies/autolink/none.rb +27 -0
  71. data/lib/coradoc/markdown/serializer/strategies/autolink/registry.rb +58 -0
  72. data/lib/coradoc/markdown/serializer/strategies/definition_list/base.rb +37 -0
  73. data/lib/coradoc/markdown/serializer/strategies/definition_list/flat.rb +48 -0
  74. data/lib/coradoc/markdown/serializer/strategies/definition_list/nested_html.rb +54 -0
  75. data/lib/coradoc/markdown/serializer/strategies/definition_list/registry.rb +37 -0
  76. data/lib/coradoc/markdown/serializer.rb +29 -243
  77. data/lib/coradoc/markdown/toc_generator.rb +2 -2
  78. data/lib/coradoc/markdown/transform/block_transformer.rb +163 -0
  79. data/lib/coradoc/markdown/transform/from_core_model.rb +195 -28
  80. data/lib/coradoc/markdown/transform/image_transformer.rb +20 -0
  81. data/lib/coradoc/markdown/transform/inline_transformer.rb +74 -0
  82. data/lib/coradoc/markdown/transform/list_transformer.rb +52 -0
  83. data/lib/coradoc/markdown/transform/structural_transformer.rb +94 -0
  84. data/lib/coradoc/markdown/transform/table_transformer.rb +40 -0
  85. data/lib/coradoc/markdown/transform/to_core_model.rb +24 -3
  86. data/lib/coradoc/markdown/transformer.rb +87 -2
  87. data/lib/coradoc/markdown/version.rb +1 -1
  88. data/lib/coradoc/markdown.rb +16 -2
  89. metadata +75 -1
@@ -20,6 +20,9 @@ module Coradoc
20
20
  when Coradoc::CoreModel::AnnotationBlock
21
21
  # Must be checked before Block since AnnotationBlock < Block
22
22
  transform_annotation_block(model)
23
+ when Coradoc::CoreModel::CommentBlock
24
+ # Must be checked before Block since CommentBlock < Block
25
+ Coradoc::Markdown::Comment.new(text: model.content.to_s)
23
26
  when Coradoc::CoreModel::Block
24
27
  transform_block(model)
25
28
  when Coradoc::CoreModel::ListBlock
@@ -48,8 +51,12 @@ module Coradoc
48
51
  transform_bibliography_entry(model)
49
52
  when Coradoc::CoreModel::TocEntry
50
53
  Coradoc::Markdown::Text.new(content: model.title.to_s)
54
+ when Coradoc::CoreModel::CommentLine
55
+ Coradoc::Markdown::Comment.new(text: model.text.to_s)
56
+ when Coradoc::CoreModel::TextContent
57
+ model.text.to_s
51
58
  when Array
52
- model.map { |item| transform(item) }
59
+ model.flat_map { |item| flatten_result(transform(item)) }
53
60
  else
54
61
  model
55
62
  end
@@ -69,23 +76,39 @@ module Coradoc
69
76
  end
70
77
 
71
78
  def transform_document(doc)
72
- blocks = Array(doc.children).map { |child| transform(child) }
79
+ blocks, frontmatter = extract_frontmatter(Array(doc.children))
80
+ blocks = blocks.flat_map { |child| flatten_result(transform(child)) }
73
81
 
74
82
  Coradoc::Markdown::Document.new(
75
83
  id: doc.id,
76
- blocks: blocks
84
+ blocks: blocks,
85
+ frontmatter: frontmatter
77
86
  )
78
87
  end
79
88
 
89
+ # If the first CoreModel child is a FrontmatterBlock, serialize
90
+ # it to YAML text via Codec (single source of truth) and pop
91
+ # it from the children list. Returns [remaining_children,
92
+ # frontmatter_text].
93
+ def extract_frontmatter(children)
94
+ first = children.first
95
+ return [children, nil] unless first.is_a?(CoreModel::FrontmatterBlock)
96
+
97
+ yaml = CoreModel::FrontmatterBlock::Codec.to_yaml(first)
98
+ [children.drop(1), yaml.nil? || yaml.empty? ? nil : yaml]
99
+ end
100
+
80
101
  def transform_section(section)
81
- Coradoc::Markdown::Heading.new(
102
+ heading = Coradoc::Markdown::Heading.new(
82
103
  level: section.level || 1,
83
104
  text: section.title.to_s
84
105
  )
106
+ child_blocks = Array(section.children).map { |child| transform(child) }
107
+ [heading, *child_blocks]
85
108
  end
86
109
 
87
110
  def transform_generic_element(element)
88
- blocks = Array(element.children).map { |child| transform(child) }
111
+ blocks = Array(element.children).flat_map { |child| flatten_result(transform(child)) }
89
112
 
90
113
  Coradoc::Markdown::Document.new(
91
114
  id: element.id,
@@ -99,7 +122,7 @@ module Coradoc
99
122
  when :paragraph
100
123
  transform_paragraph(block)
101
124
  when :comment
102
- Coradoc::Markdown::Extension.comment(block.content.to_s)
125
+ Coradoc::Markdown::Comment.new(text: block.content.to_s)
103
126
  else
104
127
  transform_delimited_block(block)
105
128
  end
@@ -107,8 +130,17 @@ module Coradoc
107
130
 
108
131
  def transform_paragraph(block)
109
132
  content = block.renderable_content
110
- has_structured = content.is_a?(Array) && content.any? { |c| !c.is_a?(CoreModel::TextContent) }
111
- if has_structured
133
+ has_nested_blocks = content.is_a?(Array) && content.any? do |c|
134
+ c.is_a?(CoreModel::Block) || c.is_a?(CoreModel::StructuralElement)
135
+ end
136
+ if has_nested_blocks
137
+ content.filter_map do |c|
138
+ next c.text if c.is_a?(CoreModel::TextContent)
139
+ next nil if c.is_a?(String) && c.strip.empty?
140
+
141
+ transform(c)
142
+ end.flat_map { |c| flatten_result(c) }
143
+ elsif content.is_a?(Array) && content.any? { |c| !c.is_a?(CoreModel::TextContent) }
112
144
  children = content.map { |c| transform_inline_content(c) }
113
145
  Coradoc::Markdown::Paragraph.new(text: block.flat_text, children: children)
114
146
  else
@@ -122,32 +154,122 @@ module Coradoc
122
154
  transform_inline(element)
123
155
  when CoreModel::TextContent
124
156
  element.text
157
+ when CoreModel::Base
158
+ transform(element)
125
159
  when String
126
160
  element
161
+ when Array
162
+ element.map { |e| transform_inline_content(e) }
127
163
  else
128
164
  element.to_s
129
165
  end
130
166
  end
131
167
 
168
+ def transform_inline_array(renderable)
169
+ return [] unless renderable.is_a?(Array)
170
+
171
+ renderable.map { |c| transform_inline_content(c) }
172
+ end
173
+
132
174
  def transform_delimited_block(block)
133
175
  semantic = resolve_markdown_semantic(block)
134
176
 
135
177
  case semantic
136
178
  when :source_code, :listing
137
179
  transform_code_block(block)
138
- when :quote, :verse
180
+ when :quote
139
181
  transform_blockquote(block)
182
+ when :verse
183
+ transform_verse_block(block)
140
184
  when :horizontal_rule
141
185
  transform_horizontal_rule(block)
142
186
  when :pass
143
- Coradoc::Markdown::Extension.nomarkdown(block.content.to_s)
187
+ transform_pass_block(block)
144
188
  when :literal
145
- transform_code_block(block)
189
+ transform_literal_block(block)
190
+ when :example
191
+ transform_example_block(block)
192
+ when :sidebar
193
+ transform_sidebar_block(block)
194
+ when :open
195
+ transform_open_block(block)
196
+ when :reviewer
197
+ transform_admonition_block(block, default_type: 'reviewer')
146
198
  else
147
199
  transform_paragraph(block)
148
200
  end
149
201
  end
150
202
 
203
+ def transform_container_block(block)
204
+ rc = block.renderable_content
205
+ if rc.is_a?(Array) && rc.any? { |c| c.is_a?(CoreModel::Block) || c.is_a?(CoreModel::ListBlock) }
206
+ rc.filter_map do |c|
207
+ next c.text if c.is_a?(CoreModel::TextContent)
208
+ next nil if c.is_a?(String) && c.strip.empty?
209
+
210
+ transform(c)
211
+ end.flat_map { |c| flatten_result(c) }
212
+ else
213
+ Coradoc::Markdown::Blockquote.new(content: block.flat_text)
214
+ end
215
+ end
216
+
217
+ def transform_verse_block(block)
218
+ Coradoc::Markdown::Verse.new(
219
+ content: block.flat_text,
220
+ attribution: block.respond_to?(:attribution) ? block.attribution : nil
221
+ )
222
+ end
223
+
224
+ def transform_pass_block(block)
225
+ return Coradoc::Markdown::Math.block(block.content.to_s) if block.language == 'latexmath'
226
+
227
+ Coradoc::Markdown::Pass.new(content: block.content.to_s)
228
+ end
229
+
230
+ def transform_literal_block(block)
231
+ Coradoc::Markdown::Literal.new(content: block.content.to_s)
232
+ end
233
+
234
+ def transform_example_block(block)
235
+ Coradoc::Markdown::ExampleBlock.new(
236
+ content: block.flat_text,
237
+ caption: block.title.to_s
238
+ )
239
+ end
240
+
241
+ def transform_sidebar_block(block)
242
+ Coradoc::Markdown::Sidebar.new(
243
+ content: block.flat_text,
244
+ title: block.title.to_s
245
+ )
246
+ end
247
+
248
+ def transform_open_block(block)
249
+ children = Array(block.children).map { |c| transform(c) }.flat_map { |c| flatten_result(c) }
250
+ children = paragraphs_from_content(block.content) if children.empty?
251
+ Coradoc::Markdown::OpenBlock.new(
252
+ children: children,
253
+ id: block.id
254
+ )
255
+ end
256
+
257
+ def paragraphs_from_content(content)
258
+ content.to_s.split(/\n\s*\n/).map do |chunk|
259
+ Coradoc::Markdown::Paragraph.new(text: chunk.strip)
260
+ end
261
+ end
262
+
263
+ def transform_admonition_block(block, default_type: 'note')
264
+ children = transform_inline_array(block.renderable_content)
265
+ Coradoc::Markdown::Admonition.new(
266
+ admonition_type: block.respond_to?(:annotation_type) ? (block.annotation_type || default_type) : default_type,
267
+ content: block.flat_text,
268
+ title: block.respond_to?(:annotation_label) ? block.annotation_label : nil,
269
+ children: children
270
+ )
271
+ end
272
+
151
273
  def resolve_markdown_semantic(block)
152
274
  # Polymorphic dispatch: typed classes override semantic_type
153
275
  semantic = block.resolve_semantic_type
@@ -167,10 +289,21 @@ module Coradoc
167
289
  end
168
290
 
169
291
  def transform_code_block(block)
170
- Coradoc::Markdown::CodeBlock.new(
171
- code: block.content.to_s,
292
+ code = CoreModel::CalloutText.strip_markers(block.content.to_s, block.callouts)
293
+ code_block = Coradoc::Markdown::CodeBlock.new(
294
+ code: code,
172
295
  language: block.language
173
296
  )
297
+ return code_block if block.callouts.nil? || block.callouts.empty?
298
+
299
+ [code_block, transform_callout_list(block.callouts)]
300
+ end
301
+
302
+ def transform_callout_list(callouts)
303
+ items = CoreModel::CalloutText.ordered(callouts).map do |callout|
304
+ Coradoc::Markdown::ListItem.new(text: callout.content.to_s)
305
+ end
306
+ Coradoc::Markdown::List.new(ordered: true, items: items)
174
307
  end
175
308
 
176
309
  def transform_blockquote(block)
@@ -180,19 +313,21 @@ module Coradoc
180
313
  end
181
314
 
182
315
  def transform_horizontal_rule(_block)
183
- Coradoc::Markdown::HorizontalRule.new
316
+ Coradoc::Markdown::HorizontalRule.new(style: '---')
184
317
  end
185
318
 
186
319
  def transform_list(list)
187
320
  items = Array(list.items).map do |item|
188
321
  content = item.renderable_content
189
322
  has_structured = content.is_a?(Array) && content.any? { |c| !c.is_a?(CoreModel::TextContent) }
190
- if has_structured
191
- children = content.map { |c| transform_inline_content(c) }
192
- Coradoc::Markdown::ListItem.new(text: item.flat_text, children: children)
193
- else
194
- Coradoc::Markdown::ListItem.new(text: item.flat_text)
195
- end
323
+ md_item = if has_structured
324
+ children = content.map { |c| transform_inline_content(c) }
325
+ Coradoc::Markdown::ListItem.new(text: item.flat_text, children: children)
326
+ else
327
+ Coradoc::Markdown::ListItem.new(text: item.flat_text)
328
+ end
329
+ md_item.sublist = transform_list(item.nested_list) if item.nested_list
330
+ md_item
196
331
  end
197
332
 
198
333
  Coradoc::Markdown::List.new(
@@ -211,8 +346,8 @@ module Coradoc
211
346
  first_row = table_rows.first
212
347
  first_row_cells = Array(first_row&.cells)
213
348
 
214
- # Check if first row has header cells
215
- if first_row_cells.any?(&:header)
349
+ # Check if first row is marked as header, or if any of its cells are header cells
350
+ if first_row&.header || first_row_cells.any?(&:header)
216
351
  headers = first_row_cells.map(&:flat_text)
217
352
  table_rows = table_rows[1..] || []
218
353
  end
@@ -278,9 +413,11 @@ module Coradoc
278
413
  definitions = Array(item.definitions).map do |defn|
279
414
  Coradoc::Markdown::DefinitionItem.new(content: defn.to_s)
280
415
  end
416
+ nested = item.nested ? transform_definition_list(item.nested) : nil
281
417
  Coradoc::Markdown::DefinitionTerm.new(
282
418
  text: item.term.to_s,
283
- definitions: definitions
419
+ definitions: definitions,
420
+ nested: nested
284
421
  )
285
422
  end
286
423
 
@@ -307,10 +444,7 @@ module Coradoc
307
444
  end
308
445
 
309
446
  def transform_annotation_block(annotation)
310
- text = annotation.flat_text
311
- Coradoc::Markdown::Paragraph.new(
312
- text: "**#{annotation.annotation_type}:** #{text}"
313
- )
447
+ transform_admonition_block(annotation, default_type: 'note')
314
448
  end
315
449
 
316
450
  def transform_bibliography(bib)
@@ -322,7 +456,40 @@ module Coradoc
322
456
  end
323
457
 
324
458
  def transform_bibliography_entry(entry)
325
- Coradoc::Markdown::Paragraph.new(text: entry.display_text)
459
+ text = entry.display_text.to_s
460
+ text = convert_asciidoc_markers_to_markdown(text)
461
+ Coradoc::Markdown::Paragraph.new(text: text)
462
+ end
463
+
464
+ def convert_asciidoc_markers_to_markdown(text)
465
+ return '' if text.nil?
466
+
467
+ result = text.dup
468
+
469
+ # footnote:[text] -> ^[text]
470
+ result.gsub!(/footnote:\[(.*?)\]/, '^[\1]')
471
+
472
+ # [smallcap]#text# -> text
473
+ result.gsub!(/\[smallcap\]#(.*?)#/, '\1')
474
+
475
+ # *text* -> **text**
476
+ # Use negative lookbehind and lookahead to avoid replacing **text** to ****text****
477
+ result.gsub!(/(?<!\*)\*(.*?)\*(?!\*)/, '**\1**')
478
+
479
+ # _text_ -> *text*
480
+ # Use negative lookbehind and lookahead to avoid replacing __text__ to **text**
481
+ result.gsub!(/(?<!_)_(.*?)_(?!_)/, '*\1*')
482
+
483
+ result
484
+ end
485
+
486
+ def flatten_result(result)
487
+ case result
488
+ when Array
489
+ result.flat_map { |r| flatten_result(r) }
490
+ else
491
+ [result]
492
+ end
326
493
  end
327
494
  end
328
495
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Markdown
5
+ module Transform
6
+ module ImageTransformer
7
+ class << self
8
+ def transform_image(image)
9
+ Coradoc::Markdown::Image.new(
10
+ src: image.src,
11
+ alt: image.alt.to_s
12
+ )
13
+ end
14
+ end
15
+
16
+ FromCoreModel.register(CoreModel::Image, method(:transform_image))
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Markdown
5
+ module Transform
6
+ module InlineTransformer
7
+ class << self
8
+ def transform_inline(element)
9
+ case element.resolve_format_type
10
+ when 'bold'
11
+ Coradoc::Markdown::Strong.new(text: element.content.to_s)
12
+ when 'italic'
13
+ Coradoc::Markdown::Emphasis.new(text: element.content.to_s)
14
+ when 'monospace'
15
+ Coradoc::Markdown::Code.new(text: element.content.to_s)
16
+ when 'link'
17
+ Coradoc::Markdown::Link.new(
18
+ text: element.content.to_s,
19
+ url: element.target.to_s
20
+ )
21
+ when 'footnote'
22
+ Coradoc::Markdown::FootnoteReference.new(id: element.target.to_s)
23
+ when 'stem'
24
+ Coradoc::Markdown::Math.inline(element.content.to_s)
25
+ when 'highlight'
26
+ Coradoc::Markdown::Highlight.new(text: element.content.to_s)
27
+ when 'strikethrough'
28
+ Coradoc::Markdown::Strikethrough.new(text: element.content.to_s)
29
+ when 'subscript'
30
+ Coradoc::Markdown::Subscript.new(text: element.content.to_s)
31
+ when 'superscript'
32
+ Coradoc::Markdown::Superscript.new(text: element.content.to_s)
33
+ when 'underline'
34
+ Coradoc::Markdown::Underline.new(text: element.content.to_s)
35
+ when 'xref'
36
+ Coradoc::Markdown::CrossReference.new(
37
+ text: element.content.to_s,
38
+ target: element.target.to_s
39
+ )
40
+ else
41
+ element.content.to_s
42
+ end
43
+ end
44
+
45
+ def transform_footnote(fn)
46
+ Coradoc::Markdown::Footnote.new(
47
+ id: fn.id.to_s,
48
+ content: fn.content.to_s,
49
+ backlink: fn.backlink
50
+ )
51
+ end
52
+
53
+ def transform_footnote_reference(ref)
54
+ Coradoc::Markdown::FootnoteReference.new(id: ref.id.to_s)
55
+ end
56
+
57
+ def transform_abbreviation(abbr)
58
+ Coradoc::Markdown::Abbreviation.new(
59
+ term: abbr.term.to_s,
60
+ definition: abbr.definition.to_s
61
+ )
62
+ end
63
+ end
64
+
65
+ FromCoreModel.register(CoreModel::InlineElement, method(:transform_inline))
66
+ FromCoreModel.register(CoreModel::Footnote, method(:transform_footnote))
67
+ FromCoreModel.register(CoreModel::FootnoteReference, method(:transform_footnote_reference))
68
+ FromCoreModel.register(CoreModel::Abbreviation, method(:transform_abbreviation))
69
+ FromCoreModel.register(CoreModel::TextContent, lambda(&:text))
70
+ FromCoreModel.register(CoreModel::Term, ->(m) { Coradoc::Markdown::Strong.new(text: m.text.to_s) })
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Markdown
5
+ module Transform
6
+ module ListTransformer
7
+ class << self
8
+ def transform_list(list)
9
+ items = Array(list.items).map do |item|
10
+ transform_list_item(item)
11
+ end
12
+
13
+ Coradoc::Markdown::List.new(
14
+ ordered: list.marker_type == 'ordered',
15
+ items: items
16
+ )
17
+ end
18
+
19
+ def transform_list_item(item)
20
+ content = item.renderable_content
21
+ has_structured = content.is_a?(Array) && content.any? do |c|
22
+ !c.is_a?(CoreModel::TextContent)
23
+ end
24
+ if has_structured
25
+ children = content.map { |c| BlockTransformer.transform_content_node(c) }
26
+ Coradoc::Markdown::ListItem.new(text: item.flat_text, children: children)
27
+ else
28
+ Coradoc::Markdown::ListItem.new(text: item.flat_text)
29
+ end
30
+ end
31
+
32
+ def transform_definition_list(dl)
33
+ items = Array(dl.items).map do |item|
34
+ definitions = Array(item.definitions).map do |defn|
35
+ Coradoc::Markdown::DefinitionItem.new(content: defn.to_s)
36
+ end
37
+ Coradoc::Markdown::DefinitionTerm.new(
38
+ text: item.term.to_s,
39
+ definitions: definitions
40
+ )
41
+ end
42
+
43
+ Coradoc::Markdown::DefinitionList.new(items: items)
44
+ end
45
+ end
46
+
47
+ FromCoreModel.register(CoreModel::ListBlock, method(:transform_list))
48
+ FromCoreModel.register(CoreModel::DefinitionList, method(:transform_definition_list))
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Markdown
5
+ module Transform
6
+ module StructuralTransformer
7
+ class << self
8
+ def transform_structural_element(element)
9
+ case element
10
+ when CoreModel::DocumentElement
11
+ transform_document(element)
12
+ when CoreModel::SectionElement
13
+ transform_section(element)
14
+ when CoreModel::PreambleElement
15
+ transform_preamble(element)
16
+ when CoreModel::HeaderElement
17
+ transform_header(element)
18
+ else
19
+ transform_generic_element(element)
20
+ end
21
+ end
22
+
23
+ def transform_document(doc)
24
+ blocks = Array(doc.children)
25
+ .flat_map { |child| FromCoreModel.flatten_transform_result(FromCoreModel.transform(child)) }
26
+ .compact
27
+
28
+ Coradoc::Markdown::Document.new(
29
+ id: doc.id,
30
+ blocks: blocks
31
+ )
32
+ end
33
+
34
+ def transform_section(section)
35
+ blocks = []
36
+ blocks << Coradoc::Markdown::Heading.new(
37
+ level: section.level || 1,
38
+ text: section.title.to_s
39
+ )
40
+ child_blocks = Array(section.children)
41
+ .flat_map { |child| FromCoreModel.flatten_transform_result(FromCoreModel.transform(child)) }
42
+ .compact
43
+ blocks.concat(child_blocks)
44
+ blocks
45
+ end
46
+
47
+ def transform_preamble(preamble)
48
+ Array(preamble.children)
49
+ .flat_map { |child| FromCoreModel.flatten_transform_result(FromCoreModel.transform(child)) }
50
+ .compact
51
+ end
52
+
53
+ def transform_header(header)
54
+ level = header.level || 1
55
+ Coradoc::Markdown::Heading.new(
56
+ level: level,
57
+ text: header.title.to_s
58
+ )
59
+ end
60
+
61
+ def transform_generic_element(element)
62
+ blocks = Array(element.children)
63
+ .flat_map { |child| FromCoreModel.flatten_transform_result(FromCoreModel.transform(child)) }
64
+ .compact
65
+
66
+ Coradoc::Markdown::Document.new(
67
+ id: element.id,
68
+ blocks: blocks
69
+ )
70
+ end
71
+
72
+ def transform_bibliography(bib)
73
+ entries = Array(bib.entries).map { |e| FromCoreModel.transform(e) }
74
+ blocks = []
75
+ blocks << Coradoc::Markdown::Heading.new(level: 2, text: bib.title.to_s) if bib.title
76
+ blocks.concat(entries)
77
+ Coradoc::Markdown::Document.new(id: bib.id, blocks: blocks)
78
+ end
79
+
80
+ def transform_bibliography_entry(entry)
81
+ FromCoreModel.transform_bibliography_entry(entry)
82
+ end
83
+ end
84
+
85
+ # Register with FromCoreModel
86
+ FromCoreModel.register(CoreModel::StructuralElement, method(:transform_structural_element))
87
+ FromCoreModel.register(CoreModel::Bibliography, method(:transform_bibliography))
88
+ FromCoreModel.register(CoreModel::BibliographyEntry, method(:transform_bibliography_entry))
89
+ FromCoreModel.register(CoreModel::Toc, ->(_m) { Coradoc::Markdown::Extension.toc })
90
+ FromCoreModel.register(CoreModel::TocEntry, ->(m) { Coradoc::Markdown::Text.new(content: m.title.to_s) })
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Markdown
5
+ module Transform
6
+ module TableTransformer
7
+ class << self
8
+ def transform_table(table)
9
+ headers = []
10
+ rows = []
11
+
12
+ table_rows = Array(table.rows)
13
+ if table_rows.any?
14
+ first_row = table_rows.first
15
+ first_row_cells = Array(first_row&.cells)
16
+
17
+ # Check if first row has header cells
18
+ if first_row_cells.any?(&:header)
19
+ headers = first_row_cells.map(&:flat_text)
20
+ table_rows = table_rows[1..] || []
21
+ end
22
+
23
+ # Convert remaining rows to pipe-separated strings
24
+ rows = table_rows.map do |row|
25
+ Array(row.cells).map(&:flat_text).join(' | ')
26
+ end
27
+ end
28
+
29
+ Coradoc::Markdown::Table.new(
30
+ headers: headers,
31
+ rows: rows
32
+ )
33
+ end
34
+ end
35
+
36
+ FromCoreModel.register(CoreModel::Table, method(:transform_table))
37
+ end
38
+ end
39
+ end
40
+ end