coradoc-adoc 2.0.7 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a29195095ab66adca7be3bdfcb331f71fdd69954c09ea3fc0cef33c4583b8d8c
4
- data.tar.gz: 805db091f5043a01ce0b4ff1501c009814c4fdd079ca402a0232b2e3abf073dd
3
+ metadata.gz: d76a16bad8dc3e4567d425b8c464bd4469db6bb55cab06aa48621ffe8ed2dc60
4
+ data.tar.gz: 7d2c531af059b0108780acdeace458051a5f484cb130f695d329cd5e1c7376c0
5
5
  SHA512:
6
- metadata.gz: a306bb17db95c5732e1a7e76f101c45a00363c356ebdc0b3d699961caa1a82c6ce2be1f69c531922cb83f53eb49c58735ca814e14a0559a431ee8c9a5ed56a00
7
- data.tar.gz: 42c724be473f6bbdd0b9db339b0ac5a02590fa760f74178088536226380994ef52a812bb7730038e5fe66e25ad888a03b0a4b38c993dbdb5748a4f56e00923df
6
+ metadata.gz: ae0aed7da09b650dd45e5781f929b99923530840741509be68721f8a978511840d0f211b7572997309f40205597fccce47e914f0fa2a33d606865ffa8d927404
7
+ data.tar.gz: 7b09ddcf81d699f4deab3c6a7dbb74f42c91dddf1607ea20b1dfe439fd0fafa05144b5f667b3391e6b9e05542c6cb321012467598b7fe492160aa58383dfb05f
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module DelimiterMapping
6
+ CHAR_TO_SEMANTIC = {
7
+ '-' => :source_code,
8
+ '=' => :example,
9
+ '_' => :quote,
10
+ '*' => :sidebar,
11
+ '.' => :literal,
12
+ '+' => :pass
13
+ }.freeze
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Transform
6
+ module ElementTransformers
7
+ class BlockTransformer
8
+ class << self
9
+ def transform_paragraph(para)
10
+ children = ToCoreModel.transform_inline_content(para.content)
11
+
12
+ Coradoc::CoreModel::ParagraphBlock.new(
13
+ id: para.id,
14
+ content: ToCoreModel.extract_text_content(para.content),
15
+ children: children
16
+ )
17
+ end
18
+
19
+ def transform_source_block(block)
20
+ non_break_lines = Array(block.lines).reject do |line|
21
+ line.is_a?(Coradoc::AsciiDoc::Model::LineBreak) ||
22
+ line.is_a?(Coradoc::AsciiDoc::Model::Break::PageBreak)
23
+ end
24
+ content_lines = non_break_lines.map do |line|
25
+ ToCoreModel.extract_text_content(line)
26
+ end.join("\n")
27
+
28
+ language = ToCoreModel.extract_block_language(block)
29
+
30
+ Coradoc::CoreModel::SourceBlock.new(
31
+ id: block.id,
32
+ title: ToCoreModel.extract_title_text(block.title),
33
+ content: content_lines,
34
+ language: language
35
+ )
36
+ end
37
+
38
+ def transform_block(block, semantic_type_or_delimiter)
39
+ content_lines = ToCoreModel.extract_block_lines(block)
40
+ semantic_type = if semantic_type_or_delimiter.is_a?(Symbol)
41
+ semantic_type_or_delimiter
42
+ else
43
+ ToCoreModel.asciidoc_delimiter_to_semantic(semantic_type_or_delimiter)
44
+ end
45
+
46
+ Coradoc::CoreModel::Block.new(
47
+ block_semantic_type: semantic_type,
48
+ delimiter_type: semantic_type_or_delimiter.is_a?(String) ? semantic_type_or_delimiter : nil,
49
+ id: block.id,
50
+ title: ToCoreModel.extract_title_text(block.title),
51
+ content: content_lines,
52
+ language: ToCoreModel.extract_block_language(block)
53
+ )
54
+ end
55
+
56
+ def transform_typed_block(block, klass, extra_attrs = {})
57
+ lines = Array(block.lines).reject do |line|
58
+ line.is_a?(Coradoc::AsciiDoc::Model::LineBreak) ||
59
+ line.is_a?(Coradoc::AsciiDoc::Model::Break::PageBreak)
60
+ end
61
+
62
+ has_nested_blocks = lines.any?(Coradoc::AsciiDoc::Model::Block::Core)
63
+
64
+ if has_nested_blocks
65
+ children = lines.map { |line| ToCoreModel.transform(line) }
66
+ klass.new(
67
+ id: block.id,
68
+ title: ToCoreModel.extract_title_text(block.title),
69
+ children: children,
70
+ language: ToCoreModel.extract_block_language(block),
71
+ **extra_attrs
72
+ )
73
+ else
74
+ content_lines = lines.map { |line| ToCoreModel.extract_text_content(line) }.join("\n")
75
+ klass.new(
76
+ id: block.id,
77
+ title: ToCoreModel.extract_title_text(block.title),
78
+ content: content_lines,
79
+ language: ToCoreModel.extract_block_language(block),
80
+ **extra_attrs
81
+ )
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Transform
6
+ module ElementTransformers
7
+ class DocumentTransformer
8
+ class << self
9
+ def transform_document(doc)
10
+ title_text = ToCoreModel.extract_title_text(doc.header&.title)
11
+ attributes = ToCoreModel.extract_document_attributes(doc)
12
+ Coradoc::CoreModel::DocumentElement.new(
13
+ id: doc.id,
14
+ title: title_text,
15
+ attributes: attributes,
16
+ children: ToCoreModel.transform(doc.sections || doc.contents || [])
17
+ )
18
+ end
19
+
20
+ def transform_section(section, parent_id: nil)
21
+ title_text = ToCoreModel.extract_title_text(section.title)
22
+ section_id = section.id || Coradoc::CoreModel::IdGenerator.generate_from_title(
23
+ title_text, parent_id: parent_id
24
+ )
25
+
26
+ content_children = ToCoreModel.transform(section.contents || [])
27
+ nested_sections = (section.sections || []).map do |child|
28
+ transform_section(child, parent_id: section_id)
29
+ end
30
+
31
+ Coradoc::CoreModel::SectionElement.new(
32
+ id: section_id,
33
+ level: section.level,
34
+ title: title_text,
35
+ children: content_children + nested_sections
36
+ )
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Transform
6
+ module ElementTransformers
7
+ class InlineTransformer
8
+ class << self
9
+ def transform_inline(inline, format_type)
10
+ klass = Coradoc::CoreModel::InlineElement.format_type_class(format_type)
11
+ klass.new(
12
+ content: ToCoreModel.extract_text_content(inline.content)
13
+ )
14
+ end
15
+
16
+ def transform_inline_text(inline, format_type)
17
+ klass = Coradoc::CoreModel::InlineElement.format_type_class(format_type)
18
+ klass.new(
19
+ content: inline.text.to_s
20
+ )
21
+ end
22
+
23
+ def transform_inline_footnote(footnote)
24
+ parsed_content = ToCoreModel.parse_and_transform_inline(footnote.text.to_s)
25
+ Coradoc::CoreModel::FootnoteElement.new(
26
+ target: footnote.id,
27
+ content: parsed_content
28
+ )
29
+ end
30
+
31
+ def transform_link(link)
32
+ Coradoc::CoreModel::LinkElement.new(
33
+ target: link.path,
34
+ content: link.name || link.path
35
+ )
36
+ end
37
+
38
+ def transform_cross_reference(xref)
39
+ Coradoc::CoreModel::CrossReferenceElement.new(
40
+ target: xref.href,
41
+ content: xref.args&.first || xref.href
42
+ )
43
+ end
44
+
45
+ def transform_stem(stem)
46
+ Coradoc::CoreModel::StemElement.new(
47
+ content: stem.content,
48
+ stem_type: stem.type || 'stem'
49
+ )
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Transform
6
+ module ElementTransformers
7
+ class ListTransformer
8
+ class << self
9
+ def transform_list(list, marker_type)
10
+ items = Array(list.items).map do |item|
11
+ if item.is_a?(Coradoc::AsciiDoc::Model::List::DefinitionItem)
12
+ transform_definition_item(item)
13
+ else
14
+ transform_list_item(item)
15
+ end
16
+ end
17
+
18
+ if marker_type == 'definition'
19
+ Coradoc::CoreModel::DefinitionList.new(items: items)
20
+ else
21
+ Coradoc::CoreModel::ListBlock.new(
22
+ marker_type: marker_type,
23
+ items: items
24
+ )
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def transform_definition_item(item)
31
+ term_content = item.terms
32
+ def_content = item.contents
33
+
34
+ term_parts = term_content.is_a?(Array) ? term_content : [term_content]
35
+ parsed_terms = term_parts.flat_map do |part|
36
+ ToCoreModel.parse_inline_text(part)
37
+ end
38
+
39
+ parsed_defs = ToCoreModel.parse_inline_text(def_content)
40
+
41
+ term_children = ToCoreModel.transform_inline_content(parsed_terms)
42
+ def_children = ToCoreModel.transform_inline_content(parsed_defs)
43
+
44
+ di = Coradoc::CoreModel::DefinitionItem.new(
45
+ term: ToCoreModel.extract_text_content(term_children),
46
+ definitions: [ToCoreModel.extract_text_content(def_children)],
47
+ term_children: term_children,
48
+ definition_children: def_children
49
+ )
50
+ di.id = item.id if item.id
51
+ di
52
+ end
53
+
54
+ def transform_list_item(item)
55
+ content_val = item.content
56
+ children = ToCoreModel.transform_inline_content(content_val)
57
+
58
+ li = Coradoc::CoreModel::ListItem.new(
59
+ content: ToCoreModel.extract_text_content(content_val),
60
+ marker: item.marker
61
+ )
62
+ li.children = children
63
+
64
+ if item.nested.is_a?(Coradoc::AsciiDoc::Model::List::Core)
65
+ nested_core = transform_list(item.nested, list_marker_type(item.nested))
66
+ li.children << nested_core
67
+ elsif item.nested.is_a?(Array)
68
+ item.nested.each do |n|
69
+ next unless n.is_a?(Coradoc::AsciiDoc::Model::List::Core)
70
+
71
+ li.children << transform_list(n, list_marker_type(n))
72
+ end
73
+ end
74
+
75
+ li
76
+ end
77
+
78
+ def list_marker_type(list)
79
+ case list
80
+ when Coradoc::AsciiDoc::Model::List::Ordered then 'ordered'
81
+ when Coradoc::AsciiDoc::Model::List::Definition then 'definition'
82
+ else 'unordered'
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Transform
6
+ module ElementTransformers
7
+ class OtherTransformer
8
+ class << self
9
+ def transform_term(term)
10
+ Coradoc::CoreModel::Term.new(
11
+ text: term.term.to_s,
12
+ type: term.type&.to_s || 'preferred',
13
+ lang: term.lang&.to_s || 'en'
14
+ )
15
+ end
16
+
17
+ def transform_admonition(admonition)
18
+ children = ToCoreModel.transform_inline_content(admonition.content)
19
+ block = Coradoc::CoreModel::AnnotationBlock.new(
20
+ annotation_type: admonition.type,
21
+ content: ToCoreModel.extract_text_content(admonition.content)
22
+ )
23
+ block.children = children
24
+ block
25
+ end
26
+
27
+ def transform_image(image)
28
+ Coradoc::CoreModel::Image.new(
29
+ src: image.src,
30
+ alt: image.title&.to_s,
31
+ width: image.attributes&.[]('width'),
32
+ height: image.attributes&.[]('height')
33
+ )
34
+ end
35
+
36
+ def transform_bibliography(bib)
37
+ entries = Array(bib.entries).map do |entry|
38
+ transform_bibliography_entry(entry)
39
+ end
40
+
41
+ Coradoc::CoreModel::Bibliography.new(
42
+ id: bib.id,
43
+ title: bib.title.to_s,
44
+ level: nil,
45
+ entries: entries
46
+ )
47
+ end
48
+
49
+ def transform_bibliography_entry(entry)
50
+ Coradoc::CoreModel::BibliographyEntry.new(
51
+ anchor_name: entry.anchor_name,
52
+ document_id: entry.document_id,
53
+ ref_text: entry.ref_text.to_s
54
+ )
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Transform
6
+ module ElementTransformers
7
+ class TableTransformer
8
+ class << self
9
+ def transform_table(table)
10
+ rows = Array(table.rows).map do |row|
11
+ transform_table_row(row)
12
+ end
13
+
14
+ Coradoc::CoreModel::Table.new(
15
+ id: table.id,
16
+ title: table.title&.to_s,
17
+ rows: rows
18
+ )
19
+ end
20
+
21
+ def transform_table_row(row)
22
+ cells = Array(row.columns).map do |cell|
23
+ transform_table_cell(cell)
24
+ end
25
+ Coradoc::CoreModel::TableRow.new(
26
+ cells: cells,
27
+ header: row.header
28
+ )
29
+ end
30
+
31
+ def transform_table_cell(cell)
32
+ children = ToCoreModel.transform_inline_content(cell.content)
33
+
34
+ Coradoc::CoreModel::TableCell.new(
35
+ content: ToCoreModel.extract_text_content(cell.content),
36
+ alignment: cell.horizontal_alignment,
37
+ vertical_alignment: cell.vertical_alignment,
38
+ colspan: cell.colspan,
39
+ rowspan: cell.rowspan,
40
+ style: cell.style_name,
41
+ children: children
42
+ )
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Transform
6
+ module ElementTransformers
7
+ autoload :DocumentTransformer, "#{__dir__}/element_transformers/document_transformer"
8
+ autoload :BlockTransformer, "#{__dir__}/element_transformers/block_transformer"
9
+ autoload :ListTransformer, "#{__dir__}/element_transformers/list_transformer"
10
+ autoload :InlineTransformer, "#{__dir__}/element_transformers/inline_transformer"
11
+ autoload :TableTransformer, "#{__dir__}/element_transformers/table_transformer"
12
+ autoload :OtherTransformer, "#{__dir__}/element_transformers/other_transformer"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -7,9 +7,7 @@ module Coradoc
7
7
  module Transform
8
8
  # Transforms CoreModel to AsciiDoc models
9
9
  class FromCoreModel
10
- def transform(model)
11
- self.class.transform(model)
12
- end
10
+ include Coradoc::Transform::Base
13
11
 
14
12
  class << self
15
13
  def transform(model)
@@ -17,52 +15,7 @@ module Coradoc
17
15
  return model unless model.is_a?(Coradoc::CoreModel::Base)
18
16
 
19
17
  transformer = Registry.lookup(model.class)
20
- return transformer.call(model) if transformer
21
-
22
- transform_with_case(model)
23
- end
24
-
25
- def transform_with_case(model)
26
- case model
27
- when Coradoc::CoreModel::StructuralElement
28
- transform_structural_element(model)
29
- when Coradoc::CoreModel::AnnotationBlock
30
- transform_annotation(model)
31
- when Coradoc::CoreModel::Block
32
- transform_block(model)
33
- when Coradoc::CoreModel::Table
34
- transform_table(model)
35
- when Coradoc::CoreModel::ListBlock
36
- transform_list(model)
37
- when Coradoc::CoreModel::ListItem
38
- transform_list_item(model)
39
- when Coradoc::CoreModel::Term
40
- transform_term(model)
41
- when Coradoc::CoreModel::InlineElement
42
- transform_inline(model)
43
- when Coradoc::CoreModel::Image
44
- transform_image(model)
45
- when Coradoc::CoreModel::Footnote
46
- transform_footnote(model)
47
- when Coradoc::CoreModel::FootnoteReference
48
- transform_footnote_reference(model)
49
- when Coradoc::CoreModel::Abbreviation
50
- transform_abbreviation(model)
51
- when Coradoc::CoreModel::DefinitionList
52
- transform_definition_list(model)
53
- when Coradoc::CoreModel::DefinitionItem
54
- transform_definition_item(model)
55
- when Coradoc::CoreModel::Toc
56
- transform_toc(model)
57
- when Coradoc::CoreModel::TocEntry
58
- transform_toc_entry(model)
59
- when Coradoc::CoreModel::Bibliography
60
- transform_bibliography(model)
61
- when Coradoc::CoreModel::BibliographyEntry
62
- transform_bibliography_entry(model)
63
- else
64
- model
65
- end
18
+ transformer ? transformer.call(model) : model
66
19
  end
67
20
 
68
21
  def transform_structural_element(element)
@@ -173,7 +126,8 @@ module Coradoc
173
126
  Coradoc::AsciiDoc::Model::Block::Quote.new(
174
127
  id: block.id,
175
128
  title: block.title,
176
- lines: content_text.split("\n")
129
+ lines: content_text.split("\n"),
130
+ delimiter: '[verse]'
177
131
  )
178
132
  when :reviewer
179
133
  Coradoc::AsciiDoc::Model::Block::ReviewerComment.new(
@@ -183,7 +137,7 @@ module Coradoc
183
137
  )
184
138
  else
185
139
  delim = block.delimiter_type.to_s
186
- delim_char = delim.chars.first
140
+ delim_char = delim[0]
187
141
  delim_len = delim.length
188
142
 
189
143
  Coradoc::AsciiDoc::Model::Block::Core.new(
@@ -376,35 +330,10 @@ module Coradoc
376
330
 
377
331
  private
378
332
 
379
- # Reverse mapping: semantic type → AsciiDoc delimiter generation
380
- SEMANTIC_TO_ADOC_BLOCK = {
381
- source_code: :source_code,
382
- quote: :quote,
383
- example: :example,
384
- sidebar: :sidebar,
385
- literal: :literal,
386
- pass: :pass,
387
- open: :open,
388
- verse: :open,
389
- paragraph: :paragraph,
390
- comment: :comment
391
- }.freeze
392
-
393
- # Map raw delimiter_type string → semantic type (backward compat)
394
- DELIMITER_CHAR_TO_SEMANTIC = {
395
- '-' => :source_code,
396
- '=' => :example,
397
- '_' => :quote,
398
- '*' => :sidebar,
399
- '.' => :literal,
400
- '+' => :pass
401
- }.freeze
402
-
403
333
  def resolve_semantic_type(block)
404
334
  semantic = block.resolve_semantic_type
405
335
  return semantic if semantic
406
336
 
407
- # Format-specific fallback from delimiter_type
408
337
  delim = block.delimiter_type
409
338
  return nil unless delim && !delim.empty?
410
339
 
@@ -415,7 +344,7 @@ module Coradoc
415
344
  when "'''", '---', '___', '***' then :horizontal_rule
416
345
  else
417
346
  char = delim[0]
418
- DELIMITER_CHAR_TO_SEMANTIC[char] || nil
347
+ DelimiterMapping::CHAR_TO_SEMANTIC[char] || nil
419
348
  end
420
349
  end
421
350
 
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Transform
6
+ # Visits AsciiDoc inline content and produces CoreModel inline elements.
7
+ #
8
+ # Replaces the 50-line transform_inline_content case/when in ToCoreModel.
9
+ # Handles whitespace insertion between adjacent TextElements.
10
+ class InlineTransformVisitor
11
+ def initialize(to_core_model)
12
+ @to_core_model = to_core_model
13
+ end
14
+
15
+ def transform(content)
16
+ visit_content(content)
17
+ end
18
+
19
+ private
20
+
21
+ def visit_content(content)
22
+ case content
23
+ when nil then []
24
+ when Array then visit_array(content)
25
+ when Model::TextElement then visit_content(content.content)
26
+ when Model::Term
27
+ [CoreModel::TermElement.new(content: content.term.to_s)]
28
+ when String
29
+ content.empty? ? [] : [CoreModel::TextContent.new(text: content)]
30
+ when Model::Base
31
+ [visit_model(content)]
32
+ else
33
+ text = TextExtractVisitor.new.extract(content)
34
+ text.empty? ? [] : [CoreModel::TextContent.new(text: text)]
35
+ end
36
+ end
37
+
38
+ def visit_array(items)
39
+ result = []
40
+ items.each_with_index do |item, idx|
41
+ transformed = visit_content(item)
42
+ next if transformed.empty?
43
+
44
+ needs_space = idx.positive? &&
45
+ item.is_a?(Model::TextElement) &&
46
+ item.line_break != '+'
47
+ result << CoreModel::TextContent.new(text: ' ') if needs_space
48
+ result.concat(transformed)
49
+ end
50
+ result
51
+ end
52
+
53
+ def visit_model(model)
54
+ @to_core_model.transform(model)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end