coradoc-markdown 1.0.2 → 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.
- checksums.yaml +4 -4
- data/lib/coradoc/markdown/model/admonition.rb +35 -0
- data/lib/coradoc/markdown/model/comment.rb +14 -0
- data/lib/coradoc/markdown/model/definition_term.rb +16 -6
- data/lib/coradoc/markdown/model/document.rb +9 -0
- data/lib/coradoc/markdown/model/example_block.rb +26 -0
- data/lib/coradoc/markdown/model/hard_line_break.rb +21 -0
- data/lib/coradoc/markdown/model/horizontal_rule.rb +1 -6
- data/lib/coradoc/markdown/model/list_item.rb +1 -1
- data/lib/coradoc/markdown/model/literal.rb +21 -0
- data/lib/coradoc/markdown/model/open_block.rb +22 -0
- data/lib/coradoc/markdown/model/paragraph.rb +2 -2
- data/lib/coradoc/markdown/model/pass.rb +21 -0
- data/lib/coradoc/markdown/model/sidebar.rb +22 -0
- data/lib/coradoc/markdown/model/verse.rb +27 -0
- data/lib/coradoc/markdown/parser/block_parser.rb +1 -1
- data/lib/coradoc/markdown/parser/frontmatter_parser.rb +23 -0
- data/lib/coradoc/markdown/serializer/builder.rb +57 -0
- data/lib/coradoc/markdown/serializer/config.rb +77 -0
- data/lib/coradoc/markdown/serializer/context.rb +66 -0
- data/lib/coradoc/markdown/serializer/element_serializer.rb +46 -0
- data/lib/coradoc/markdown/serializer/flavor.rb +82 -0
- data/lib/coradoc/markdown/serializer/registrations.rb +111 -0
- data/lib/coradoc/markdown/serializer/registry.rb +62 -0
- data/lib/coradoc/markdown/serializer/runner.rb +84 -0
- data/lib/coradoc/markdown/serializer/serializers/abbreviation.rb +19 -0
- data/lib/coradoc/markdown/serializer/serializers/admonition.rb +20 -0
- data/lib/coradoc/markdown/serializer/serializers/attribute_list.rb +25 -0
- data/lib/coradoc/markdown/serializer/serializers/blockquote.rb +19 -0
- data/lib/coradoc/markdown/serializer/serializers/code.rb +19 -0
- data/lib/coradoc/markdown/serializer/serializers/code_block.rb +19 -0
- data/lib/coradoc/markdown/serializer/serializers/comment.rb +31 -0
- data/lib/coradoc/markdown/serializer/serializers/cross_reference.rb +19 -0
- data/lib/coradoc/markdown/serializer/serializers/definition_list.rb +20 -0
- data/lib/coradoc/markdown/serializer/serializers/document.rb +22 -0
- data/lib/coradoc/markdown/serializer/serializers/emphasis.rb +19 -0
- data/lib/coradoc/markdown/serializer/serializers/example_block.rb +40 -0
- data/lib/coradoc/markdown/serializer/serializers/extension.rb +30 -0
- data/lib/coradoc/markdown/serializer/serializers/footnote.rb +20 -0
- data/lib/coradoc/markdown/serializer/serializers/footnote_reference.rb +19 -0
- data/lib/coradoc/markdown/serializer/serializers/hard_line_break.rb +22 -0
- data/lib/coradoc/markdown/serializer/serializers/heading.rb +19 -0
- data/lib/coradoc/markdown/serializer/serializers/highlight.rb +19 -0
- data/lib/coradoc/markdown/serializer/serializers/horizontal_rule.rb +19 -0
- data/lib/coradoc/markdown/serializer/serializers/image.rb +19 -0
- data/lib/coradoc/markdown/serializer/serializers/link.rb +29 -0
- data/lib/coradoc/markdown/serializer/serializers/list.rb +45 -0
- data/lib/coradoc/markdown/serializer/serializers/literal.rb +21 -0
- data/lib/coradoc/markdown/serializer/serializers/math.rb +23 -0
- data/lib/coradoc/markdown/serializer/serializers/open_block.rb +38 -0
- data/lib/coradoc/markdown/serializer/serializers/paragraph.rb +23 -0
- data/lib/coradoc/markdown/serializer/serializers/pass.rb +21 -0
- data/lib/coradoc/markdown/serializer/serializers/sidebar.rb +20 -0
- data/lib/coradoc/markdown/serializer/serializers/strikethrough.rb +19 -0
- data/lib/coradoc/markdown/serializer/serializers/strong.rb +19 -0
- data/lib/coradoc/markdown/serializer/serializers/subscript.rb +19 -0
- data/lib/coradoc/markdown/serializer/serializers/superscript.rb +19 -0
- data/lib/coradoc/markdown/serializer/serializers/table.rb +37 -0
- data/lib/coradoc/markdown/serializer/serializers/underline.rb +19 -0
- data/lib/coradoc/markdown/serializer/serializers/verse.rb +31 -0
- data/lib/coradoc/markdown/serializer/strategies/admonition/base.rb +30 -0
- data/lib/coradoc/markdown/serializer/strategies/admonition/container.rb +34 -0
- data/lib/coradoc/markdown/serializer/strategies/admonition/gfm_alert.rb +28 -0
- data/lib/coradoc/markdown/serializer/strategies/admonition/github.rb +29 -0
- data/lib/coradoc/markdown/serializer/strategies/admonition/html.rb +25 -0
- data/lib/coradoc/markdown/serializer/strategies/admonition/registry.rb +50 -0
- data/lib/coradoc/markdown/serializer/strategies/autolink/angle.rb +35 -0
- data/lib/coradoc/markdown/serializer/strategies/autolink/bare.rb +23 -0
- data/lib/coradoc/markdown/serializer/strategies/autolink/base.rb +33 -0
- data/lib/coradoc/markdown/serializer/strategies/autolink/none.rb +27 -0
- data/lib/coradoc/markdown/serializer/strategies/autolink/registry.rb +58 -0
- data/lib/coradoc/markdown/serializer/strategies/definition_list/base.rb +37 -0
- data/lib/coradoc/markdown/serializer/strategies/definition_list/flat.rb +48 -0
- data/lib/coradoc/markdown/serializer/strategies/definition_list/nested_html.rb +54 -0
- data/lib/coradoc/markdown/serializer/strategies/definition_list/registry.rb +37 -0
- data/lib/coradoc/markdown/serializer.rb +29 -243
- data/lib/coradoc/markdown/toc_generator.rb +2 -2
- data/lib/coradoc/markdown/transform/block_transformer.rb +163 -0
- data/lib/coradoc/markdown/transform/from_core_model.rb +187 -28
- data/lib/coradoc/markdown/transform/image_transformer.rb +20 -0
- data/lib/coradoc/markdown/transform/inline_transformer.rb +74 -0
- data/lib/coradoc/markdown/transform/list_transformer.rb +52 -0
- data/lib/coradoc/markdown/transform/structural_transformer.rb +94 -0
- data/lib/coradoc/markdown/transform/table_transformer.rb +40 -0
- data/lib/coradoc/markdown/transform/to_core_model.rb +24 -3
- data/lib/coradoc/markdown/transformer.rb +87 -2
- data/lib/coradoc/markdown/version.rb +1 -1
- data/lib/coradoc/markdown.rb +16 -2
- 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.
|
|
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)
|
|
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).
|
|
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::
|
|
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
|
-
|
|
111
|
-
|
|
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,8 +154,12 @@ 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
|
|
@@ -135,19 +171,97 @@ module Coradoc
|
|
|
135
171
|
case semantic
|
|
136
172
|
when :source_code, :listing
|
|
137
173
|
transform_code_block(block)
|
|
138
|
-
when :quote
|
|
174
|
+
when :quote
|
|
139
175
|
transform_blockquote(block)
|
|
176
|
+
when :verse
|
|
177
|
+
transform_verse_block(block)
|
|
140
178
|
when :horizontal_rule
|
|
141
179
|
transform_horizontal_rule(block)
|
|
142
180
|
when :pass
|
|
143
|
-
|
|
181
|
+
transform_pass_block(block)
|
|
144
182
|
when :literal
|
|
145
|
-
|
|
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')
|
|
146
192
|
else
|
|
147
193
|
transform_paragraph(block)
|
|
148
194
|
end
|
|
149
195
|
end
|
|
150
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
|
+
|
|
151
265
|
def resolve_markdown_semantic(block)
|
|
152
266
|
# Polymorphic dispatch: typed classes override semantic_type
|
|
153
267
|
semantic = block.resolve_semantic_type
|
|
@@ -167,10 +281,21 @@ module Coradoc
|
|
|
167
281
|
end
|
|
168
282
|
|
|
169
283
|
def transform_code_block(block)
|
|
170
|
-
|
|
171
|
-
|
|
284
|
+
code = CoreModel::CalloutText.strip_markers(block.content.to_s, block.callouts)
|
|
285
|
+
code_block = Coradoc::Markdown::CodeBlock.new(
|
|
286
|
+
code: code,
|
|
172
287
|
language: block.language
|
|
173
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)
|
|
174
299
|
end
|
|
175
300
|
|
|
176
301
|
def transform_blockquote(block)
|
|
@@ -180,19 +305,21 @@ module Coradoc
|
|
|
180
305
|
end
|
|
181
306
|
|
|
182
307
|
def transform_horizontal_rule(_block)
|
|
183
|
-
Coradoc::Markdown::HorizontalRule.new
|
|
308
|
+
Coradoc::Markdown::HorizontalRule.new(style: '---')
|
|
184
309
|
end
|
|
185
310
|
|
|
186
311
|
def transform_list(list)
|
|
187
312
|
items = Array(list.items).map do |item|
|
|
188
313
|
content = item.renderable_content
|
|
189
314
|
has_structured = content.is_a?(Array) && content.any? { |c| !c.is_a?(CoreModel::TextContent) }
|
|
190
|
-
if has_structured
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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
|
|
196
323
|
end
|
|
197
324
|
|
|
198
325
|
Coradoc::Markdown::List.new(
|
|
@@ -211,8 +338,8 @@ module Coradoc
|
|
|
211
338
|
first_row = table_rows.first
|
|
212
339
|
first_row_cells = Array(first_row&.cells)
|
|
213
340
|
|
|
214
|
-
# Check if first row
|
|
215
|
-
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)
|
|
216
343
|
headers = first_row_cells.map(&:flat_text)
|
|
217
344
|
table_rows = table_rows[1..] || []
|
|
218
345
|
end
|
|
@@ -278,9 +405,11 @@ module Coradoc
|
|
|
278
405
|
definitions = Array(item.definitions).map do |defn|
|
|
279
406
|
Coradoc::Markdown::DefinitionItem.new(content: defn.to_s)
|
|
280
407
|
end
|
|
408
|
+
nested = item.nested ? transform_definition_list(item.nested) : nil
|
|
281
409
|
Coradoc::Markdown::DefinitionTerm.new(
|
|
282
410
|
text: item.term.to_s,
|
|
283
|
-
definitions: definitions
|
|
411
|
+
definitions: definitions,
|
|
412
|
+
nested: nested
|
|
284
413
|
)
|
|
285
414
|
end
|
|
286
415
|
|
|
@@ -307,10 +436,7 @@ module Coradoc
|
|
|
307
436
|
end
|
|
308
437
|
|
|
309
438
|
def transform_annotation_block(annotation)
|
|
310
|
-
|
|
311
|
-
Coradoc::Markdown::Paragraph.new(
|
|
312
|
-
text: "**#{annotation.annotation_type}:** #{text}"
|
|
313
|
-
)
|
|
439
|
+
transform_admonition_block(annotation, default_type: 'note')
|
|
314
440
|
end
|
|
315
441
|
|
|
316
442
|
def transform_bibliography(bib)
|
|
@@ -322,7 +448,40 @@ module Coradoc
|
|
|
322
448
|
end
|
|
323
449
|
|
|
324
450
|
def transform_bibliography_entry(entry)
|
|
325
|
-
|
|
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
|
|
326
485
|
end
|
|
327
486
|
end
|
|
328
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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'coradoc
|
|
3
|
+
require 'coradoc'
|
|
4
4
|
|
|
5
5
|
module Coradoc
|
|
6
6
|
module Markdown
|
|
@@ -62,6 +62,8 @@ module Coradoc
|
|
|
62
62
|
transform_extension(model)
|
|
63
63
|
when Coradoc::Markdown::AttributeList
|
|
64
64
|
transform_attribute_list(model)
|
|
65
|
+
when Coradoc::Markdown::Comment
|
|
66
|
+
Coradoc::CoreModel::CommentBlock.new(content: model.text.to_s)
|
|
65
67
|
when Coradoc::Markdown::Text
|
|
66
68
|
model.content.to_s
|
|
67
69
|
when Array
|
|
@@ -75,6 +77,7 @@ module Coradoc
|
|
|
75
77
|
|
|
76
78
|
def transform_document(doc)
|
|
77
79
|
children = Array(doc.blocks).map { |block| transform(block) }
|
|
80
|
+
children = prepend_frontmatter(children, doc.frontmatter)
|
|
78
81
|
|
|
79
82
|
Coradoc::CoreModel::DocumentElement.new(
|
|
80
83
|
id: doc.id,
|
|
@@ -83,6 +86,22 @@ module Coradoc
|
|
|
83
86
|
)
|
|
84
87
|
end
|
|
85
88
|
|
|
89
|
+
# If the Markdown document had raw frontmatter text, parse it
|
|
90
|
+
# via Codec into a typed FrontmatterBlock and prepend it so
|
|
91
|
+
# it participates in the standard block pipeline. Codec is
|
|
92
|
+
# the single source of truth for YAML parsing (DRY/MECE).
|
|
93
|
+
#
|
|
94
|
+
# The block is prepended even when the YAML is malformed —
|
|
95
|
+
# Codec returns an empty FrontmatterBlock in that case, which
|
|
96
|
+
# preserves the signal "frontmatter was present but invalid"
|
|
97
|
+
# for downstream consumers.
|
|
98
|
+
def prepend_frontmatter(children, frontmatter_text)
|
|
99
|
+
return children if frontmatter_text.nil? || frontmatter_text.strip.empty?
|
|
100
|
+
|
|
101
|
+
block = Coradoc::CoreModel::FrontmatterBlock::Codec.from_yaml(frontmatter_text)
|
|
102
|
+
[block, *children]
|
|
103
|
+
end
|
|
104
|
+
|
|
86
105
|
def transform_heading(heading)
|
|
87
106
|
Coradoc::CoreModel::SectionElement.new(
|
|
88
107
|
level: heading.level,
|
|
@@ -114,9 +133,11 @@ module Coradoc
|
|
|
114
133
|
|
|
115
134
|
def transform_list(list)
|
|
116
135
|
items = Array(list.items).map do |item|
|
|
136
|
+
nested = item.sublist ? transform_list(item.sublist) : nil
|
|
117
137
|
Coradoc::CoreModel::ListItem.new(
|
|
118
138
|
content: extract_text(item.text),
|
|
119
|
-
marker: list.ordered ? '1.' : '*'
|
|
139
|
+
marker: list.ordered ? '1.' : '*',
|
|
140
|
+
nested_list: nested
|
|
120
141
|
)
|
|
121
142
|
end
|
|
122
143
|
|
|
@@ -144,7 +165,7 @@ module Coradoc
|
|
|
144
165
|
cells = if row.is_a?(Array)
|
|
145
166
|
row.map { |c| Coradoc::CoreModel::TableCell.new(content: c.to_s, header: false) }
|
|
146
167
|
else
|
|
147
|
-
|
|
168
|
+
row.to_s.split(' | ').map { |c| Coradoc::CoreModel::TableCell.new(content: c.to_s, header: false) }
|
|
148
169
|
end
|
|
149
170
|
rows << Coradoc::CoreModel::TableRow.new(cells: cells)
|
|
150
171
|
end
|