coradoc-adoc 2.0.0 → 2.0.6

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: c26d9ebfcf6853d33150a149234dbb84d35fa07afe3cba77894fa6bcc96dc0cd
4
- data.tar.gz: d9208da701b03723fedcbe52bc40dad2c7c880fbc48d2817e309a7fdfd439d35
3
+ metadata.gz: bfa6580ceec41f023bc49501abcd731a8ce2bbe25fb381a083b6595a4ccd7c1e
4
+ data.tar.gz: 0fa0c15adc1ed488f4fc0913cc8342551896025065cf543ef2307de95947fa1a
5
5
  SHA512:
6
- metadata.gz: 0c10a653ea35637819bd299247cfa100793dc16ec9a02e4c9d96e4e54dbf8f6d38fd053feab58e8849a5b06d4cf24c2b9a97fd29048e584e76ca1a732cbb0628
7
- data.tar.gz: 76fb17f26249012cc48d581cb4dce02ffee066260d41cd010b7bcf8f2c7bfa46ac4ef83330d5d14d568099b059abf2cb910d19b397d4b12401833bb4867a0282
6
+ metadata.gz: e9276729c16a8084735f487d8faaadc9d64ac81781214c41ff8808bd771eeddfc5d22e726b1fc09add738b3771fcf1902249879fbc91f203d6918f2a42b5509e
7
+ data.tar.gz: 07735c28d0a67001c6791420c22558e4a711a08857fe20fe33eade7c3d6f5284a67c6bbc3d3473614e401324dd150abe76aa618150837b0df81967134535ec94
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ class Builder
6
+ module BlockBuilder
7
+ def build_annotation_block(ast)
8
+ Coradoc::CoreModel::AnnotationBlock.new(
9
+ annotation_type: extract_annotation_type(ast),
10
+ annotation_label: extract_annotation_label(ast),
11
+ content: extract_block_content(ast),
12
+ lines: extract_block_lines(ast),
13
+ title: ast[:title],
14
+ id: ast[:id],
15
+ attributes: build_attributes_private(ast[:attribute_list])
16
+ )
17
+ end
18
+
19
+ def build_generic_block(ast)
20
+ Coradoc::CoreModel::Block.new(
21
+ delimiter_type: ast[:delimiter]&.to_s,
22
+ content: extract_block_content(ast),
23
+ lines: extract_block_lines(ast),
24
+ title: ast[:title],
25
+ id: ast[:id],
26
+ attributes: build_attributes_private(ast[:attribute_list])
27
+ )
28
+ end
29
+
30
+ def extract_block_content(ast)
31
+ return ast[:content] if ast[:content]
32
+
33
+ if ast[:lines]
34
+ lines = Array(ast[:lines])
35
+ return lines.map { |line| extract_text_content(line) }.join("\n")
36
+ end
37
+
38
+ ''
39
+ end
40
+
41
+ def extract_block_lines(ast)
42
+ return [] unless ast[:lines]
43
+
44
+ Array(ast[:lines]).map { |line| extract_text_content(line) }
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ class Builder
6
+ module Detection
7
+ def detect_element_type(ast)
8
+ return :header if ast.key?(:header) || has_header_structure?(ast)
9
+ return :section if ast.key?(:section) || has_section_structure?(ast)
10
+ return :block if ast.key?(:block) || has_block_structure?(ast)
11
+ return :list if ast.key?(:list) || ast.key?(:unordered) ||
12
+ ast.key?(:ordered) || ast.key?(:definition_list)
13
+ return :paragraph if ast.key?(:paragraph)
14
+ return :text if ast.key?(:text)
15
+ return :attribute if ast.key?(:key) && ast.key?(:value)
16
+ return :document_attributes if ast.key?(:document_attributes)
17
+ return :inline if has_inline_structure?(ast)
18
+ return :line_break if ast.key?(:line_break) && ast.keys.length == 1
19
+ return :comment_line if ast.key?(:comment_line)
20
+ return :comment_block if ast.key?(:comment_block)
21
+ return :include if ast.key?(:include)
22
+ return :table if ast.key?(:table)
23
+ return :unparsed if ast.key?(:unparsed)
24
+ return :tag if ast.key?(:tag)
25
+ return :bibliography_entry if ast.key?(:bibliography_entry)
26
+
27
+ nil
28
+ end
29
+
30
+ def detect_block_type(ast)
31
+ return :annotation if extract_annotation_type(ast)
32
+ return :list if ast[:marker] && list_markers.include?(ast[:marker].to_s)
33
+
34
+ :generic
35
+ end
36
+
37
+ def has_header_structure?(ast)
38
+ ast.key?(:title) && (ast.key?(:author) || ast.key?(:revision))
39
+ end
40
+
41
+ def has_section_structure?(ast)
42
+ ast.key?(:title) && ast.key?(:level)
43
+ end
44
+
45
+ def has_block_structure?(ast)
46
+ ast.key?(:delimiter) || ast.key?(:lines)
47
+ end
48
+
49
+ def has_inline_structure?(ast)
50
+ inline_format_types.any? { |type| ast.key?(type) }
51
+ end
52
+
53
+ def detect_inline_format(ast)
54
+ ast.each_key do |key|
55
+ key_str = key.to_s
56
+ return key_str if key_str.end_with?('_constrained', '_unconstrained')
57
+ end
58
+
59
+ inline_format_types.each do |format|
60
+ return format.to_s if ast.key?(format)
61
+ end
62
+
63
+ 'text'
64
+ end
65
+
66
+ def detect_constrained(ast, format_type)
67
+ if format_type.end_with?('_constrained')
68
+ return true
69
+ elsif format_type.end_with?('_unconstrained')
70
+ return false
71
+ end
72
+
73
+ key = "#{format_type}_constrained".to_sym
74
+ return true if ast.key?(key)
75
+
76
+ unconstrained_key = "#{format_type}_unconstrained".to_sym
77
+ return false if ast.key?(unconstrained_key)
78
+
79
+ true
80
+ end
81
+
82
+ def extract_level(ast)
83
+ if ast[:level]
84
+ level_str = ast[:level].to_s
85
+ return level_str.length - 1 if level_str.start_with?('=')
86
+ return level_str.to_i if level_str.match?(/^\d+$/)
87
+ end
88
+
89
+ 1
90
+ end
91
+
92
+ def extract_annotation_type(ast)
93
+ attr_list = ast[:attribute_list]
94
+ if attr_list.is_a?(Hash) && attr_list[:positional]
95
+ positional = Array(attr_list[:positional])
96
+ annotation = positional.find do |p|
97
+ annotation_types.include?(p.to_s.downcase)
98
+ end
99
+ return annotation.to_s.downcase if annotation
100
+ end
101
+
102
+ return ast[:admonition_type]&.to_s&.downcase if ast[:admonition_type]
103
+
104
+ nil
105
+ end
106
+
107
+ def extract_annotation_label(ast)
108
+ attr_list = ast[:attribute_list]
109
+ return nil unless attr_list.is_a?(Hash)
110
+
111
+ if attr_list[:named]
112
+ named = Array(attr_list[:named])
113
+ reviewer_attr = named.find do |n|
114
+ n.is_a?(Hash) && n[:key] == 'reviewer'
115
+ end
116
+ return reviewer_attr[:value] if reviewer_attr
117
+ end
118
+
119
+ nil
120
+ end
121
+
122
+ def detect_marker_type(ast)
123
+ marker = ast[:marker]&.to_s
124
+ return 'unordered' if marker&.start_with?('*')
125
+ return 'unordered' if marker&.start_with?('-')
126
+ return 'ordered' if marker&.match?(/^\d+\./) || marker&.start_with?('.')
127
+ return 'definition' if marker&.end_with?('::')
128
+
129
+ 'unordered'
130
+ end
131
+
132
+ def detect_marker_level(ast)
133
+ marker = ast[:marker]&.to_s
134
+ return marker.length if marker&.match?(/^[*.]+$/)
135
+
136
+ 1
137
+ end
138
+
139
+ def extract_text_content(content)
140
+ case content
141
+ when String
142
+ content
143
+ when Array
144
+ content.map { |c| extract_text_content(c) }.join
145
+ when Hash
146
+ if content[:text]
147
+ extract_text_content(content[:text])
148
+ elsif content[:paragraph_text]
149
+ extract_text_content(content[:paragraph_text])
150
+ else
151
+ content.values.map { |v| extract_text_content(v) }.join
152
+ end
153
+ else
154
+ content.to_s
155
+ end
156
+ end
157
+
158
+ def extract_inline_content(ast, format_type)
159
+ content_key = format_type.to_sym
160
+ content = ast[content_key] ||
161
+ ast["#{format_type}_constrained".to_sym] ||
162
+ ast["#{format_type}_unconstrained".to_sym]
163
+
164
+ extract_text_content(content)
165
+ end
166
+
167
+ def annotation_types
168
+ %w[note warning caution important tip reviewer sidebar]
169
+ end
170
+
171
+ def list_markers
172
+ %w[* - . ::]
173
+ end
174
+
175
+ def inline_format_types
176
+ %i[bold italic monospace superscript subscript highlight span link
177
+ cross_reference bold_constrained bold_unconstrained
178
+ italic_constrained italic_unconstrained monospace_constrained
179
+ monospace_unconstrained]
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ class Builder
6
+ module ElementBuilder
7
+ def build_header(ast)
8
+ header_ast = ast[:header] || ast
9
+
10
+ Coradoc::CoreModel::HeaderElement.new(
11
+ title: extract_text_content(header_ast[:title]),
12
+ id: header_ast[:id]
13
+ )
14
+ end
15
+
16
+ def build_section(ast)
17
+ section_ast = ast[:section] || ast
18
+
19
+ Coradoc::CoreModel::SectionElement.new(
20
+ title: extract_text_content(section_ast[:title]),
21
+ id: section_ast[:id],
22
+ level: extract_level(section_ast),
23
+ children: build_section_contents(section_ast[:contents]) +
24
+ build_subsections(section_ast[:sections])
25
+ )
26
+ end
27
+
28
+ def build_section_contents(contents_ast)
29
+ return [] unless contents_ast
30
+
31
+ Array(contents_ast).map { |content| build_element(content) }.compact
32
+ end
33
+
34
+ def build_subsections(sections_ast)
35
+ return [] unless sections_ast
36
+
37
+ Array(sections_ast).map { |section| build_element(section) }.compact
38
+ end
39
+
40
+ def build_line_break(ast)
41
+ Coradoc::CoreModel::Block.new(
42
+ block_semantic_type: 'line_break',
43
+ content: ast[:line_break] || ast['line_break']
44
+ )
45
+ end
46
+
47
+ def build_comment_line(ast)
48
+ comment_ast = ast[:comment_line] || ast['comment_line'] || ast
49
+
50
+ Coradoc::CoreModel::CommentBlock.new(
51
+ content: comment_ast[:comment_text] || comment_ast['comment_text']
52
+ )
53
+ end
54
+
55
+ def build_comment_block(ast)
56
+ comment_ast = ast[:comment_block] || ast['comment_block'] || ast
57
+
58
+ Coradoc::CoreModel::CommentBlock.new(
59
+ content: comment_ast[:comment_text] || comment_ast['comment_text']
60
+ )
61
+ end
62
+
63
+ def build_include(ast)
64
+ include_ast = ast[:include] || ast['include'] || ast
65
+
66
+ Coradoc::CoreModel::Block.new(
67
+ block_semantic_type: 'include',
68
+ content: include_ast[:path] || include_ast['path']
69
+ )
70
+ end
71
+
72
+ def build_table(ast)
73
+ table_ast = ast[:table] || ast['table'] || ast
74
+
75
+ Coradoc::CoreModel::Table.new(
76
+ title: table_ast[:title] || table_ast['title'],
77
+ id: table_ast[:id] || table_ast['id'],
78
+ rows: table_ast[:rows] || table_ast['rows'] || []
79
+ )
80
+ end
81
+
82
+ def build_unparsed(ast)
83
+ Coradoc::CoreModel::Block.new(
84
+ block_semantic_type: 'unparsed',
85
+ content: (ast[:unparsed] || ast['unparsed']).to_s
86
+ )
87
+ end
88
+
89
+ def build_tag(ast)
90
+ tag_ast = ast[:tag] || ast['tag'] || ast
91
+
92
+ Coradoc::CoreModel::Block.new(
93
+ block_semantic_type: 'tag',
94
+ content: tag_ast[:name] || tag_ast['name']
95
+ )
96
+ end
97
+
98
+ def build_bibliography_entry(ast)
99
+ bib_ast = ast[:bibliography_entry] || ast['bibliography_entry'] || ast
100
+
101
+ Coradoc::CoreModel::BibliographyEntry.new(
102
+ anchor_name: bib_ast[:anchor_name] || bib_ast['anchor_name'],
103
+ document_id: bib_ast[:document_id] || bib_ast['document_id'],
104
+ ref_text: bib_ast[:ref_text] || bib_ast['ref_text']
105
+ )
106
+ end
107
+
108
+ def build_generic_element(ast)
109
+ Coradoc::CoreModel::Block.new(
110
+ block_semantic_type: 'unknown',
111
+ content: ast.to_s
112
+ )
113
+ end
114
+
115
+ def build_attribute(ast)
116
+ Coradoc::CoreModel::ElementAttribute.new(
117
+ name: ast[:key],
118
+ value: ast[:value]
119
+ )
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ class Builder
6
+ module ListBuilder
7
+ def build_list_block(ast)
8
+ Coradoc::CoreModel::ListBlock.new(
9
+ marker_type: detect_marker_type(ast),
10
+ marker_level: detect_marker_level(ast),
11
+ items: build_list_items(ast[:items] || ast[:list_items]),
12
+ title: ast[:title],
13
+ id: ast[:id],
14
+ attributes: build_attributes_private(ast[:attribute_list])
15
+ )
16
+ end
17
+
18
+ def build_unordered_list(ast)
19
+ items = Array(ast[:unordered]).map { |item| build_list_item(item) }
20
+
21
+ Coradoc::CoreModel::ListBlock.new(
22
+ marker_type: 'unordered',
23
+ marker_level: 1,
24
+ items: items,
25
+ attributes: build_attributes_private(ast[:attribute_list])
26
+ )
27
+ end
28
+
29
+ def build_ordered_list(ast)
30
+ items = Array(ast[:ordered]).map { |item| build_list_item(item) }
31
+
32
+ Coradoc::CoreModel::ListBlock.new(
33
+ marker_type: 'ordered',
34
+ marker_level: 1,
35
+ items: items,
36
+ attributes: build_attributes_private(ast[:attribute_list])
37
+ )
38
+ end
39
+
40
+ def build_definition_list(ast)
41
+ items = Array(ast[:definition_list]).map do |item|
42
+ build_definition_item(item)
43
+ end
44
+
45
+ Coradoc::CoreModel::ListBlock.new(
46
+ marker_type: 'definition',
47
+ marker_level: 1,
48
+ items: items,
49
+ attributes: build_attributes_private(ast[:attribute_list])
50
+ )
51
+ end
52
+
53
+ def build_list_items(items_ast)
54
+ return [] unless items_ast
55
+
56
+ Array(items_ast).map { |item| build_list_item(item) }
57
+ end
58
+
59
+ def build_list_item(ast)
60
+ item_ast = ast[:list_item] || ast
61
+
62
+ Coradoc::CoreModel::ListItem.new(
63
+ marker: item_ast[:marker]&.to_s,
64
+ content: extract_item_content(item_ast),
65
+ nested_list: build_nested_list(item_ast[:nested]),
66
+ children: build_item_children(item_ast[:attached])
67
+ )
68
+ end
69
+
70
+ def build_definition_item(ast)
71
+ item_ast = ast[:definition_list_item] || ast
72
+
73
+ Coradoc::CoreModel::ListItem.new(
74
+ marker: '::',
75
+ content: build_definition_content(item_ast),
76
+ children: []
77
+ )
78
+ end
79
+
80
+ def build_definition_content(ast)
81
+ terms = Array(ast[:terms]).join(', ')
82
+ definition = ast[:definition] || ast[:contents]
83
+
84
+ "#{terms}: #{definition}"
85
+ end
86
+
87
+ def build_nested_list(nested_ast)
88
+ return nil unless nested_ast
89
+
90
+ if nested_ast.is_a?(Array)
91
+ Coradoc::CoreModel::ListBlock.new(
92
+ marker_type: 'unordered',
93
+ marker_level: 2,
94
+ items: nested_ast.map { |item| build_list_item(item) }
95
+ )
96
+ else
97
+ build_element(nested_ast)
98
+ end
99
+ end
100
+
101
+ def build_item_children(attached_ast)
102
+ return [] unless attached_ast
103
+
104
+ Array(attached_ast).map { |child| build_element(child) }.compact
105
+ end
106
+
107
+ def extract_item_content(ast)
108
+ if ast[:text]
109
+ case ast[:text]
110
+ when String
111
+ ast[:text]
112
+ when Array
113
+ ast[:text].map(&:to_s).join
114
+ else
115
+ ast[:text].to_s
116
+ end
117
+ elsif ast[:content]
118
+ ast[:content].to_s
119
+ else
120
+ ''
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module AsciiDoc
5
+ class Builder
6
+ module TextBuilder
7
+ def build_nested_inlines(ast)
8
+ nested = []
9
+
10
+ ast.each_value do |value|
11
+ next unless value.is_a?(Array)
12
+
13
+ value.each do |item|
14
+ nested << build_inline(item) if item.is_a?(Hash) && has_inline_structure?(item)
15
+ end
16
+ end
17
+
18
+ nested
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end