coradoc-mirror 0.1.7 → 0.1.8
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/core_model_to_mirror.rb +17 -0
- data/lib/coradoc/mirror/handlers/inline.rb +5 -1
- data/lib/coradoc/mirror/mirror_to_core_model.rb +21 -1
- data/lib/coradoc/mirror/node.rb +7 -0
- data/lib/coradoc/mirror/reverse_builder/abstract.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/admonition.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/biblio_entry.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/bibliography.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/blockquote.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/bullet_list.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/caption.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/code_block.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/definition_list.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/document.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/example.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/figure.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/footnote_entry.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/footnote_marker.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/footnotes.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/frontmatter.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/generic_block.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/hard_break.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/header.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/horizontal_rule.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/image.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/include.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/inline_text.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/list_item.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/literal_block.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/open_block.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/ordered_list.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/paragraph.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/partintro.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/pass_block.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/preamble.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/raw_inline.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/section.rb +0 -6
- data/lib/coradoc/mirror/reverse_builder/sections.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/sidebar.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/soft_break.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/stem_block.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/table.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/table_body.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/table_cell.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/table_head.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/table_row.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/text.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/toc.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/toc_entry.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder/verse.rb +0 -4
- data/lib/coradoc/mirror/reverse_builder.rb +122 -75
- data/lib/coradoc/mirror/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0a1079e6734d1795dd52788ca44ac74475590dbf6ccb9a576a5fcf4ef92f020d
|
|
4
|
+
data.tar.gz: ab04156585e16f2b4fa61337e3a9eca6b0f758ea82db4233c38f4422686fe611
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d3e532a097d574ac76f76c3ba863ad82fefc8c4007572a30c7d4c4bcad66f14008236a0ef9e4aca550c4f55b91f5dbc75740afac67aa2bcc18bce5c9aae0f0b9
|
|
7
|
+
data.tar.gz: 7bf8e4d4c71e20cb6cb1f71ef4a6e9c5cb1109a81c4fc1b5e85a2b462af197e3f5801827ceb30bce5ed7ce5f897ca3c2300d9fa27db699ee5a9eb239da9d4272
|
|
@@ -164,9 +164,26 @@ module Coradoc
|
|
|
164
164
|
value, concat = result
|
|
165
165
|
return unless value
|
|
166
166
|
|
|
167
|
+
propagate_source_line(value, element)
|
|
167
168
|
concat ? content.concat(Array(value)) : content << value
|
|
168
169
|
end
|
|
169
170
|
|
|
171
|
+
# Copy parser-attached source_line from the CoreModel element onto
|
|
172
|
+
# every Mirror node the handler produced. Single touchpoint for the
|
|
173
|
+
# entire CoreModel → Mirror direction — handlers stay focused on
|
|
174
|
+
# per-type mapping and don't repeat this concern (DRY).
|
|
175
|
+
def propagate_source_line(value, element)
|
|
176
|
+
line = element.source_line
|
|
177
|
+
return unless line
|
|
178
|
+
|
|
179
|
+
Array(value).each do |node|
|
|
180
|
+
next unless node.is_a?(Node)
|
|
181
|
+
next if node.source_line
|
|
182
|
+
|
|
183
|
+
node.source_line = line
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
170
187
|
def build_document_attrs(document)
|
|
171
188
|
attrs = {}
|
|
172
189
|
attrs[:title] = document.title if document.title
|
|
@@ -208,7 +208,11 @@ module Coradoc
|
|
|
208
208
|
def extract_inline_text(element)
|
|
209
209
|
return element.content.to_s if element.content && !element.content.to_s.empty?
|
|
210
210
|
|
|
211
|
-
|
|
211
|
+
if element.is_a?(CoreModel::InlineElement) && element.nested_elements
|
|
212
|
+
return element.nested_elements.map do |nested|
|
|
213
|
+
extract_inline_text(nested)
|
|
214
|
+
end.join
|
|
215
|
+
end
|
|
212
216
|
|
|
213
217
|
if (element.is_a?(CoreModel::InlineElement) || element.is_a?(CoreModel::Block)) && element.children && !element.children.empty?
|
|
214
218
|
return element.children.map do |child|
|
|
@@ -19,7 +19,27 @@ module Coradoc
|
|
|
19
19
|
builder_class = ReverseBuilder.lookup(node.type)
|
|
20
20
|
raise Error, "Unknown mirror node type: #{node.type}" unless builder_class
|
|
21
21
|
|
|
22
|
-
builder_class.new(self).build(node)
|
|
22
|
+
result = builder_class.new(self).build(node)
|
|
23
|
+
propagate_source_line(result, node)
|
|
24
|
+
result
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Copy parser-attached source_line from the Mirror node onto every
|
|
28
|
+
# CoreModel node the builder produced. Single touchpoint for the
|
|
29
|
+
# entire Mirror → CoreModel direction — builders stay focused on
|
|
30
|
+
# per-type mapping and don't repeat this concern (DRY).
|
|
31
|
+
def propagate_source_line(result, node)
|
|
32
|
+
return unless node.is_a?(Node)
|
|
33
|
+
|
|
34
|
+
line = node.source_line
|
|
35
|
+
return unless line
|
|
36
|
+
|
|
37
|
+
Array(result).each do |built|
|
|
38
|
+
next unless built.is_a?(CoreModel::Base)
|
|
39
|
+
next if built.source_line
|
|
40
|
+
|
|
41
|
+
built.source_line = line
|
|
42
|
+
end
|
|
23
43
|
end
|
|
24
44
|
|
|
25
45
|
# ── Shared helpers (single source of truth — used by every
|
data/lib/coradoc/mirror/node.rb
CHANGED
|
@@ -29,6 +29,13 @@ module Coradoc
|
|
|
29
29
|
attribute :type, :string, default: -> { self.class::PM_TYPE }
|
|
30
30
|
attribute :content, Node, collection: true
|
|
31
31
|
attribute :marks, Mark, collection: true
|
|
32
|
+
# Parser metadata, single source of truth on the wire side too.
|
|
33
|
+
# Carried in memory so CoreModel → Mirror → CoreModel round-trips
|
|
34
|
+
# preserve the source location. Intentionally absent from every
|
|
35
|
+
# subclass `key_value` block: source_line is not part of the
|
|
36
|
+
# ProseMirror JSON contract — editor consumers don't need it, and
|
|
37
|
+
# serializing it would leak parser internals onto the wire.
|
|
38
|
+
attribute :source_line, :integer
|
|
32
39
|
|
|
33
40
|
key_value do
|
|
34
41
|
map 'type', to: :type, render_default: true
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
8
6
|
class Admonition < Base
|
|
9
|
-
registers 'admonition'
|
|
10
|
-
|
|
11
7
|
def build(node)
|
|
12
8
|
CoreModel::AnnotationBlock.new(
|
|
13
9
|
annotation_type: node.attrs&.admonition_type,
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
8
6
|
class Bibliography < Base
|
|
9
|
-
registers 'bibliography'
|
|
10
|
-
|
|
11
7
|
def build(node)
|
|
12
8
|
entries = build_content(node).select { |c| c.is_a?(CoreModel::BibliographyEntry) }
|
|
13
9
|
CoreModel::Bibliography.new(title: node.attrs&.title, entries: entries)
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
8
6
|
class Blockquote < Base
|
|
9
|
-
registers 'quote'
|
|
10
|
-
|
|
11
7
|
def build(node)
|
|
12
8
|
CoreModel::QuoteBlock.new(
|
|
13
9
|
attribution: node.attrs&.attribution,
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
8
6
|
class BulletList < Base
|
|
9
|
-
registers 'bullet_list'
|
|
10
|
-
|
|
11
7
|
def build(node)
|
|
12
8
|
items = build_content(node).select { |c| c.is_a?(CoreModel::ListItem) }
|
|
13
9
|
CoreModel::ListBlock.new(marker_type: 'unordered', items: items)
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
8
6
|
# Caption only appears as a Figure child. If encountered standalone,
|
|
9
7
|
# extract its text as an inline element so it isn't lost.
|
|
10
8
|
class Caption < Base
|
|
11
|
-
registers 'caption'
|
|
12
|
-
|
|
13
9
|
def build(node)
|
|
14
10
|
CoreModel::InlineElement.new(content: extract_text(node))
|
|
15
11
|
end
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
@@ -9,8 +7,6 @@ module Coradoc
|
|
|
9
7
|
# caption. Reverse: collapse back to a single CoreModel::Image,
|
|
10
8
|
# promoting the caption child to `caption:` if present.
|
|
11
9
|
class Figure < Base
|
|
12
|
-
registers 'figure'
|
|
13
|
-
|
|
14
10
|
def build(node)
|
|
15
11
|
image_child = node.content&.find { |c| c.is_a?(Node) && c.type == 'image' }
|
|
16
12
|
return nil unless image_child
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
8
6
|
class FootnoteEntry < Base
|
|
9
|
-
registers 'footnote_entry'
|
|
10
|
-
|
|
11
7
|
def build(node)
|
|
12
8
|
attrs = node.attrs
|
|
13
9
|
CoreModel::Footnote.new(id: attrs&.id, content: extract_text(node))
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
8
6
|
# Inline footnote marker (JS `footnote_marker`). The CoreModel
|
|
9
7
|
# FootnoteReference holds the same id/ref/number triple.
|
|
10
8
|
class FootnoteMarker < Base
|
|
11
|
-
registers 'footnote_marker'
|
|
12
|
-
|
|
13
9
|
def build(node)
|
|
14
10
|
attrs = node.attrs
|
|
15
11
|
CoreModel::FootnoteReference.new(
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
@@ -9,8 +7,6 @@ module Coradoc
|
|
|
9
7
|
# no CoreModel equivalent (each entry is built separately). Returns
|
|
10
8
|
# nil so build_content filters it out.
|
|
11
9
|
class Footnotes < Base
|
|
12
|
-
registers 'footnotes'
|
|
13
|
-
|
|
14
10
|
def build(_node)
|
|
15
11
|
nil
|
|
16
12
|
end
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
@@ -9,8 +7,6 @@ module Coradoc
|
|
|
9
7
|
# direction (`Node::GenericBlock`). Preserves the semantic_type so
|
|
10
8
|
# downstream consumers can dispatch on it.
|
|
11
9
|
class GenericBlock < Base
|
|
12
|
-
registers 'generic_block'
|
|
13
|
-
|
|
14
10
|
def build(node)
|
|
15
11
|
attrs = node.attrs
|
|
16
12
|
CoreModel::Block.new(
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
8
6
|
class Header < Base
|
|
9
|
-
registers 'floating_title', 'heading'
|
|
10
|
-
|
|
11
7
|
def build(node)
|
|
12
8
|
attrs = node.attrs
|
|
13
9
|
CoreModel::HeaderElement.new(
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
8
6
|
class HorizontalRule < Base
|
|
9
|
-
registers 'horizontal_rule', 'thematic_break'
|
|
10
|
-
|
|
11
7
|
def build(_node)
|
|
12
8
|
CoreModel::HorizontalRuleBlock.new
|
|
13
9
|
end
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
8
6
|
# Include directive: round-trips back to a CoreModel::Include link
|
|
9
7
|
# node. The text graph is preserved through mirror_json → core.
|
|
10
8
|
class Include < Base
|
|
11
|
-
registers 'include'
|
|
12
|
-
|
|
13
9
|
def build(node)
|
|
14
10
|
attrs = node.attrs
|
|
15
11
|
CoreModel::Include.new(
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
8
6
|
class InlineText < Base
|
|
9
|
-
registers 'dt', 'dd'
|
|
10
|
-
|
|
11
7
|
def build(node)
|
|
12
8
|
children = build_inline_children(node)
|
|
13
9
|
text = children.map { |c| c.is_a?(CoreModel::TextContent) ? c.text : '' }.join
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
8
6
|
class OrderedList < Base
|
|
9
|
-
registers 'ordered_list'
|
|
10
|
-
|
|
11
7
|
def build(node)
|
|
12
8
|
items = build_content(node).select { |c| c.is_a?(CoreModel::ListItem) }
|
|
13
9
|
CoreModel::ListBlock.new(marker_type: 'ordered', items: items)
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
8
6
|
class Paragraph < Base
|
|
9
|
-
registers 'paragraph'
|
|
10
|
-
|
|
11
7
|
def build(node)
|
|
12
8
|
CoreModel::ParagraphBlock.new(children: build_inline_children(node))
|
|
13
9
|
end
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
8
6
|
class Partintro < Base
|
|
9
|
-
registers 'partintro_block'
|
|
10
|
-
|
|
11
7
|
def build(node)
|
|
12
8
|
CoreModel::PartintroBlock.new(
|
|
13
9
|
title: node.attrs&.title,
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
8
6
|
class Preamble < Base
|
|
9
|
-
registers 'preface'
|
|
10
|
-
|
|
11
7
|
def build(node)
|
|
12
8
|
CoreModel::PreambleElement.new(children: build_content(node))
|
|
13
9
|
end
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
8
6
|
class RawInline < Base
|
|
9
|
-
registers 'raw_inline'
|
|
10
|
-
|
|
11
7
|
def build(node)
|
|
12
8
|
CoreModel::RawInlineElement.new(content: node.text.to_s)
|
|
13
9
|
end
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
@@ -9,10 +7,6 @@ module Coradoc
|
|
|
9
7
|
# information lives in the original AsciiDoc and is preserved only
|
|
10
8
|
# on the forward side; the reverse side collapses them.
|
|
11
9
|
class Section < Base
|
|
12
|
-
registers 'section', 'clause', 'annex', 'content_section',
|
|
13
|
-
'abstract', 'foreword', 'introduction',
|
|
14
|
-
'acknowledgements', 'terms', 'definitions', 'references'
|
|
15
|
-
|
|
16
10
|
def build(node)
|
|
17
11
|
attrs = node.attrs
|
|
18
12
|
CoreModel::SectionElement.new(
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
8
6
|
# `sections` is a structural container only — unwrap directly into
|
|
9
7
|
# an array. MirrorToCoreModel#build_content flattens arrays.
|
|
10
8
|
class Sections < Base
|
|
11
|
-
registers 'sections'
|
|
12
|
-
|
|
13
9
|
def build(node)
|
|
14
10
|
build_content(node)
|
|
15
11
|
end
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
8
6
|
class TableRow < Base
|
|
9
|
-
registers 'table_row'
|
|
10
|
-
|
|
11
7
|
def build(node)
|
|
12
8
|
cells = build_content(node).select { |c| c.is_a?(CoreModel::TableCell) }
|
|
13
9
|
CoreModel::TableRow.new(cells: cells)
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Mirror
|
|
7
5
|
module ReverseBuilder
|
|
8
6
|
class TocEntry < Base
|
|
9
|
-
registers 'toc_entry'
|
|
10
|
-
|
|
11
7
|
def build(node)
|
|
12
8
|
attrs = node.attrs
|
|
13
9
|
CoreModel::TocEntry.new(id: attrs&.id, title: attrs&.title)
|
|
@@ -2,34 +2,117 @@
|
|
|
2
2
|
|
|
3
3
|
module Coradoc
|
|
4
4
|
module Mirror
|
|
5
|
-
# OCP-compliant registry for Mirror node
|
|
5
|
+
# OCP-compliant registry for Mirror node → CoreModel transformation.
|
|
6
6
|
#
|
|
7
|
-
#
|
|
7
|
+
# Single source of truth: the TYPE_TO_FILE table below maps every
|
|
8
|
+
# Mirror wire type string (and its aliases) to the file that
|
|
9
|
+
# implements its builder. Two things derive from this one table:
|
|
8
10
|
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# class Figure < Base
|
|
13
|
-
# registers 'figure'
|
|
14
|
-
# def build(node) = CoreModel::Image.new(...)
|
|
15
|
-
# end
|
|
16
|
-
# end
|
|
11
|
+
# 1. autoload declarations — one per unique file, so builders
|
|
12
|
+
# load lazily on first lookup (no 47-file eager load at boot).
|
|
13
|
+
# 2. lookup() — type → file → const_get, which triggers autoload.
|
|
17
14
|
#
|
|
18
|
-
#
|
|
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).
|
|
15
|
+
# Adding a new built-in builder is purely additive:
|
|
22
16
|
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
17
|
+
# 1. Add `'<wire_type>' => '<file_basename>'` to TYPE_TO_FILE.
|
|
18
|
+
# 2. Create `reverse_builder/<file_basename>.rb` defining
|
|
19
|
+
# `class <CamelizedName> < Base; def build(node); ...; end; end`.
|
|
20
|
+
#
|
|
21
|
+
# No edits to this file beyond the table — autoload and lookup
|
|
22
|
+
# adapt automatically. Mirror-level mark dispatch lives in
|
|
23
|
+
# MarkReverseBuilder (mark_reverse_builder.rb).
|
|
24
|
+
#
|
|
25
|
+
# Third-party / runtime builders can still register via
|
|
26
|
+
# `ReverseBuilder.register(type, klass)`; they take precedence over
|
|
27
|
+
# built-in autoload entries.
|
|
29
28
|
module ReverseBuilder
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
#
|
|
29
|
+
autoload :Base, "#{__dir__}/reverse_builder/base"
|
|
30
|
+
|
|
31
|
+
# Wire type string → file basename under reverse_builder/.
|
|
32
|
+
# Aliases (e.g. 'clause' and 'annex' both route to section) are
|
|
33
|
+
# expressed by mapping multiple type strings to the same file.
|
|
34
|
+
TYPE_TO_FILE = {
|
|
35
|
+
'doc' => 'document',
|
|
36
|
+
'section' => 'section',
|
|
37
|
+
'clause' => 'section',
|
|
38
|
+
'annex' => 'section',
|
|
39
|
+
'content_section' => 'section',
|
|
40
|
+
'abstract' => 'section',
|
|
41
|
+
'foreword' => 'section',
|
|
42
|
+
'introduction' => 'section',
|
|
43
|
+
'acknowledgements' => 'section',
|
|
44
|
+
'terms' => 'section',
|
|
45
|
+
'definitions' => 'section',
|
|
46
|
+
'references' => 'section',
|
|
47
|
+
'sections' => 'sections',
|
|
48
|
+
'preface' => 'preamble',
|
|
49
|
+
'floating_title' => 'header',
|
|
50
|
+
'heading' => 'header',
|
|
51
|
+
'paragraph' => 'paragraph',
|
|
52
|
+
'sourcecode' => 'code_block',
|
|
53
|
+
'literal' => 'literal_block',
|
|
54
|
+
'pass' => 'pass_block',
|
|
55
|
+
'stem' => 'stem_block',
|
|
56
|
+
'quote' => 'blockquote',
|
|
57
|
+
'example' => 'example',
|
|
58
|
+
'sidebar' => 'sidebar',
|
|
59
|
+
'abstract_block' => 'abstract',
|
|
60
|
+
'partintro_block' => 'partintro',
|
|
61
|
+
'open_block' => 'open_block',
|
|
62
|
+
'verse' => 'verse',
|
|
63
|
+
'horizontal_rule' => 'horizontal_rule',
|
|
64
|
+
'thematic_break' => 'horizontal_rule',
|
|
65
|
+
'soft_break' => 'soft_break',
|
|
66
|
+
'hard_break' => 'hard_break',
|
|
67
|
+
'admonition' => 'admonition',
|
|
68
|
+
'bullet_list' => 'bullet_list',
|
|
69
|
+
'ordered_list' => 'ordered_list',
|
|
70
|
+
'list_item' => 'list_item',
|
|
71
|
+
'dl' => 'definition_list',
|
|
72
|
+
'dt' => 'inline_text',
|
|
73
|
+
'dd' => 'inline_text',
|
|
74
|
+
'image' => 'image',
|
|
75
|
+
'figure' => 'figure',
|
|
76
|
+
'caption' => 'caption',
|
|
77
|
+
'include' => 'include',
|
|
78
|
+
'table' => 'table',
|
|
79
|
+
'table_head' => 'table_head',
|
|
80
|
+
'table_body' => 'table_body',
|
|
81
|
+
'table_row' => 'table_row',
|
|
82
|
+
'table_cell' => 'table_cell',
|
|
83
|
+
'bibliography' => 'bibliography',
|
|
84
|
+
'biblio_entry' => 'biblio_entry',
|
|
85
|
+
'footnotes' => 'footnotes',
|
|
86
|
+
'footnote_entry' => 'footnote_entry',
|
|
87
|
+
'footnote_marker' => 'footnote_marker',
|
|
88
|
+
'toc' => 'toc',
|
|
89
|
+
'toc_entry' => 'toc_entry',
|
|
90
|
+
'text' => 'text',
|
|
91
|
+
'raw_inline' => 'raw_inline',
|
|
92
|
+
'frontmatter' => 'frontmatter',
|
|
93
|
+
'generic_block' => 'generic_block'
|
|
94
|
+
}.freeze
|
|
95
|
+
|
|
96
|
+
# File basename → Ruby constant name. Derived from the file name
|
|
97
|
+
# using the project-wide snake_case → CamelCase convention
|
|
98
|
+
# (every existing builder follows it). Declared once here so
|
|
99
|
+
# adding a builder that follows convention requires no extra
|
|
100
|
+
# wiring.
|
|
101
|
+
FILE_TO_CLASS = TYPE_TO_FILE.each_value.each_with_object({}) do |file, acc|
|
|
102
|
+
next if acc.key?(file)
|
|
103
|
+
|
|
104
|
+
acc[file] = file.split('_').map(&:capitalize).join
|
|
105
|
+
end.freeze
|
|
106
|
+
|
|
107
|
+
# Lazy-load each builder. Lookup triggers autoload via const_get.
|
|
108
|
+
FILE_TO_CLASS.each do |file, const_name|
|
|
109
|
+
autoload const_name.to_sym, "#{__dir__}/reverse_builder/#{file}"
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Runtime registrations from third-party / external builders.
|
|
113
|
+
# Takes precedence over built-in autoload entries so external
|
|
114
|
+
# code can override built-in behaviour (e.g. a custom Paragraph).
|
|
115
|
+
# Not frozen: register() writes here at runtime.
|
|
33
116
|
REGISTRY = {}
|
|
34
117
|
|
|
35
118
|
module_function
|
|
@@ -38,63 +121,27 @@ module Coradoc
|
|
|
38
121
|
REGISTRY[type] = builder_class
|
|
39
122
|
end
|
|
40
123
|
|
|
124
|
+
# DSL for subclasses to self-register at load time. Kept for
|
|
125
|
+
# backward compatibility with the existing OCP test pattern that
|
|
126
|
+
# creates synthetic builders via `Class.new(Base) { registers(...) }`.
|
|
127
|
+
# Built-in builders no longer call this — their dispatch is
|
|
128
|
+
# derived from TYPE_TO_FILE.
|
|
129
|
+
def registers(*types)
|
|
130
|
+
types.each { |t| register(t, self) }
|
|
131
|
+
end
|
|
132
|
+
|
|
41
133
|
def lookup(type)
|
|
42
|
-
REGISTRY[type]
|
|
134
|
+
return REGISTRY[type] if REGISTRY.key?(type)
|
|
135
|
+
|
|
136
|
+
file = TYPE_TO_FILE[type]
|
|
137
|
+
return nil unless file
|
|
138
|
+
|
|
139
|
+
const_get(FILE_TO_CLASS[file])
|
|
43
140
|
end
|
|
44
141
|
|
|
45
142
|
def registered_types
|
|
46
|
-
REGISTRY.keys
|
|
143
|
+
(REGISTRY.keys + TYPE_TO_FILE.keys).uniq
|
|
47
144
|
end
|
|
48
|
-
|
|
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/abstract'
|
|
66
|
-
require_relative 'reverse_builder/partintro'
|
|
67
|
-
require_relative 'reverse_builder/open_block'
|
|
68
|
-
require_relative 'reverse_builder/verse'
|
|
69
|
-
require_relative 'reverse_builder/horizontal_rule'
|
|
70
|
-
require_relative 'reverse_builder/frontmatter'
|
|
71
|
-
require_relative 'reverse_builder/admonition'
|
|
72
|
-
require_relative 'reverse_builder/bullet_list'
|
|
73
|
-
require_relative 'reverse_builder/ordered_list'
|
|
74
|
-
require_relative 'reverse_builder/list_item'
|
|
75
|
-
require_relative 'reverse_builder/definition_list'
|
|
76
|
-
require_relative 'reverse_builder/inline_text'
|
|
77
|
-
require_relative 'reverse_builder/image'
|
|
78
|
-
require_relative 'reverse_builder/figure'
|
|
79
|
-
require_relative 'reverse_builder/caption'
|
|
80
|
-
require_relative 'reverse_builder/include'
|
|
81
|
-
require_relative 'reverse_builder/table'
|
|
82
|
-
require_relative 'reverse_builder/table_head'
|
|
83
|
-
require_relative 'reverse_builder/table_body'
|
|
84
|
-
require_relative 'reverse_builder/table_row'
|
|
85
|
-
require_relative 'reverse_builder/table_cell'
|
|
86
|
-
require_relative 'reverse_builder/bibliography'
|
|
87
|
-
require_relative 'reverse_builder/biblio_entry'
|
|
88
|
-
require_relative 'reverse_builder/footnotes'
|
|
89
|
-
require_relative 'reverse_builder/footnote_entry'
|
|
90
|
-
require_relative 'reverse_builder/footnote_marker'
|
|
91
|
-
require_relative 'reverse_builder/toc'
|
|
92
|
-
require_relative 'reverse_builder/toc_entry'
|
|
93
|
-
require_relative 'reverse_builder/text'
|
|
94
|
-
require_relative 'reverse_builder/raw_inline'
|
|
95
|
-
require_relative 'reverse_builder/soft_break'
|
|
96
|
-
require_relative 'reverse_builder/hard_break'
|
|
97
|
-
require_relative 'reverse_builder/generic_block'
|
|
98
145
|
end
|
|
99
146
|
end
|
|
100
147
|
end
|