coradoc-adoc 2.0.7 → 2.0.9

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.
Files changed (24) hide show
  1. checksums.yaml +4 -4
  2. data/lib/coradoc/asciidoc/delimiter_mapping.rb +16 -0
  3. data/lib/coradoc/asciidoc/model/list/definition_item.rb +6 -0
  4. data/lib/coradoc/asciidoc/parser/list.rb +18 -13
  5. data/lib/coradoc/asciidoc/serializer/serializers/list/definition_item.rb +21 -1
  6. data/lib/coradoc/asciidoc/transform/element_transformers/block_transformer.rb +89 -0
  7. data/lib/coradoc/asciidoc/transform/element_transformers/document_transformer.rb +43 -0
  8. data/lib/coradoc/asciidoc/transform/element_transformers/inline_transformer.rb +56 -0
  9. data/lib/coradoc/asciidoc/transform/element_transformers/list_transformer.rb +96 -0
  10. data/lib/coradoc/asciidoc/transform/element_transformers/other_transformer.rb +61 -0
  11. data/lib/coradoc/asciidoc/transform/element_transformers/table_transformer.rb +49 -0
  12. data/lib/coradoc/asciidoc/transform/element_transformers.rb +16 -0
  13. data/lib/coradoc/asciidoc/transform/from_core_model.rb +19 -83
  14. data/lib/coradoc/asciidoc/transform/inline_transform_visitor.rb +59 -0
  15. data/lib/coradoc/asciidoc/transform/text_extract_visitor.rb +126 -0
  16. data/lib/coradoc/asciidoc/transform/to_core_model.rb +42 -569
  17. data/lib/coradoc/asciidoc/transform/to_core_model_registrations.rb +31 -70
  18. data/lib/coradoc/asciidoc/transform/transformer_registry.rb +80 -0
  19. data/lib/coradoc/asciidoc/transform.rb +5 -1
  20. data/lib/coradoc/asciidoc/transformer/list_rules.rb +54 -11
  21. data/lib/coradoc/asciidoc/version.rb +1 -1
  22. data/lib/coradoc/asciidoc.rb +1 -0
  23. metadata +12 -2
  24. data/lib/coradoc/asciidoc/transform/registry.rb +0 -146
@@ -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(
@@ -344,22 +298,29 @@ module Coradoc
344
298
  )
345
299
  end
346
300
 
347
- def transform_definition_list(definition_list)
301
+ def transform_definition_list(definition_list, depth = 1)
302
+ delimiter = ':' * (depth + 1)
348
303
  items = Array(definition_list.items).map do |item|
349
- transform_definition_item(item)
304
+ transform_definition_item(item, depth)
350
305
  end
351
- Coradoc::AsciiDoc::Model::List::Definition.new(items: items)
306
+ list = Coradoc::AsciiDoc::Model::List::Definition.new(items: items)
307
+ list.delimiter = delimiter
308
+ list
352
309
  end
353
310
 
354
- def transform_definition_item(item)
311
+ def transform_definition_item(item, depth = 1)
312
+ delimiter = ':' * (depth + 1)
355
313
  term = Coradoc::AsciiDoc::Model::Term.new(term: item.term.to_s)
356
314
  contents = Array(item.definitions).map do |defn|
357
315
  Coradoc::AsciiDoc::Model::TextElement.new(content: defn.to_s)
358
316
  end
359
- Coradoc::AsciiDoc::Model::List::DefinitionItem.new(
317
+ di = Coradoc::AsciiDoc::Model::List::DefinitionItem.new(
360
318
  terms: [term],
361
- contents: contents
319
+ contents: contents,
320
+ delimiter: delimiter
362
321
  )
322
+ di.nested << transform_definition_list(item.nested, depth + 1) if item.nested&.items&.any?
323
+ di
363
324
  end
364
325
 
365
326
  def transform_toc(_toc)
@@ -376,35 +337,10 @@ module Coradoc
376
337
 
377
338
  private
378
339
 
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
340
  def resolve_semantic_type(block)
404
341
  semantic = block.resolve_semantic_type
405
342
  return semantic if semantic
406
343
 
407
- # Format-specific fallback from delimiter_type
408
344
  delim = block.delimiter_type
409
345
  return nil unless delim && !delim.empty?
410
346
 
@@ -415,7 +351,7 @@ module Coradoc
415
351
  when "'''", '---', '___', '***' then :horizontal_rule
416
352
  else
417
353
  char = delim[0]
418
- DELIMITER_CHAR_TO_SEMANTIC[char] || nil
354
+ DelimiterMapping::CHAR_TO_SEMANTIC[char] || nil
419
355
  end
420
356
  end
421
357
 
@@ -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
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ module Transform
6
+ # Visits AsciiDoc inline model nodes and extracts plain text.
7
+ #
8
+ # Replaces the 70-line extract_text_content case/when in ToCoreModel.
9
+ # Each visit_ method handles one model type — locality per element.
10
+ class TextExtractVisitor
11
+ def extract(model)
12
+ visit(model)
13
+ end
14
+
15
+ private
16
+
17
+ # Scalars
18
+ def visit_nil(_)
19
+ ''
20
+ end
21
+
22
+ def visit_string(model)
23
+ model
24
+ end
25
+
26
+ def visit_parslet_slice(model)
27
+ model.to_s
28
+ end
29
+
30
+ # Text carriers
31
+ def visit_text_element(model)
32
+ content = model.content
33
+ content.is_a?(Array) ? visit_array(content) : visit(content)
34
+ end
35
+
36
+ # Inline formatting — recurse into content
37
+ def visit_inline(model)
38
+ visit(model.content)
39
+ end
40
+
41
+ def visit_term(model)
42
+ model.term.to_s
43
+ end
44
+
45
+ def visit_link(model)
46
+ model.name || model.path || ''
47
+ end
48
+
49
+ def visit_cross_reference(model)
50
+ model.href || ''
51
+ end
52
+
53
+ def visit_stem(model)
54
+ model.content.to_s
55
+ end
56
+
57
+ def visit_footnote(model)
58
+ model.text ? visit(model.text) : ''
59
+ end
60
+
61
+ def visit_attribute_reference(model)
62
+ "{#{model.name}}"
63
+ end
64
+
65
+ def visit_core_model_text_content(model)
66
+ model.text.to_s
67
+ end
68
+
69
+ def visit_core_model_image(model)
70
+ model.alt || model.src || ''
71
+ end
72
+
73
+ def visit_adoc_image(model)
74
+ model.alt || model.src || ''
75
+ end
76
+
77
+ def visit_base_model(model)
78
+ model.content ? visit(model.content) : ''
79
+ end
80
+
81
+ def visit_core_model_inline(model)
82
+ model.content.to_s
83
+ end
84
+
85
+ # Collections
86
+ def visit_array(models)
87
+ result = []
88
+ models.each_with_index do |item, idx|
89
+ text = visit(item)
90
+ next if text.empty?
91
+
92
+ result << text
93
+ next unless idx < models.length - 1 && !text.empty?
94
+
95
+ result << ' ' if item.is_a?(Model::TextElement) && item.line_break != '+'
96
+ end
97
+ result.join
98
+ end
99
+
100
+ # Dispatch
101
+ def visit(model)
102
+ case model
103
+ when nil then visit_nil(model)
104
+ when String then visit_string(model)
105
+ when Parslet::Slice then visit_parslet_slice(model)
106
+ when CoreModel::TextContent then visit_core_model_text_content(model)
107
+ when CoreModel::Image then visit_core_model_image(model)
108
+ when CoreModel::InlineElement then visit_core_model_inline(model)
109
+ when Array then visit_array(model)
110
+ when Model::TextElement then visit_text_element(model)
111
+ when Model::Term then visit_term(model)
112
+ when Model::Inline::Link then visit_link(model)
113
+ when Model::Inline::CrossReference then visit_cross_reference(model)
114
+ when Model::Inline::Stem then visit_stem(model)
115
+ when Model::Inline::Footnote then visit_footnote(model)
116
+ when Model::Inline::AttributeReference then visit_attribute_reference(model)
117
+ when Model::Image::Core then visit_adoc_image(model)
118
+ when Model::Base then visit_base_model(model)
119
+ else
120
+ model.class.name.start_with?('Parslet::') ? model.to_s : ''
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end