coradoc-markdown 1.0.0 → 1.0.3

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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/lib/coradoc/markdown/model/admonition.rb +35 -0
  3. data/lib/coradoc/markdown/model/attribute_list.rb +5 -16
  4. data/lib/coradoc/markdown/model/base.rb +2 -34
  5. data/lib/coradoc/markdown/model/comment.rb +14 -0
  6. data/lib/coradoc/markdown/model/cross_reference.rb +10 -0
  7. data/lib/coradoc/markdown/model/definition_list.rb +0 -12
  8. data/lib/coradoc/markdown/model/definition_term.rb +16 -6
  9. data/lib/coradoc/markdown/model/document.rb +9 -0
  10. data/lib/coradoc/markdown/model/example_block.rb +26 -0
  11. data/lib/coradoc/markdown/model/extension.rb +9 -18
  12. data/lib/coradoc/markdown/model/footnote_reference.rb +0 -5
  13. data/lib/coradoc/markdown/model/hard_line_break.rb +21 -0
  14. data/lib/coradoc/markdown/model/highlight.rb +0 -5
  15. data/lib/coradoc/markdown/model/horizontal_rule.rb +1 -6
  16. data/lib/coradoc/markdown/model/list_item.rb +1 -1
  17. data/lib/coradoc/markdown/model/literal.rb +21 -0
  18. data/lib/coradoc/markdown/model/math.rb +0 -14
  19. data/lib/coradoc/markdown/model/named_value.rb +18 -0
  20. data/lib/coradoc/markdown/model/open_block.rb +22 -0
  21. data/lib/coradoc/markdown/model/paragraph.rb +2 -2
  22. data/lib/coradoc/markdown/model/pass.rb +21 -0
  23. data/lib/coradoc/markdown/model/sidebar.rb +22 -0
  24. data/lib/coradoc/markdown/model/strikethrough.rb +0 -5
  25. data/lib/coradoc/markdown/model/subscript.rb +9 -0
  26. data/lib/coradoc/markdown/model/superscript.rb +9 -0
  27. data/lib/coradoc/markdown/model/underline.rb +9 -0
  28. data/lib/coradoc/markdown/model/verse.rb +27 -0
  29. data/lib/coradoc/markdown/parser/block_parser.rb +1 -1
  30. data/lib/coradoc/markdown/parser/frontmatter_parser.rb +23 -0
  31. data/lib/coradoc/markdown/serializer/builder.rb +57 -0
  32. data/lib/coradoc/markdown/serializer/config.rb +77 -0
  33. data/lib/coradoc/markdown/serializer/context.rb +66 -0
  34. data/lib/coradoc/markdown/serializer/element_serializer.rb +46 -0
  35. data/lib/coradoc/markdown/serializer/flavor.rb +82 -0
  36. data/lib/coradoc/markdown/serializer/registrations.rb +111 -0
  37. data/lib/coradoc/markdown/serializer/registry.rb +62 -0
  38. data/lib/coradoc/markdown/serializer/runner.rb +84 -0
  39. data/lib/coradoc/markdown/serializer/serializers/abbreviation.rb +19 -0
  40. data/lib/coradoc/markdown/serializer/serializers/admonition.rb +20 -0
  41. data/lib/coradoc/markdown/serializer/serializers/attribute_list.rb +25 -0
  42. data/lib/coradoc/markdown/serializer/serializers/blockquote.rb +19 -0
  43. data/lib/coradoc/markdown/serializer/serializers/code.rb +19 -0
  44. data/lib/coradoc/markdown/serializer/serializers/code_block.rb +19 -0
  45. data/lib/coradoc/markdown/serializer/serializers/comment.rb +31 -0
  46. data/lib/coradoc/markdown/serializer/serializers/cross_reference.rb +19 -0
  47. data/lib/coradoc/markdown/serializer/serializers/definition_list.rb +20 -0
  48. data/lib/coradoc/markdown/serializer/serializers/document.rb +22 -0
  49. data/lib/coradoc/markdown/serializer/serializers/emphasis.rb +19 -0
  50. data/lib/coradoc/markdown/serializer/serializers/example_block.rb +40 -0
  51. data/lib/coradoc/markdown/serializer/serializers/extension.rb +30 -0
  52. data/lib/coradoc/markdown/serializer/serializers/footnote.rb +20 -0
  53. data/lib/coradoc/markdown/serializer/serializers/footnote_reference.rb +19 -0
  54. data/lib/coradoc/markdown/serializer/serializers/hard_line_break.rb +22 -0
  55. data/lib/coradoc/markdown/serializer/serializers/heading.rb +19 -0
  56. data/lib/coradoc/markdown/serializer/serializers/highlight.rb +19 -0
  57. data/lib/coradoc/markdown/serializer/serializers/horizontal_rule.rb +19 -0
  58. data/lib/coradoc/markdown/serializer/serializers/image.rb +19 -0
  59. data/lib/coradoc/markdown/serializer/serializers/link.rb +29 -0
  60. data/lib/coradoc/markdown/serializer/serializers/list.rb +45 -0
  61. data/lib/coradoc/markdown/serializer/serializers/literal.rb +21 -0
  62. data/lib/coradoc/markdown/serializer/serializers/math.rb +23 -0
  63. data/lib/coradoc/markdown/serializer/serializers/open_block.rb +38 -0
  64. data/lib/coradoc/markdown/serializer/serializers/paragraph.rb +23 -0
  65. data/lib/coradoc/markdown/serializer/serializers/pass.rb +21 -0
  66. data/lib/coradoc/markdown/serializer/serializers/sidebar.rb +20 -0
  67. data/lib/coradoc/markdown/serializer/serializers/strikethrough.rb +19 -0
  68. data/lib/coradoc/markdown/serializer/serializers/strong.rb +19 -0
  69. data/lib/coradoc/markdown/serializer/serializers/subscript.rb +19 -0
  70. data/lib/coradoc/markdown/serializer/serializers/superscript.rb +19 -0
  71. data/lib/coradoc/markdown/serializer/serializers/table.rb +37 -0
  72. data/lib/coradoc/markdown/serializer/serializers/underline.rb +19 -0
  73. data/lib/coradoc/markdown/serializer/serializers/verse.rb +31 -0
  74. data/lib/coradoc/markdown/serializer/strategies/admonition/base.rb +30 -0
  75. data/lib/coradoc/markdown/serializer/strategies/admonition/container.rb +34 -0
  76. data/lib/coradoc/markdown/serializer/strategies/admonition/gfm_alert.rb +28 -0
  77. data/lib/coradoc/markdown/serializer/strategies/admonition/github.rb +29 -0
  78. data/lib/coradoc/markdown/serializer/strategies/admonition/html.rb +25 -0
  79. data/lib/coradoc/markdown/serializer/strategies/admonition/registry.rb +50 -0
  80. data/lib/coradoc/markdown/serializer/strategies/autolink/angle.rb +35 -0
  81. data/lib/coradoc/markdown/serializer/strategies/autolink/bare.rb +23 -0
  82. data/lib/coradoc/markdown/serializer/strategies/autolink/base.rb +33 -0
  83. data/lib/coradoc/markdown/serializer/strategies/autolink/none.rb +27 -0
  84. data/lib/coradoc/markdown/serializer/strategies/autolink/registry.rb +58 -0
  85. data/lib/coradoc/markdown/serializer/strategies/definition_list/base.rb +37 -0
  86. data/lib/coradoc/markdown/serializer/strategies/definition_list/flat.rb +48 -0
  87. data/lib/coradoc/markdown/serializer/strategies/definition_list/nested_html.rb +54 -0
  88. data/lib/coradoc/markdown/serializer/strategies/definition_list/registry.rb +37 -0
  89. data/lib/coradoc/markdown/serializer.rb +30 -181
  90. data/lib/coradoc/markdown/toc_generator.rb +2 -8
  91. data/lib/coradoc/markdown/transform/block_transformer.rb +163 -0
  92. data/lib/coradoc/markdown/transform/from_core_model.rb +205 -40
  93. data/lib/coradoc/markdown/transform/image_transformer.rb +20 -0
  94. data/lib/coradoc/markdown/transform/inline_transformer.rb +74 -0
  95. data/lib/coradoc/markdown/transform/list_transformer.rb +52 -0
  96. data/lib/coradoc/markdown/transform/structural_transformer.rb +94 -0
  97. data/lib/coradoc/markdown/transform/table_transformer.rb +40 -0
  98. data/lib/coradoc/markdown/transform/to_core_model.rb +36 -30
  99. data/lib/coradoc/markdown/transformer.rb +87 -2
  100. data/lib/coradoc/markdown/version.rb +1 -1
  101. data/lib/coradoc/markdown.rb +23 -20
  102. metadata +89 -10
@@ -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
@@ -58,10 +65,10 @@ module Coradoc
58
65
  private
59
66
 
60
67
  def transform_structural_element(element)
61
- case element.element_type
62
- when 'document'
68
+ case element
69
+ when CoreModel::DocumentElement
63
70
  transform_document(element)
64
- when 'section'
71
+ when CoreModel::SectionElement
65
72
  transform_section(element)
66
73
  else
67
74
  transform_generic_element(element)
@@ -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,
@@ -94,11 +117,12 @@ module Coradoc
94
117
  end
95
118
 
96
119
  def transform_block(block)
97
- case block.element_type
98
- when 'paragraph'
120
+ semantic = block.resolve_semantic_type
121
+ case semantic
122
+ when :paragraph
99
123
  transform_paragraph(block)
100
- when 'comment'
101
- Coradoc::Markdown::Extension.comment(block.content.to_s)
124
+ when :comment
125
+ Coradoc::Markdown::Comment.new(text: block.content.to_s)
102
126
  else
103
127
  transform_delimited_block(block)
104
128
  end
@@ -106,8 +130,17 @@ module Coradoc
106
130
 
107
131
  def transform_paragraph(block)
108
132
  content = block.renderable_content
109
- if content.is_a?(Array) && content.any? { |c| !c.is_a?(String) }
110
- # Mixed content with inline elements
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) }
111
144
  children = content.map { |c| transform_inline_content(c) }
112
145
  Coradoc::Markdown::Paragraph.new(text: block.flat_text, children: children)
113
146
  else
@@ -119,8 +152,14 @@ module Coradoc
119
152
  case element
120
153
  when Coradoc::CoreModel::InlineElement
121
154
  transform_inline(element)
155
+ when CoreModel::TextContent
156
+ element.text
157
+ when CoreModel::Base
158
+ transform(element)
122
159
  when String
123
160
  element
161
+ when Array
162
+ element.map { |e| transform_inline_content(e) }
124
163
  else
125
164
  element.to_s
126
165
  end
@@ -132,19 +171,97 @@ module Coradoc
132
171
  case semantic
133
172
  when :source_code, :listing
134
173
  transform_code_block(block)
135
- when :quote, :verse
174
+ when :quote
136
175
  transform_blockquote(block)
176
+ when :verse
177
+ transform_verse_block(block)
137
178
  when :horizontal_rule
138
179
  transform_horizontal_rule(block)
139
180
  when :pass
140
- Coradoc::Markdown::Extension.nomarkdown(block.content.to_s)
181
+ transform_pass_block(block)
141
182
  when :literal
142
- transform_code_block(block)
183
+ transform_literal_block(block)
184
+ when :example
185
+ transform_example_block(block)
186
+ when :sidebar
187
+ transform_sidebar_block(block)
188
+ when :open
189
+ transform_open_block(block)
190
+ when :reviewer
191
+ transform_admonition_block(block, default_type: 'reviewer')
143
192
  else
144
193
  transform_paragraph(block)
145
194
  end
146
195
  end
147
196
 
197
+ def transform_container_block(block)
198
+ rc = block.renderable_content
199
+ if rc.is_a?(Array) && rc.any? { |c| c.is_a?(CoreModel::Block) || c.is_a?(CoreModel::ListBlock) }
200
+ rc.filter_map do |c|
201
+ next c.text if c.is_a?(CoreModel::TextContent)
202
+ next nil if c.is_a?(String) && c.strip.empty?
203
+
204
+ transform(c)
205
+ end.flat_map { |c| flatten_result(c) }
206
+ else
207
+ Coradoc::Markdown::Blockquote.new(content: block.flat_text)
208
+ end
209
+ end
210
+
211
+ def transform_verse_block(block)
212
+ Coradoc::Markdown::Verse.new(
213
+ content: block.flat_text,
214
+ attribution: block.respond_to?(:attribution) ? block.attribution : nil
215
+ )
216
+ end
217
+
218
+ def transform_pass_block(block)
219
+ return Coradoc::Markdown::Math.block(block.content.to_s) if block.language == 'latexmath'
220
+
221
+ Coradoc::Markdown::Pass.new(content: block.content.to_s)
222
+ end
223
+
224
+ def transform_literal_block(block)
225
+ Coradoc::Markdown::Literal.new(content: block.content.to_s)
226
+ end
227
+
228
+ def transform_example_block(block)
229
+ Coradoc::Markdown::ExampleBlock.new(
230
+ content: block.flat_text,
231
+ caption: block.title.to_s
232
+ )
233
+ end
234
+
235
+ def transform_sidebar_block(block)
236
+ Coradoc::Markdown::Sidebar.new(
237
+ content: block.flat_text,
238
+ title: block.title.to_s
239
+ )
240
+ end
241
+
242
+ def transform_open_block(block)
243
+ children = Array(block.children).map { |c| transform(c) }.flat_map { |c| flatten_result(c) }
244
+ children = paragraphs_from_content(block.content) if children.empty?
245
+ Coradoc::Markdown::OpenBlock.new(
246
+ children: children,
247
+ id: block.id
248
+ )
249
+ end
250
+
251
+ def paragraphs_from_content(content)
252
+ content.to_s.split(/\n\s*\n/).map do |chunk|
253
+ Coradoc::Markdown::Paragraph.new(text: chunk.strip)
254
+ end
255
+ end
256
+
257
+ def transform_admonition_block(block, default_type: 'note')
258
+ Coradoc::Markdown::Admonition.new(
259
+ admonition_type: block.respond_to?(:annotation_type) ? (block.annotation_type || default_type) : default_type,
260
+ content: block.flat_text,
261
+ title: block.respond_to?(:annotation_label) ? block.annotation_label : nil
262
+ )
263
+ end
264
+
148
265
  def resolve_markdown_semantic(block)
149
266
  # Polymorphic dispatch: typed classes override semantic_type
150
267
  semantic = block.resolve_semantic_type
@@ -160,15 +277,25 @@ module Coradoc
160
277
  when '>' then :quote
161
278
  when '---', '***', '___' then :horizontal_rule
162
279
  when '++++' then :pass
163
- else nil
164
280
  end
165
281
  end
166
282
 
167
283
  def transform_code_block(block)
168
- Coradoc::Markdown::CodeBlock.new(
169
- code: block.content.to_s,
284
+ code = CoreModel::CalloutText.strip_markers(block.content.to_s, block.callouts)
285
+ code_block = Coradoc::Markdown::CodeBlock.new(
286
+ code: code,
170
287
  language: block.language
171
288
  )
289
+ return code_block if block.callouts.nil? || block.callouts.empty?
290
+
291
+ [code_block, transform_callout_list(block.callouts)]
292
+ end
293
+
294
+ def transform_callout_list(callouts)
295
+ items = CoreModel::CalloutText.ordered(callouts).map do |callout|
296
+ Coradoc::Markdown::ListItem.new(text: callout.content.to_s)
297
+ end
298
+ Coradoc::Markdown::List.new(ordered: true, items: items)
172
299
  end
173
300
 
174
301
  def transform_blockquote(block)
@@ -178,18 +305,21 @@ module Coradoc
178
305
  end
179
306
 
180
307
  def transform_horizontal_rule(_block)
181
- Coradoc::Markdown::HorizontalRule.new
308
+ Coradoc::Markdown::HorizontalRule.new(style: '---')
182
309
  end
183
310
 
184
311
  def transform_list(list)
185
312
  items = Array(list.items).map do |item|
186
313
  content = item.renderable_content
187
- if content.is_a?(Array) && content.any? { |c| !c.is_a?(String) }
188
- children = content.map { |c| transform_inline_content(c) }
189
- Coradoc::Markdown::ListItem.new(text: item.flat_text, children: children)
190
- else
191
- Coradoc::Markdown::ListItem.new(text: item.flat_text)
192
- end
314
+ has_structured = content.is_a?(Array) && content.any? { |c| !c.is_a?(CoreModel::TextContent) }
315
+ md_item = if has_structured
316
+ children = content.map { |c| transform_inline_content(c) }
317
+ Coradoc::Markdown::ListItem.new(text: item.flat_text, children: children)
318
+ else
319
+ Coradoc::Markdown::ListItem.new(text: item.flat_text)
320
+ end
321
+ md_item.sublist = transform_list(item.nested_list) if item.nested_list
322
+ md_item
193
323
  end
194
324
 
195
325
  Coradoc::Markdown::List.new(
@@ -208,8 +338,8 @@ module Coradoc
208
338
  first_row = table_rows.first
209
339
  first_row_cells = Array(first_row&.cells)
210
340
 
211
- # Check if first row has header cells
212
- if first_row_cells.any?(&:header)
341
+ # Check if first row is marked as header, or if any of its cells are header cells
342
+ if first_row&.header || first_row_cells.any?(&:header)
213
343
  headers = first_row_cells.map(&:flat_text)
214
344
  table_rows = table_rows[1..] || []
215
345
  end
@@ -234,7 +364,7 @@ module Coradoc
234
364
  end
235
365
 
236
366
  def transform_inline(element)
237
- case element.format_type
367
+ case element.resolve_format_type
238
368
  when 'bold'
239
369
  Coradoc::Markdown::Strong.new(text: element.content.to_s)
240
370
  when 'italic'
@@ -255,13 +385,16 @@ module Coradoc
255
385
  when 'strikethrough'
256
386
  Coradoc::Markdown::Strikethrough.new(text: element.content.to_s)
257
387
  when 'subscript'
258
- "<sub>#{element.content}</sub>"
388
+ Coradoc::Markdown::Subscript.new(text: element.content.to_s)
259
389
  when 'superscript'
260
- "<sup>#{element.content}</sup>"
390
+ Coradoc::Markdown::Superscript.new(text: element.content.to_s)
261
391
  when 'underline'
262
- "<u>#{element.content}</u>"
392
+ Coradoc::Markdown::Underline.new(text: element.content.to_s)
263
393
  when 'xref'
264
- "[#{element.content}](##{element.target})"
394
+ Coradoc::Markdown::CrossReference.new(
395
+ text: element.content.to_s,
396
+ target: element.target.to_s
397
+ )
265
398
  else
266
399
  element.content.to_s
267
400
  end
@@ -272,9 +405,11 @@ module Coradoc
272
405
  definitions = Array(item.definitions).map do |defn|
273
406
  Coradoc::Markdown::DefinitionItem.new(content: defn.to_s)
274
407
  end
408
+ nested = item.nested ? transform_definition_list(item.nested) : nil
275
409
  Coradoc::Markdown::DefinitionTerm.new(
276
410
  text: item.term.to_s,
277
- definitions: definitions
411
+ definitions: definitions,
412
+ nested: nested
278
413
  )
279
414
  end
280
415
 
@@ -301,10 +436,7 @@ module Coradoc
301
436
  end
302
437
 
303
438
  def transform_annotation_block(annotation)
304
- text = annotation.flat_text
305
- Coradoc::Markdown::Paragraph.new(
306
- text: "**#{annotation.annotation_type}:** #{text}"
307
- )
439
+ transform_admonition_block(annotation, default_type: 'note')
308
440
  end
309
441
 
310
442
  def transform_bibliography(bib)
@@ -316,7 +448,40 @@ module Coradoc
316
448
  end
317
449
 
318
450
  def transform_bibliography_entry(entry)
319
- Coradoc::Markdown::Paragraph.new(text: entry.display_text)
451
+ text = entry.display_text.to_s
452
+ text = convert_asciidoc_markers_to_markdown(text)
453
+ Coradoc::Markdown::Paragraph.new(text: text)
454
+ end
455
+
456
+ def convert_asciidoc_markers_to_markdown(text)
457
+ return '' if text.nil?
458
+
459
+ result = text.dup
460
+
461
+ # footnote:[text] -> ^[text]
462
+ result.gsub!(/footnote:\[(.*?)\]/, '^[\1]')
463
+
464
+ # [smallcap]#text# -> text
465
+ result.gsub!(/\[smallcap\]#(.*?)#/, '\1')
466
+
467
+ # *text* -> **text**
468
+ # Use negative lookbehind and lookahead to avoid replacing **text** to ****text****
469
+ result.gsub!(/(?<!\*)\*(.*?)\*(?!\*)/, '**\1**')
470
+
471
+ # _text_ -> *text*
472
+ # Use negative lookbehind and lookahead to avoid replacing __text__ to **text**
473
+ result.gsub!(/(?<!_)_(.*?)_(?!_)/, '*\1*')
474
+
475
+ result
476
+ end
477
+
478
+ def flatten_result(result)
479
+ case result
480
+ when Array
481
+ result.flat_map { |r| flatten_result(r) }
482
+ else
483
+ [result]
484
+ end
320
485
  end
321
486
  end
322
487
  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