Class: Coradoc::Mirror::CoreModelToMirror

Inherits:
Object
  • Object
show all
Defined in:
lib/coradoc/mirror/core_model_to_mirror.rb

Overview

Transforms CoreModel documents into ProseMirror-compatible Mirror nodes.

Uses a HandlerRegistry for OCP-compliant dispatch: each CoreModel type maps to a handler module/class that produces the corresponding Mirror node.

Defined Under Namespace

Classes: FootnoteData

Constant Summary collapse

COLLECTION_ACCESSORS =

Maps element types to their children accessors.

{
  CoreModel::ListBlock => :items,
  CoreModel::DefinitionList => :items,
  CoreModel::Table => :rows,
  CoreModel::Bibliography => :entries
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(registry: Coradoc::Mirror.default_registry) ⇒ CoreModelToMirror

Returns a new instance of CoreModelToMirror.



23
24
25
26
27
28
# File 'lib/coradoc/mirror/core_model_to_mirror.rb', line 23

def initialize(registry: Coradoc::Mirror.default_registry)
  @registry = registry
  @footnote_counter = 0
  @footnotes = []
  @partition_structural = false
end

Instance Attribute Details

#partition_structuralObject

Read by Handlers::Structural.section to decide whether to emit generic ‘section` (legacy) or a JS SECTION_TYPE (`clause`, `annex`, etc.) when partition_structural mode is on.



33
34
35
# File 'lib/coradoc/mirror/core_model_to_mirror.rb', line 33

def partition_structural
  @partition_structural
end

#registryObject (readonly)

Returns the value of attribute registry.



10
11
12
# File 'lib/coradoc/mirror/core_model_to_mirror.rb', line 10

def registry
  @registry
end

Instance Method Details

#call(document, partition_structural: false) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/coradoc/mirror/core_model_to_mirror.rb', line 35

def call(document, partition_structural: false)
  @footnote_counter = 0
  @footnotes = []
  @partition_structural = partition_structural

  content = extract_content(document)
  fn_block = flush_footnotes
  content << fn_block if fn_block

  attrs = build_document_attrs(document)
  Node::Document.new(
    attrs: Node::Document::Attrs.new(title: attrs[:title], id: attrs[:id]),
    content: partition_structural ? wrap_structural(content) : content
  )
end

#extract_content(element) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/coradoc/mirror/core_model_to_mirror.rb', line 64

def extract_content(element)
  children = element_children(element)

  if children && !children.empty?
    content = []
    children.each { |child| handle_element(child, content) }
    content.compact
  elsif element_has_text_content?(element)
    process_inline_content(element)
  else
    []
  end
end

#flush_footnotesObject



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/coradoc/mirror/core_model_to_mirror.rb', line 121

def flush_footnotes
  return nil if @footnotes.empty?

  entries = @footnotes.map do |fn|
    Node::FootnoteEntry.new(
      attrs: Node::FootnoteEntry::Attrs.new(
        id: fn.id, ref_id: fn.ref_id, number: fn.number
      ),
      content: fn.content
    )
  end

  @footnotes = []
  Node::Footnotes.new(content: entries)
end

#process_inline_content(element) ⇒ Object



78
79
80
# File 'lib/coradoc/mirror/core_model_to_mirror.rb', line 78

def process_inline_content(element)
  Handlers::Inline.process(element, context: self)
end

#register_footnote(footnote) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/coradoc/mirror/core_model_to_mirror.rb', line 86

def register_footnote(footnote)
  @footnote_counter += 1
  num = @footnote_counter
  fn_id = footnote.id || "fn-#{num}"
  ref_id = "fn-ref-#{num}"

  fn_content = footnote.content ? [text_node(footnote.content)] : []
  @footnotes << FootnoteData.new(
    id: fn_id, ref_id: ref_id, number: num, content: fn_content
  )

  Node::FootnoteMarker.new(
    attrs: Node::FootnoteMarker::Attrs.new(
      id: fn_id, ref_id: ref_id, number: num
    )
  )
end

#resolve_footnote_reference(ref) ⇒ Object



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/coradoc/mirror/core_model_to_mirror.rb', line 104

def resolve_footnote_reference(ref)
  target_id = ref.id
  entry = @footnotes.find { |fn| fn.id == target_id } if target_id

  if entry
    Node::FootnoteMarker.new(
      attrs: Node::FootnoteMarker::Attrs.new(
        id: entry.id,
        ref_id: "fn-ref-#{entry.number}-dup-#{@footnote_counter}",
        number: entry.number
      )
    )
  else
    text_node("[#{target_id || 'footnote'}]")
  end
end

#text_node(text, marks: []) ⇒ Object



82
83
84
# File 'lib/coradoc/mirror/core_model_to_mirror.rb', line 82

def text_node(text, marks: [])
  Node::Text.new(text: text, marks: marks)
end

#wrap_structural(children) ⇒ Object

Partitions flat doc children into [preface?, sections?, *bibliography, *trailing] per the @metanorma/mirror JS structural contract. See Partitioner for the bucketing rules.



54
55
56
57
58
59
60
61
62
# File 'lib/coradoc/mirror/core_model_to_mirror.rb', line 54

def wrap_structural(children)
  partitioned = Partitioner.partition(children)
  wrapped = []
  wrapped << Node::Preamble.new(content: partitioned[:preface]) if partitioned[:preface].any?
  wrapped << Node::Sections.new(content: partitioned[:sections]) if partitioned[:sections].any?
  wrapped.concat(partitioned[:bibliography])
  wrapped.concat(partitioned[:trailing])
  wrapped
end