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.
- checksums.yaml +4 -4
- data/lib/coradoc/asciidoc/delimiter_mapping.rb +16 -0
- data/lib/coradoc/asciidoc/model/list/definition_item.rb +6 -0
- data/lib/coradoc/asciidoc/parser/list.rb +18 -13
- data/lib/coradoc/asciidoc/serializer/serializers/list/definition_item.rb +21 -1
- data/lib/coradoc/asciidoc/transform/element_transformers/block_transformer.rb +89 -0
- data/lib/coradoc/asciidoc/transform/element_transformers/document_transformer.rb +43 -0
- data/lib/coradoc/asciidoc/transform/element_transformers/inline_transformer.rb +56 -0
- data/lib/coradoc/asciidoc/transform/element_transformers/list_transformer.rb +96 -0
- data/lib/coradoc/asciidoc/transform/element_transformers/other_transformer.rb +61 -0
- data/lib/coradoc/asciidoc/transform/element_transformers/table_transformer.rb +49 -0
- data/lib/coradoc/asciidoc/transform/element_transformers.rb +16 -0
- data/lib/coradoc/asciidoc/transform/from_core_model.rb +19 -83
- data/lib/coradoc/asciidoc/transform/inline_transform_visitor.rb +59 -0
- data/lib/coradoc/asciidoc/transform/text_extract_visitor.rb +126 -0
- data/lib/coradoc/asciidoc/transform/to_core_model.rb +42 -569
- data/lib/coradoc/asciidoc/transform/to_core_model_registrations.rb +31 -70
- data/lib/coradoc/asciidoc/transform/transformer_registry.rb +80 -0
- data/lib/coradoc/asciidoc/transform.rb +5 -1
- data/lib/coradoc/asciidoc/transformer/list_rules.rb +54 -11
- data/lib/coradoc/asciidoc/version.rb +1 -1
- data/lib/coradoc/asciidoc.rb +1 -0
- metadata +12 -2
- 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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|