coradoc-mirror 0.1.4 → 0.1.5
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/mirror/handler_registry.rb +19 -30
- data/lib/coradoc/mirror/handlers/code_block.rb +17 -24
- data/lib/coradoc/mirror/handlers/inline.rb +14 -0
- data/lib/coradoc/mirror/node.rb +39 -0
- data/lib/coradoc/mirror/reverse_builder/admonition.rb +20 -0
- data/lib/coradoc/mirror/reverse_builder/base.rb +42 -0
- data/lib/coradoc/mirror/reverse_builder/biblio_entry.rb +22 -0
- data/lib/coradoc/mirror/reverse_builder/bibliography.rb +18 -0
- data/lib/coradoc/mirror/reverse_builder/blockquote.rb +20 -0
- data/lib/coradoc/mirror/reverse_builder/bullet_list.rb +18 -0
- data/lib/coradoc/mirror/reverse_builder/caption.rb +19 -0
- data/lib/coradoc/mirror/reverse_builder/code_block.rb +22 -0
- data/lib/coradoc/mirror/reverse_builder/definition_list.rb +35 -0
- data/lib/coradoc/mirror/reverse_builder/document.rb +22 -0
- data/lib/coradoc/mirror/reverse_builder/example.rb +20 -0
- data/lib/coradoc/mirror/reverse_builder/figure.rb +35 -0
- data/lib/coradoc/mirror/reverse_builder/footnote_entry.rb +18 -0
- data/lib/coradoc/mirror/reverse_builder/footnote_marker.rb +24 -0
- data/lib/coradoc/mirror/reverse_builder/footnotes.rb +20 -0
- data/lib/coradoc/mirror/reverse_builder/frontmatter.rb +21 -0
- data/lib/coradoc/mirror/reverse_builder/generic_block.rb +26 -0
- data/lib/coradoc/mirror/reverse_builder/header.rb +22 -0
- data/lib/coradoc/mirror/reverse_builder/horizontal_rule.rb +17 -0
- data/lib/coradoc/mirror/reverse_builder/image.rb +25 -0
- data/lib/coradoc/mirror/reverse_builder/include.rb +46 -0
- data/lib/coradoc/mirror/reverse_builder/inline_text.rb +19 -0
- data/lib/coradoc/mirror/reverse_builder/list_item.rb +37 -0
- data/lib/coradoc/mirror/reverse_builder/literal_block.rb +22 -0
- data/lib/coradoc/mirror/reverse_builder/open_block.rb +17 -0
- data/lib/coradoc/mirror/reverse_builder/ordered_list.rb +18 -0
- data/lib/coradoc/mirror/reverse_builder/paragraph.rb +17 -0
- data/lib/coradoc/mirror/reverse_builder/pass_block.rb +22 -0
- data/lib/coradoc/mirror/reverse_builder/preamble.rb +17 -0
- data/lib/coradoc/mirror/reverse_builder/raw_inline.rb +17 -0
- data/lib/coradoc/mirror/reverse_builder/section.rb +28 -0
- data/lib/coradoc/mirror/reverse_builder/sections.rb +19 -0
- data/lib/coradoc/mirror/reverse_builder/sidebar.rb +20 -0
- data/lib/coradoc/mirror/reverse_builder/soft_break.rb +17 -0
- data/lib/coradoc/mirror/reverse_builder/stem_block.rb +22 -0
- data/lib/coradoc/mirror/reverse_builder/table.rb +27 -0
- data/lib/coradoc/mirror/reverse_builder/table_body.rb +17 -0
- data/lib/coradoc/mirror/reverse_builder/table_cell.rb +24 -0
- data/lib/coradoc/mirror/reverse_builder/table_head.rb +17 -0
- data/lib/coradoc/mirror/reverse_builder/table_row.rb +18 -0
- data/lib/coradoc/mirror/reverse_builder/text.rb +24 -0
- data/lib/coradoc/mirror/reverse_builder/toc.rb +17 -0
- data/lib/coradoc/mirror/reverse_builder/toc_entry.rb +18 -0
- data/lib/coradoc/mirror/reverse_builder/verse.rb +20 -0
- data/lib/coradoc/mirror/reverse_builder.rb +59 -574
- data/lib/coradoc/mirror/version.rb +1 -1
- data/lib/coradoc/mirror.rb +2 -0
- data/lib/coradoc-mirror.rb +0 -2
- metadata +45 -2
- data/lib/coradoc/mirror/output.rb +0 -62
|
@@ -6,25 +6,26 @@ module Coradoc
|
|
|
6
6
|
#
|
|
7
7
|
# Adding support for a new Mirror node type is purely additive:
|
|
8
8
|
#
|
|
9
|
-
#
|
|
9
|
+
# # reverse_builder/<name>.rb
|
|
10
|
+
# require_relative 'base'
|
|
11
|
+
# module Coradoc::Mirror::ReverseBuilder
|
|
10
12
|
# class Figure < Base
|
|
11
13
|
# registers 'figure'
|
|
12
|
-
#
|
|
13
|
-
# def build(node)
|
|
14
|
-
# CoreModel::Image.new(src: node.src, ...)
|
|
15
|
-
# end
|
|
14
|
+
# def build(node) = CoreModel::Image.new(...)
|
|
16
15
|
# end
|
|
17
16
|
# end
|
|
18
17
|
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
18
|
+
# Then add a single `require_relative` for the new file below. No edits
|
|
19
|
+
# to MirrorToCoreModel or any other existing class — the registry is
|
|
20
|
+
# the single source of truth for "which type string maps to which
|
|
21
|
+
# builder" (MECE).
|
|
22
22
|
#
|
|
23
23
|
# This file is the autoload target for the ReverseBuilder constant
|
|
24
|
-
# (see coradoc/mirror.rb).
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
# lives in MarkReverseBuilder
|
|
24
|
+
# (see coradoc/mirror.rb). Each Builder subclass lives in its own
|
|
25
|
+
# file under reverse_builder/; eager-requiring them here populates
|
|
26
|
+
# the REGISTRY at load time so every caller sees a full registry.
|
|
27
|
+
# Mirror-level mark dispatch lives in MarkReverseBuilder
|
|
28
|
+
# (mark_reverse_builder.rb).
|
|
28
29
|
module ReverseBuilder
|
|
29
30
|
# Not frozen: subclasses call `register` from their class body at
|
|
30
31
|
# load time, and `registers` may fire late via autoload. Freezing
|
|
@@ -45,568 +46,52 @@ module Coradoc
|
|
|
45
46
|
REGISTRY.keys
|
|
46
47
|
end
|
|
47
48
|
|
|
48
|
-
# Base
|
|
49
|
-
#
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
)
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# All JS SECTION_TYPES reverse to a generic SectionElement. Style
|
|
99
|
-
# information lives in the original AsciiDoc and is preserved only
|
|
100
|
-
# on the forward side; the reverse side collapses them.
|
|
101
|
-
class Section < Base
|
|
102
|
-
registers 'section', 'clause', 'annex', 'content_section',
|
|
103
|
-
'abstract', 'foreword', 'introduction',
|
|
104
|
-
'acknowledgements', 'terms', 'definitions', 'references'
|
|
105
|
-
|
|
106
|
-
def build(node)
|
|
107
|
-
attrs = node.attrs
|
|
108
|
-
CoreModel::SectionElement.new(
|
|
109
|
-
title: attrs&.title,
|
|
110
|
-
level: attrs&.level,
|
|
111
|
-
id: attrs&.id,
|
|
112
|
-
children: build_content(node)
|
|
113
|
-
)
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
class Header < Base
|
|
118
|
-
registers 'floating_title', 'heading'
|
|
119
|
-
|
|
120
|
-
def build(node)
|
|
121
|
-
attrs = node.attrs
|
|
122
|
-
CoreModel::HeaderElement.new(
|
|
123
|
-
title: attrs&.title,
|
|
124
|
-
level: attrs&.level,
|
|
125
|
-
children: build_content(node)
|
|
126
|
-
)
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
class Preamble < Base
|
|
131
|
-
registers 'preface'
|
|
132
|
-
|
|
133
|
-
def build(node)
|
|
134
|
-
CoreModel::PreambleElement.new(children: build_content(node))
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
# `sections` is a structural container only — unwrap directly into
|
|
139
|
-
# an array. MirrorToCoreModel#build_content flattens arrays.
|
|
140
|
-
class Sections < Base
|
|
141
|
-
registers 'sections'
|
|
142
|
-
|
|
143
|
-
def build(node)
|
|
144
|
-
build_content(node)
|
|
145
|
-
end
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
# ── Blocks ──
|
|
149
|
-
|
|
150
|
-
class Paragraph < Base
|
|
151
|
-
registers 'paragraph'
|
|
152
|
-
|
|
153
|
-
def build(node)
|
|
154
|
-
CoreModel::ParagraphBlock.new(children: build_inline_children(node))
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
class CodeBlock < Base
|
|
159
|
-
registers 'sourcecode'
|
|
160
|
-
|
|
161
|
-
def build(node)
|
|
162
|
-
attrs = node.attrs
|
|
163
|
-
CoreModel::SourceBlock.new(
|
|
164
|
-
content: attrs&.text || extract_text(node),
|
|
165
|
-
language: attrs&.language,
|
|
166
|
-
title: attrs&.title
|
|
167
|
-
)
|
|
168
|
-
end
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
class Blockquote < Base
|
|
172
|
-
registers 'quote'
|
|
173
|
-
|
|
174
|
-
def build(node)
|
|
175
|
-
CoreModel::QuoteBlock.new(
|
|
176
|
-
attribution: node.attrs&.attribution,
|
|
177
|
-
children: build_content(node)
|
|
178
|
-
)
|
|
179
|
-
end
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
class Example < Base
|
|
183
|
-
registers 'example'
|
|
184
|
-
|
|
185
|
-
def build(node)
|
|
186
|
-
CoreModel::ExampleBlock.new(
|
|
187
|
-
title: node.attrs&.title,
|
|
188
|
-
children: build_content(node)
|
|
189
|
-
)
|
|
190
|
-
end
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
class Sidebar < Base
|
|
194
|
-
registers 'sidebar'
|
|
195
|
-
|
|
196
|
-
def build(node)
|
|
197
|
-
CoreModel::SidebarBlock.new(
|
|
198
|
-
title: node.attrs&.title,
|
|
199
|
-
children: build_content(node)
|
|
200
|
-
)
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
class OpenBlock < Base
|
|
205
|
-
registers 'open_block'
|
|
206
|
-
|
|
207
|
-
def build(node)
|
|
208
|
-
CoreModel::OpenBlock.new(children: build_content(node))
|
|
209
|
-
end
|
|
210
|
-
end
|
|
211
|
-
|
|
212
|
-
class Verse < Base
|
|
213
|
-
registers 'verse'
|
|
214
|
-
|
|
215
|
-
def build(node)
|
|
216
|
-
CoreModel::VerseBlock.new(
|
|
217
|
-
content: extract_text(node),
|
|
218
|
-
attribution: node.attrs&.attribution
|
|
219
|
-
)
|
|
220
|
-
end
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
class HorizontalRule < Base
|
|
224
|
-
registers 'horizontal_rule', 'thematic_break'
|
|
225
|
-
|
|
226
|
-
def build(_node)
|
|
227
|
-
CoreModel::HorizontalRuleBlock.new
|
|
228
|
-
end
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
class Frontmatter < Base
|
|
232
|
-
registers 'frontmatter'
|
|
233
|
-
|
|
234
|
-
def build(node)
|
|
235
|
-
attrs = node.attrs
|
|
236
|
-
CoreModel::FrontmatterBlock.new(
|
|
237
|
-
schema: attrs&.schema,
|
|
238
|
-
data: FrontmatterTreeToHash.to_hash(attrs&.entries || [])
|
|
239
|
-
)
|
|
240
|
-
end
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
class Admonition < Base
|
|
244
|
-
registers 'admonition'
|
|
245
|
-
|
|
246
|
-
def build(node)
|
|
247
|
-
CoreModel::AnnotationBlock.new(
|
|
248
|
-
annotation_type: node.attrs&.admonition_type,
|
|
249
|
-
content: extract_text(node)
|
|
250
|
-
)
|
|
251
|
-
end
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
# ── Lists ──
|
|
255
|
-
|
|
256
|
-
class BulletList < Base
|
|
257
|
-
registers 'bullet_list'
|
|
258
|
-
|
|
259
|
-
def build(node)
|
|
260
|
-
items = build_content(node).select { |c| c.is_a?(CoreModel::ListItem) }
|
|
261
|
-
CoreModel::ListBlock.new(marker_type: 'unordered', items: items)
|
|
262
|
-
end
|
|
263
|
-
end
|
|
264
|
-
|
|
265
|
-
class OrderedList < Base
|
|
266
|
-
registers 'ordered_list'
|
|
267
|
-
|
|
268
|
-
def build(node)
|
|
269
|
-
items = build_content(node).select { |c| c.is_a?(CoreModel::ListItem) }
|
|
270
|
-
CoreModel::ListBlock.new(marker_type: 'ordered', items: items)
|
|
271
|
-
end
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
class ListItem < Base
|
|
275
|
-
registers 'list_item'
|
|
276
|
-
|
|
277
|
-
def build(node)
|
|
278
|
-
children = build_inline_children(node)
|
|
279
|
-
text = children.map { |c| c.is_a?(CoreModel::TextContent) ? c.text : '' }.join
|
|
280
|
-
|
|
281
|
-
CoreModel::ListItem.new(
|
|
282
|
-
content: text,
|
|
283
|
-
children: children,
|
|
284
|
-
nested_list: find_nested_list(node)
|
|
285
|
-
)
|
|
286
|
-
end
|
|
287
|
-
|
|
288
|
-
private
|
|
289
|
-
|
|
290
|
-
def find_nested_list(node)
|
|
291
|
-
node.content&.each do |child|
|
|
292
|
-
next unless child.is_a?(Node)
|
|
293
|
-
return build_node(child) if LIST_TYPES.include?(child.type)
|
|
294
|
-
end
|
|
295
|
-
nil
|
|
296
|
-
end
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
class DefinitionList < Base
|
|
300
|
-
registers 'dl'
|
|
301
|
-
|
|
302
|
-
def build(node)
|
|
303
|
-
terms = []
|
|
304
|
-
descriptions = []
|
|
305
|
-
node.content&.each do |child|
|
|
306
|
-
next unless child.is_a?(Node)
|
|
307
|
-
|
|
308
|
-
case child.type
|
|
309
|
-
when 'dt' then terms << build_node(child)
|
|
310
|
-
when 'dd' then descriptions << build_node(child)
|
|
311
|
-
end
|
|
312
|
-
end
|
|
313
|
-
|
|
314
|
-
items = terms.zip(descriptions).map do |term, desc|
|
|
315
|
-
CoreModel::DefinitionItem.new(
|
|
316
|
-
term: inline_content(term),
|
|
317
|
-
definitions: [inline_content(desc)]
|
|
318
|
-
)
|
|
319
|
-
end
|
|
320
|
-
|
|
321
|
-
CoreModel::DefinitionList.new(items: items)
|
|
322
|
-
end
|
|
323
|
-
end
|
|
324
|
-
|
|
325
|
-
class InlineText < Base
|
|
326
|
-
registers 'dt', 'dd'
|
|
327
|
-
|
|
328
|
-
def build(node)
|
|
329
|
-
children = build_inline_children(node)
|
|
330
|
-
text = children.map { |c| c.is_a?(CoreModel::TextContent) ? c.text : '' }.join
|
|
331
|
-
CoreModel::InlineElement.new(content: text)
|
|
332
|
-
end
|
|
333
|
-
end
|
|
334
|
-
|
|
335
|
-
# ── Media ──
|
|
336
|
-
|
|
337
|
-
class Image < Base
|
|
338
|
-
registers 'image'
|
|
339
|
-
|
|
340
|
-
def build(node)
|
|
341
|
-
attrs = node.attrs
|
|
342
|
-
CoreModel::Image.new(
|
|
343
|
-
src: attrs&.src,
|
|
344
|
-
alt: attrs&.alt,
|
|
345
|
-
title: attrs&.title,
|
|
346
|
-
caption: attrs&.caption,
|
|
347
|
-
width: attrs&.width,
|
|
348
|
-
height: attrs&.height
|
|
349
|
-
)
|
|
350
|
-
end
|
|
351
|
-
end
|
|
352
|
-
|
|
353
|
-
# JS @metanorma/mirror `figure` wraps an image plus an optional
|
|
354
|
-
# caption. Reverse: collapse back to a single CoreModel::Image,
|
|
355
|
-
# promoting the caption child to `caption:` if present.
|
|
356
|
-
class Figure < Base
|
|
357
|
-
registers 'figure'
|
|
358
|
-
|
|
359
|
-
def build(node)
|
|
360
|
-
image_child = node.content&.find { |c| c.is_a?(Node) && c.type == 'image' }
|
|
361
|
-
return nil unless image_child
|
|
362
|
-
|
|
363
|
-
image = build_node(image_child)
|
|
364
|
-
caption = extract_caption(node)
|
|
365
|
-
image.caption = caption if caption && !image.caption
|
|
366
|
-
image
|
|
367
|
-
end
|
|
368
|
-
|
|
369
|
-
private
|
|
370
|
-
|
|
371
|
-
def extract_caption(node)
|
|
372
|
-
caption_node = node.content&.find { |c| c.is_a?(Node) && c.type == 'caption' }
|
|
373
|
-
return nil unless caption_node
|
|
374
|
-
|
|
375
|
-
extract_text(caption_node)
|
|
376
|
-
end
|
|
377
|
-
end
|
|
378
|
-
|
|
379
|
-
# Caption only appears as a Figure child. If encountered standalone,
|
|
380
|
-
# extract its text as an inline element so it isn't lost.
|
|
381
|
-
class Caption < Base
|
|
382
|
-
registers 'caption'
|
|
383
|
-
|
|
384
|
-
def build(node)
|
|
385
|
-
CoreModel::InlineElement.new(content: extract_text(node))
|
|
386
|
-
end
|
|
387
|
-
end
|
|
388
|
-
|
|
389
|
-
# Include directive: round-trips back to a CoreModel::Include link
|
|
390
|
-
# node. The text graph is preserved through mirror_json → core.
|
|
391
|
-
class Include < Base
|
|
392
|
-
registers 'include'
|
|
393
|
-
|
|
394
|
-
def build(node)
|
|
395
|
-
attrs = node.attrs
|
|
396
|
-
CoreModel::Include.new(
|
|
397
|
-
target: attrs&.target,
|
|
398
|
-
options: build_options(attrs),
|
|
399
|
-
raw_options: attrs&.raw_options || ''
|
|
400
|
-
)
|
|
401
|
-
end
|
|
402
|
-
|
|
403
|
-
private
|
|
404
|
-
|
|
405
|
-
def build_options(attrs)
|
|
406
|
-
return CoreModel::IncludeOptions.new unless attrs
|
|
407
|
-
|
|
408
|
-
CoreModel::IncludeOptions.new(
|
|
409
|
-
tags: Array(attrs.tags),
|
|
410
|
-
tags_wildcard: attrs.tags == ['*'],
|
|
411
|
-
tags_inverted: attrs.tags == ['**'],
|
|
412
|
-
lines_spec: attrs.lines,
|
|
413
|
-
leveloffset: parse_leveloffset(attrs.leveloffset),
|
|
414
|
-
indent: attrs.indent,
|
|
415
|
-
file_encoding: attrs.file_encoding
|
|
416
|
-
)
|
|
417
|
-
end
|
|
418
|
-
|
|
419
|
-
def parse_leveloffset(raw)
|
|
420
|
-
return nil if raw.nil? || raw.to_s.empty?
|
|
421
|
-
|
|
422
|
-
Coradoc::CoreModel::IncludeLevelOffset.parse(raw.to_s)
|
|
423
|
-
end
|
|
424
|
-
end
|
|
425
|
-
|
|
426
|
-
# ── Tables ──
|
|
427
|
-
|
|
428
|
-
class Table < Base
|
|
429
|
-
registers 'table'
|
|
430
|
-
|
|
431
|
-
def build(node)
|
|
432
|
-
rows = []
|
|
433
|
-
node.content&.each do |child|
|
|
434
|
-
next unless child.is_a?(Node)
|
|
435
|
-
next unless %w[table_head table_body].include?(child.type)
|
|
436
|
-
|
|
437
|
-
child.content&.each do |row_node|
|
|
438
|
-
rows << build_node(row_node) if row_node.is_a?(Node)
|
|
439
|
-
end
|
|
440
|
-
end
|
|
441
|
-
|
|
442
|
-
CoreModel::Table.new(title: node.attrs&.title, rows: rows)
|
|
443
|
-
end
|
|
444
|
-
end
|
|
445
|
-
|
|
446
|
-
class TableHead < Base
|
|
447
|
-
registers 'table_head'
|
|
448
|
-
|
|
449
|
-
def build(node)
|
|
450
|
-
build_content(node).first || CoreModel::TableRow.new
|
|
451
|
-
end
|
|
452
|
-
end
|
|
453
|
-
|
|
454
|
-
class TableBody < Base
|
|
455
|
-
registers 'table_body'
|
|
456
|
-
|
|
457
|
-
def build(node)
|
|
458
|
-
build_content(node).first || CoreModel::TableRow.new
|
|
459
|
-
end
|
|
460
|
-
end
|
|
461
|
-
|
|
462
|
-
class TableRow < Base
|
|
463
|
-
registers 'table_row'
|
|
464
|
-
|
|
465
|
-
def build(node)
|
|
466
|
-
cells = build_content(node).select { |c| c.is_a?(CoreModel::TableCell) }
|
|
467
|
-
CoreModel::TableRow.new(cells: cells)
|
|
468
|
-
end
|
|
469
|
-
end
|
|
470
|
-
|
|
471
|
-
class TableCell < Base
|
|
472
|
-
registers 'table_cell'
|
|
473
|
-
|
|
474
|
-
def build(node)
|
|
475
|
-
attrs = node.attrs
|
|
476
|
-
CoreModel::TableCell.new(
|
|
477
|
-
content: extract_text(node),
|
|
478
|
-
header: attrs&.header || false,
|
|
479
|
-
colspan: attrs&.colspan,
|
|
480
|
-
rowspan: attrs&.rowspan,
|
|
481
|
-
alignment: attrs&.alignment
|
|
482
|
-
)
|
|
483
|
-
end
|
|
484
|
-
end
|
|
485
|
-
|
|
486
|
-
# ── Bibliography ──
|
|
487
|
-
|
|
488
|
-
class Bibliography < Base
|
|
489
|
-
registers 'bibliography'
|
|
490
|
-
|
|
491
|
-
def build(node)
|
|
492
|
-
entries = build_content(node).select { |c| c.is_a?(CoreModel::BibliographyEntry) }
|
|
493
|
-
CoreModel::Bibliography.new(title: node.attrs&.title, entries: entries)
|
|
494
|
-
end
|
|
495
|
-
end
|
|
496
|
-
|
|
497
|
-
class BiblioEntry < Base
|
|
498
|
-
registers 'biblio_entry'
|
|
499
|
-
|
|
500
|
-
def build(node)
|
|
501
|
-
attrs = node.attrs
|
|
502
|
-
CoreModel::BibliographyEntry.new(
|
|
503
|
-
anchor_name: attrs&.anchor_name,
|
|
504
|
-
document_id: attrs&.document_id,
|
|
505
|
-
ref_text: extract_text(node)
|
|
506
|
-
)
|
|
507
|
-
end
|
|
508
|
-
end
|
|
509
|
-
|
|
510
|
-
# ── Footnotes ──
|
|
511
|
-
|
|
512
|
-
# The `footnotes` block is a structural trailing container; it has
|
|
513
|
-
# no CoreModel equivalent (each entry is built separately). Returns
|
|
514
|
-
# nil so build_content filters it out.
|
|
515
|
-
class Footnotes < Base
|
|
516
|
-
registers 'footnotes'
|
|
517
|
-
|
|
518
|
-
def build(_node)
|
|
519
|
-
nil
|
|
520
|
-
end
|
|
521
|
-
end
|
|
522
|
-
|
|
523
|
-
class FootnoteEntry < Base
|
|
524
|
-
registers 'footnote_entry'
|
|
525
|
-
|
|
526
|
-
def build(node)
|
|
527
|
-
attrs = node.attrs
|
|
528
|
-
CoreModel::Footnote.new(id: attrs&.id, content: extract_text(node))
|
|
529
|
-
end
|
|
530
|
-
end
|
|
531
|
-
|
|
532
|
-
# Inline footnote marker (JS `footnote_marker`). The CoreModel
|
|
533
|
-
# FootnoteReference holds the same id/ref/number triple.
|
|
534
|
-
class FootnoteMarker < Base
|
|
535
|
-
registers 'footnote_marker'
|
|
536
|
-
|
|
537
|
-
def build(node)
|
|
538
|
-
attrs = node.attrs
|
|
539
|
-
CoreModel::FootnoteReference.new(
|
|
540
|
-
id: attrs&.id,
|
|
541
|
-
reference: attrs&.ref_id,
|
|
542
|
-
number: attrs&.number
|
|
543
|
-
)
|
|
544
|
-
end
|
|
545
|
-
end
|
|
546
|
-
|
|
547
|
-
# ── TOC ──
|
|
548
|
-
|
|
549
|
-
class Toc < Base
|
|
550
|
-
registers 'toc'
|
|
551
|
-
|
|
552
|
-
def build(_node)
|
|
553
|
-
CoreModel::Toc.new
|
|
554
|
-
end
|
|
555
|
-
end
|
|
556
|
-
|
|
557
|
-
class TocEntry < Base
|
|
558
|
-
registers 'toc_entry'
|
|
559
|
-
|
|
560
|
-
def build(node)
|
|
561
|
-
attrs = node.attrs
|
|
562
|
-
CoreModel::TocEntry.new(id: attrs&.id, title: attrs&.title)
|
|
563
|
-
end
|
|
564
|
-
end
|
|
565
|
-
|
|
566
|
-
# ── Inline ──
|
|
567
|
-
|
|
568
|
-
class Text < Base
|
|
569
|
-
registers 'text'
|
|
570
|
-
|
|
571
|
-
def build(node)
|
|
572
|
-
text = node.text || ''
|
|
573
|
-
marks = node.marks || []
|
|
574
|
-
|
|
575
|
-
return CoreModel::TextContent.new(text: text) if marks.empty?
|
|
576
|
-
|
|
577
|
-
marks.reduce(CoreModel::TextContent.new(text: text)) do |current, mark|
|
|
578
|
-
apply_mark(current, mark)
|
|
579
|
-
end
|
|
580
|
-
end
|
|
581
|
-
end
|
|
582
|
-
|
|
583
|
-
class SoftBreak < Base
|
|
584
|
-
registers 'soft_break'
|
|
585
|
-
|
|
586
|
-
def build(_node)
|
|
587
|
-
CoreModel::LineBreakElement.new
|
|
588
|
-
end
|
|
589
|
-
end
|
|
590
|
-
|
|
591
|
-
# Catch-all for unrecognized block types emitted by the forward
|
|
592
|
-
# direction (`Node::GenericBlock`). Preserves the semantic_type so
|
|
593
|
-
# downstream consumers can dispatch on it.
|
|
594
|
-
class GenericBlock < Base
|
|
595
|
-
registers 'generic_block'
|
|
596
|
-
|
|
597
|
-
def build(node)
|
|
598
|
-
attrs = node.attrs
|
|
599
|
-
CoreModel::Block.new(
|
|
600
|
-
block_semantic_type: attrs&.semantic_type || 'generic',
|
|
601
|
-
title: attrs&.title,
|
|
602
|
-
id: attrs&.id,
|
|
603
|
-
content: extract_text(node)
|
|
604
|
-
)
|
|
605
|
-
end
|
|
606
|
-
end
|
|
607
|
-
|
|
608
|
-
LIST_TYPES = %w[bullet_list ordered_list].freeze
|
|
609
|
-
private_constant :LIST_TYPES
|
|
49
|
+
# Base must load first — every subclass inherits from it. Then
|
|
50
|
+
# eager-load each Builder so its `registers` call runs.
|
|
51
|
+
require_relative 'reverse_builder/base'
|
|
52
|
+
require_relative 'reverse_builder/document'
|
|
53
|
+
require_relative 'reverse_builder/section'
|
|
54
|
+
require_relative 'reverse_builder/header'
|
|
55
|
+
require_relative 'reverse_builder/preamble'
|
|
56
|
+
require_relative 'reverse_builder/sections'
|
|
57
|
+
require_relative 'reverse_builder/paragraph'
|
|
58
|
+
require_relative 'reverse_builder/code_block'
|
|
59
|
+
require_relative 'reverse_builder/literal_block'
|
|
60
|
+
require_relative 'reverse_builder/pass_block'
|
|
61
|
+
require_relative 'reverse_builder/stem_block'
|
|
62
|
+
require_relative 'reverse_builder/blockquote'
|
|
63
|
+
require_relative 'reverse_builder/example'
|
|
64
|
+
require_relative 'reverse_builder/sidebar'
|
|
65
|
+
require_relative 'reverse_builder/open_block'
|
|
66
|
+
require_relative 'reverse_builder/verse'
|
|
67
|
+
require_relative 'reverse_builder/horizontal_rule'
|
|
68
|
+
require_relative 'reverse_builder/frontmatter'
|
|
69
|
+
require_relative 'reverse_builder/admonition'
|
|
70
|
+
require_relative 'reverse_builder/bullet_list'
|
|
71
|
+
require_relative 'reverse_builder/ordered_list'
|
|
72
|
+
require_relative 'reverse_builder/list_item'
|
|
73
|
+
require_relative 'reverse_builder/definition_list'
|
|
74
|
+
require_relative 'reverse_builder/inline_text'
|
|
75
|
+
require_relative 'reverse_builder/image'
|
|
76
|
+
require_relative 'reverse_builder/figure'
|
|
77
|
+
require_relative 'reverse_builder/caption'
|
|
78
|
+
require_relative 'reverse_builder/include'
|
|
79
|
+
require_relative 'reverse_builder/table'
|
|
80
|
+
require_relative 'reverse_builder/table_head'
|
|
81
|
+
require_relative 'reverse_builder/table_body'
|
|
82
|
+
require_relative 'reverse_builder/table_row'
|
|
83
|
+
require_relative 'reverse_builder/table_cell'
|
|
84
|
+
require_relative 'reverse_builder/bibliography'
|
|
85
|
+
require_relative 'reverse_builder/biblio_entry'
|
|
86
|
+
require_relative 'reverse_builder/footnotes'
|
|
87
|
+
require_relative 'reverse_builder/footnote_entry'
|
|
88
|
+
require_relative 'reverse_builder/footnote_marker'
|
|
89
|
+
require_relative 'reverse_builder/toc'
|
|
90
|
+
require_relative 'reverse_builder/toc_entry'
|
|
91
|
+
require_relative 'reverse_builder/text'
|
|
92
|
+
require_relative 'reverse_builder/raw_inline'
|
|
93
|
+
require_relative 'reverse_builder/soft_break'
|
|
94
|
+
require_relative 'reverse_builder/generic_block'
|
|
610
95
|
end
|
|
611
96
|
end
|
|
612
97
|
end
|
data/lib/coradoc/mirror.rb
CHANGED
|
@@ -68,6 +68,8 @@ module Coradoc
|
|
|
68
68
|
method_name: :literal)
|
|
69
69
|
registry.register(CoreModel::PassBlock, Handlers::CodeBlock,
|
|
70
70
|
method_name: :pass)
|
|
71
|
+
registry.register(CoreModel::StemBlock, Handlers::CodeBlock,
|
|
72
|
+
method_name: :stem)
|
|
71
73
|
|
|
72
74
|
# ── Blocks ──
|
|
73
75
|
registry.register(CoreModel::QuoteBlock, Handlers::Blockquote)
|
data/lib/coradoc-mirror.rb
CHANGED
|
@@ -3,10 +3,8 @@
|
|
|
3
3
|
require 'coradoc'
|
|
4
4
|
require_relative 'coradoc/mirror'
|
|
5
5
|
|
|
6
|
-
# Side-effect: registers output processors with Coradoc::Output pipeline.
|
|
7
6
|
# Side-effect: registers format modules with Coradoc registry.
|
|
8
7
|
# These must use require (not autoload) because they have load-time side effects.
|
|
9
|
-
require_relative 'coradoc/mirror/output'
|
|
10
8
|
require_relative 'coradoc/mirror/mirror_json_format'
|
|
11
9
|
require_relative 'coradoc/mirror/mirror_yaml_format'
|
|
12
10
|
|