coradoc 2.0.4 → 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 +4 -4
- data/.rubocop_todo.yml +96 -51
- data/coradoc-adoc/lib/coradoc/asciidoc/model/break.rb +7 -0
- data/coradoc-adoc/lib/coradoc/asciidoc/model/document.rb +2 -2
- data/coradoc-adoc/lib/coradoc/asciidoc/model/include.rb +2 -2
- data/coradoc-adoc/lib/coradoc/asciidoc/model.rb +6 -4
- data/coradoc-adoc/lib/coradoc/asciidoc/parser/base.rb +1 -0
- data/coradoc-adoc/lib/coradoc/asciidoc/parser/block.rb +8 -7
- data/coradoc-adoc/lib/coradoc/asciidoc/parser/content.rb +13 -3
- data/coradoc-adoc/lib/coradoc/asciidoc/parser/inline.rb +15 -15
- data/coradoc-adoc/lib/coradoc/asciidoc/parser/list.rb +2 -2
- data/coradoc-adoc/lib/coradoc/asciidoc/parser/section.rb +1 -0
- data/coradoc-adoc/lib/coradoc/asciidoc/serializer/serializers/document.rb +4 -1
- data/coradoc-adoc/lib/coradoc/asciidoc/transform/from_core_model.rb +84 -13
- data/coradoc-adoc/lib/coradoc/asciidoc/transform/to_core_model.rb +106 -27
- data/coradoc-adoc/lib/coradoc/asciidoc/transform/to_core_model_registrations.rb +50 -19
- data/coradoc-adoc/lib/coradoc/asciidoc/transformer/misc_rules.rb +5 -0
- data/coradoc-adoc/lib/coradoc/asciidoc/transformer/structural_rules.rb +9 -8
- data/coradoc-adoc/lib/coradoc/asciidoc/transformer.rb +22 -5
- data/coradoc-adoc/lib/coradoc/asciidoc.rb +7 -2
- data/coradoc-adoc/spec/coradoc/asciidoc/integration_pipeline_spec.rb +342 -0
- data/coradoc-adoc/spec/coradoc/asciidoc/list_continuation_spec.rb +1 -1
- data/coradoc-adoc/spec/coradoc/asciidoc/round_trip_spec.rb +0 -2
- data/coradoc-adoc/spec/coradoc/asciidoc/transform/from_core_model_spec.rb +3 -2
- data/coradoc-adoc/spec/coradoc/developer_experience_spec.rb +0 -2
- data/coradoc-adoc/spec/transform/from_core_model_spec.rb +3 -3
- data/coradoc-adoc/spec/transform/to_core_model_spec.rb +1 -0
- data/coradoc-html/lib/coradoc/html/converters/base.rb +41 -17
- data/coradoc-html/lib/coradoc/html/converters/example.rb +1 -2
- data/coradoc-html/lib/coradoc/html/converters/listing.rb +1 -2
- data/coradoc-html/lib/coradoc/html/converters/literal.rb +1 -2
- data/coradoc-html/lib/coradoc/html/converters/open.rb +1 -2
- data/coradoc-html/lib/coradoc/html/converters/quote.rb +2 -3
- data/coradoc-html/lib/coradoc/html/converters/sidebar.rb +1 -2
- data/coradoc-html/lib/coradoc/html/converters/source.rb +1 -2
- data/coradoc-html/lib/coradoc/html/converters/source_code.rb +1 -2
- data/coradoc-html/lib/coradoc/html/converters/term.rb +1 -2
- data/coradoc-html/lib/coradoc/html/converters/verse.rb +2 -3
- data/coradoc-html/lib/coradoc/html/input/converters/aside.rb +1 -1
- data/coradoc-html/lib/coradoc/html/input/converters/audio.rb +1 -1
- data/coradoc-html/lib/coradoc/html/input/converters/blockquote.rb +2 -3
- data/coradoc-html/lib/coradoc/html/input/converters/div.rb +1 -2
- data/coradoc-html/lib/coradoc/html/input/converters/figure.rb +2 -3
- data/coradoc-html/lib/coradoc/html/input/converters/hr.rb +1 -1
- data/coradoc-html/lib/coradoc/html/input/converters/p.rb +2 -1
- data/coradoc-html/lib/coradoc/html/input/converters/pre.rb +14 -10
- data/coradoc-html/lib/coradoc/html/input/converters/video.rb +1 -1
- data/coradoc-html/lib/coradoc/html/renderer.rb +50 -2
- data/coradoc-html/lib/coradoc/html/spa.rb +2 -2
- data/coradoc-html/lib/coradoc/html/static.rb +2 -2
- data/coradoc-html/lib/coradoc/html/templates/core_model/definition_list.liquid +11 -0
- data/coradoc-html/lib/coradoc/html/theme/modern/javascript_generator.rb +2 -2
- data/coradoc-html/lib/coradoc/html/theme/modern/serializers/document_serializer.rb +7 -11
- data/coradoc-html/lib/coradoc/html/theme/modern_renderer.rb +6 -7
- data/coradoc-html/lib/coradoc/html.rb +5 -15
- data/coradoc-html/spec/input/converters/converters_spec.rb +6 -8
- data/coradoc-markdown/lib/coradoc/markdown/model/attribute_list.rb +0 -3
- data/coradoc-markdown/lib/coradoc/markdown/model/definition_list.rb +0 -3
- data/coradoc-markdown/lib/coradoc/markdown/model/extension.rb +0 -2
- data/coradoc-markdown/lib/coradoc/markdown/model/highlight.rb +0 -1
- data/coradoc-markdown/lib/coradoc/markdown/model/math.rb +0 -1
- data/coradoc-markdown/lib/coradoc/markdown/model/strikethrough.rb +0 -1
- data/coradoc-markdown/lib/coradoc/markdown/parser/ast_processor.rb +2 -2
- data/coradoc-markdown/lib/coradoc/markdown/parser/block_parser.rb +2 -2
- data/coradoc-markdown/lib/coradoc/markdown/parser/inline_parser.rb +3 -3
- data/coradoc-markdown/lib/coradoc/markdown/parser.rb +9 -3
- data/coradoc-markdown/lib/coradoc/markdown/toc_generator.rb +6 -4
- data/coradoc-markdown/lib/coradoc/markdown/transform/from_core_model.rb +27 -6
- data/coradoc-markdown/lib/coradoc/markdown/transform/to_core_model.rb +5 -9
- data/coradoc-markdown/lib/coradoc/markdown/transformer.rb +2 -1
- data/coradoc-markdown/spec/transform/to_core_model_spec.rb +6 -8
- data/exe/coradoc +1 -0
- data/lib/coradoc/coradoc.rb +6 -7
- data/lib/coradoc/core_model/annotation_block.rb +0 -2
- data/lib/coradoc/core_model/block.rb +92 -32
- data/lib/coradoc/core_model/builder/block_builder.rb +20 -2
- data/lib/coradoc/core_model/builder/detection.rb +0 -8
- data/lib/coradoc/core_model/builder.rb +6 -7
- data/lib/coradoc/core_model/example_block.rb +12 -0
- data/lib/coradoc/core_model/listing_block.rb +15 -0
- data/lib/coradoc/core_model/literal_block.rb +12 -0
- data/lib/coradoc/core_model/open_block.rb +12 -0
- data/lib/coradoc/core_model/pass_block.rb +12 -0
- data/lib/coradoc/core_model/quote_block.rb +14 -0
- data/lib/coradoc/core_model/reviewer_block.rb +12 -0
- data/lib/coradoc/core_model/sidebar_block.rb +12 -0
- data/lib/coradoc/core_model/source_block.rb +22 -0
- data/lib/coradoc/core_model/structural_element.rb +4 -0
- data/lib/coradoc/core_model/verse_block.rb +14 -0
- data/lib/coradoc/core_model.rb +10 -0
- data/lib/coradoc/document_manipulator.rb +3 -1
- data/lib/coradoc/processor_registry.rb +0 -2
- data/lib/coradoc/version.rb +1 -1
- metadata +13 -34
- data/coradoc-markdown/coverage/.last_run.json +0 -5
- data/coradoc-markdown/coverage/.resultset.json +0 -6322
- data/coradoc-markdown/coverage/.resultset.json.lock +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/DataTables-1.10.20/images/sort_asc.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/DataTables-1.10.20/images/sort_asc_disabled.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/DataTables-1.10.20/images/sort_both.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/DataTables-1.10.20/images/sort_desc.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/DataTables-1.10.20/images/sort_desc_disabled.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/application.css +0 -1
- data/coradoc-markdown/coverage/assets/0.13.2/application.js +0 -7
- data/coradoc-markdown/coverage/assets/0.13.2/colorbox/border.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/colorbox/controls.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/colorbox/loading.gif +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/colorbox/loading_background.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/favicon_green.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/favicon_red.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/favicon_yellow.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/images/ui-icons_222222_256x240.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/images/ui-icons_2e83ff_256x240.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/images/ui-icons_454545_256x240.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/images/ui-icons_888888_256x240.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/loading.gif +0 -0
- data/coradoc-markdown/coverage/assets/0.13.2/magnify.png +0 -0
- data/coradoc-markdown/coverage/index.html +0 -66032
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
RSpec.describe 'Integration pipeline fixes' do
|
|
6
|
+
def parse_to_core(adoc)
|
|
7
|
+
ast = Coradoc::AsciiDoc::Parser::Base.parse(adoc)
|
|
8
|
+
model = Coradoc::AsciiDoc::Transformer.transform(ast)
|
|
9
|
+
Coradoc::AsciiDoc::Transform::ToCoreModel.transform(model)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def parse_to_ast(adoc)
|
|
13
|
+
Coradoc::AsciiDoc::Parser::Base.parse(adoc)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe 'Fix 01: Page break parsing' do
|
|
17
|
+
it 'parses <<< as page_break at document level' do
|
|
18
|
+
ast = parse_to_ast("= Title\n\n<<<\n")
|
|
19
|
+
doc_nodes = ast[:document]
|
|
20
|
+
page_breaks = doc_nodes.select { |n| n.is_a?(Hash) && n.key?(:page_break) }
|
|
21
|
+
expect(page_breaks.length).to eq(1)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'parses <<< as page_break inside sections' do
|
|
25
|
+
ast = parse_to_ast("== Section\n\n<<<\n\nSome text\n")
|
|
26
|
+
doc_nodes = ast[:document]
|
|
27
|
+
section = doc_nodes.find { |n| n.is_a?(Hash) && n.key?(:section) }
|
|
28
|
+
contents = section[:section][:contents]
|
|
29
|
+
page_breaks = contents.select { |n| n.is_a?(Hash) && n.key?(:page_break) }
|
|
30
|
+
expect(page_breaks.length).to eq(1)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'does not capture <<< as paragraph text' do
|
|
34
|
+
ast = parse_to_ast("= Title\n\n<<<\n")
|
|
35
|
+
doc_nodes = ast[:document]
|
|
36
|
+
paragraphs = doc_nodes.select { |n| n.is_a?(Hash) && n.key?(:paragraph) }
|
|
37
|
+
paragraph_texts = paragraphs.map { |p| p[:paragraph][:lines].map { |l| l[:text].to_s }.join }
|
|
38
|
+
expect(paragraph_texts).not_to include('<<<')
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'transforms page_break through to CoreModel as nil (filtered out)' do
|
|
42
|
+
core = parse_to_core("= Title\n\nHello\n\n<<<\n\n== Section\n")
|
|
43
|
+
expect(core).to be_a(Coradoc::CoreModel::StructuralElement)
|
|
44
|
+
expect(core.children.length).to eq(2) # paragraph + section, no page break
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe 'Fix 02+03: Table row grouping and header detection' do
|
|
49
|
+
it 'groups cells into rows by column count' do
|
|
50
|
+
adoc = <<~ADOC
|
|
51
|
+
= Doc
|
|
52
|
+
|
|
53
|
+
[cols="2"]
|
|
54
|
+
|===
|
|
55
|
+
| A | B
|
|
56
|
+
| C | D
|
|
57
|
+
| E | F
|
|
58
|
+
|===
|
|
59
|
+
ADOC
|
|
60
|
+
|
|
61
|
+
core = parse_to_core(adoc)
|
|
62
|
+
table = find_first_table(core)
|
|
63
|
+
expect(table).not_to be_nil
|
|
64
|
+
expect(table.rows.length).to eq(3)
|
|
65
|
+
table.rows.each do |row|
|
|
66
|
+
expect(row.cells.length).to eq(2)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it 'marks the first row as header' do
|
|
71
|
+
adoc = <<~ADOC
|
|
72
|
+
= Doc
|
|
73
|
+
|
|
74
|
+
[cols="2"]
|
|
75
|
+
|===
|
|
76
|
+
| Header A | Header B
|
|
77
|
+
| Data 1 | Data 2
|
|
78
|
+
|===
|
|
79
|
+
ADOC
|
|
80
|
+
|
|
81
|
+
core = parse_to_core(adoc)
|
|
82
|
+
table = find_first_table(core)
|
|
83
|
+
expect(table.rows.first.header).to be true
|
|
84
|
+
expect(table.rows.last.header).to be false
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'handles 3-column tables' do
|
|
88
|
+
adoc = <<~ADOC
|
|
89
|
+
= Doc
|
|
90
|
+
|
|
91
|
+
[cols="3"]
|
|
92
|
+
|===
|
|
93
|
+
| A | B | C
|
|
94
|
+
| D | E | F
|
|
95
|
+
|===
|
|
96
|
+
ADOC
|
|
97
|
+
|
|
98
|
+
core = parse_to_core(adoc)
|
|
99
|
+
table = find_first_table(core)
|
|
100
|
+
expect(table.rows.length).to eq(2)
|
|
101
|
+
table.rows.each { |row| expect(row.cells.length).to eq(3) }
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
describe 'Fix 04: LineBreak leak' do
|
|
106
|
+
it 'does not leak LineBreak elements into CoreModel children' do
|
|
107
|
+
adoc = <<~ADOC
|
|
108
|
+
= Title
|
|
109
|
+
|
|
110
|
+
First paragraph.
|
|
111
|
+
|
|
112
|
+
Second paragraph.
|
|
113
|
+
ADOC
|
|
114
|
+
|
|
115
|
+
core = parse_to_core(adoc)
|
|
116
|
+
core.children.each do |child|
|
|
117
|
+
next if child.is_a?(String) && child.strip.empty?
|
|
118
|
+
|
|
119
|
+
expect(child).not_to be_a(Coradoc::AsciiDoc::Model::LineBreak)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it 'does not leak PageBreak elements into CoreModel children' do
|
|
124
|
+
core = parse_to_core("= Title\n\n<<<\n\n== Section\n")
|
|
125
|
+
core.children.each do |child|
|
|
126
|
+
expect(child).not_to be_a(Coradoc::AsciiDoc::Model::Break::PageBreak)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
describe 'Fix 05: Document attributes' do
|
|
132
|
+
it 'preserves document attributes in CoreModel' do
|
|
133
|
+
skip 'Parser does not yet propagate document attributes to CoreModel'
|
|
134
|
+
adoc = <<~ADOC
|
|
135
|
+
= My Document
|
|
136
|
+
:author: John
|
|
137
|
+
:revdate: 2024-01-01
|
|
138
|
+
|
|
139
|
+
Content here.
|
|
140
|
+
ADOC
|
|
141
|
+
|
|
142
|
+
core = parse_to_core(adoc)
|
|
143
|
+
expect(core.attributes).to include('author' => 'John', 'revdate' => '2024-01-01')
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it 'handles multiple attributes' do
|
|
147
|
+
skip 'Parser does not yet propagate document attributes to CoreModel'
|
|
148
|
+
adoc = <<~ADOC
|
|
149
|
+
= Doc
|
|
150
|
+
:docnumber: 1
|
|
151
|
+
:edition: 2
|
|
152
|
+
:language: zh-Hant
|
|
153
|
+
|
|
154
|
+
Text.
|
|
155
|
+
ADOC
|
|
156
|
+
|
|
157
|
+
core = parse_to_core(adoc)
|
|
158
|
+
expect(core.attributes).to include(
|
|
159
|
+
'docnumber' => '1',
|
|
160
|
+
'edition' => '2',
|
|
161
|
+
'language' => 'zh-Hant'
|
|
162
|
+
)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
describe 'Fix 07: Cross-references' do
|
|
167
|
+
it 'parses simple cross-reference <<id>>' do
|
|
168
|
+
skip 'Cross-reference parsing not yet implemented'
|
|
169
|
+
adoc = <<~ADOC
|
|
170
|
+
= Doc
|
|
171
|
+
|
|
172
|
+
See <<introduction>> for details.
|
|
173
|
+
ADOC
|
|
174
|
+
|
|
175
|
+
core = parse_to_core(adoc)
|
|
176
|
+
xrefs = find_all_xrefs(core)
|
|
177
|
+
expect(xrefs.length).to be >= 1
|
|
178
|
+
expect(xrefs.first.target).to eq('introduction')
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
it 'parses cross-reference with text <<id,text>>' do
|
|
182
|
+
skip 'Cross-reference parsing not yet implemented'
|
|
183
|
+
adoc = <<~ADOC
|
|
184
|
+
= Doc
|
|
185
|
+
|
|
186
|
+
See <<introduction,Introduction>> for details.
|
|
187
|
+
ADOC
|
|
188
|
+
|
|
189
|
+
core = parse_to_core(adoc)
|
|
190
|
+
xrefs = find_all_xrefs(core)
|
|
191
|
+
expect(xrefs.length).to be >= 1
|
|
192
|
+
expect(xrefs.first.target).to eq('introduction')
|
|
193
|
+
expect(xrefs.first.content).to eq('Introduction')
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
it 'parses multiple cross-references' do
|
|
197
|
+
skip 'Cross-reference parsing not yet implemented'
|
|
198
|
+
adoc = <<~ADOC
|
|
199
|
+
= Doc
|
|
200
|
+
|
|
201
|
+
See <<section-a>> and <<section-b,Section B>>.
|
|
202
|
+
ADOC
|
|
203
|
+
|
|
204
|
+
core = parse_to_core(adoc)
|
|
205
|
+
xrefs = find_all_xrefs(core)
|
|
206
|
+
expect(xrefs.length).to be >= 2
|
|
207
|
+
targets = xrefs.map(&:target)
|
|
208
|
+
expect(targets).to include('section-a', 'section-b')
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
describe 'Fix 06: Section hierarchy — bold in list items' do
|
|
213
|
+
it 'parses ordered list items starting with bold formatting' do
|
|
214
|
+
ast = parse_to_ast(". *First* text\n")
|
|
215
|
+
doc_nodes = ast[:document]
|
|
216
|
+
lists = doc_nodes.select { |n| n.is_a?(Hash) && n.key?(:list) }
|
|
217
|
+
expect(lists.length).to eq(1)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
it 'parses ordered list items starting with bold inside a section' do
|
|
221
|
+
adoc = <<~ADOC
|
|
222
|
+
== Section
|
|
223
|
+
|
|
224
|
+
. *Bold item* — description
|
|
225
|
+
. Normal item
|
|
226
|
+
ADOC
|
|
227
|
+
|
|
228
|
+
ast = parse_to_ast(adoc)
|
|
229
|
+
section = ast[:document].find { |n| n.is_a?(Hash) && n.key?(:section) }
|
|
230
|
+
contents = section[:section][:contents]
|
|
231
|
+
lists = contents.select { |n| n.is_a?(Hash) && n.key?(:list) }
|
|
232
|
+
expect(lists.length).to eq(1)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
it 'parses source blocks with YAML delimiters inside' do
|
|
236
|
+
adoc = <<~ADOC
|
|
237
|
+
= Doc
|
|
238
|
+
|
|
239
|
+
[source]
|
|
240
|
+
----
|
|
241
|
+
---
|
|
242
|
+
frontmatter
|
|
243
|
+
---
|
|
244
|
+
----
|
|
245
|
+
ADOC
|
|
246
|
+
|
|
247
|
+
core = parse_to_core(adoc)
|
|
248
|
+
expect(core).to be_a(Coradoc::CoreModel::StructuralElement)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
it 'does not let highlight unconstrained match across lines' do
|
|
252
|
+
ast = parse_to_ast("## heading\nSome text\n")
|
|
253
|
+
doc_nodes = ast[:document]
|
|
254
|
+
paragraphs = doc_nodes.select { |n| n.is_a?(Hash) && n.key?(:paragraph) }
|
|
255
|
+
highlight_nodes = paragraphs.select do |p|
|
|
256
|
+
text = p[:paragraph]
|
|
257
|
+
text.to_s.include?('highlight')
|
|
258
|
+
end
|
|
259
|
+
expect(highlight_nodes).to be_empty
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
describe 'Fix 08: List marker_type' do
|
|
264
|
+
it 'sets marker_type to unordered for bullet lists' do
|
|
265
|
+
adoc = <<~ADOC
|
|
266
|
+
= Doc
|
|
267
|
+
|
|
268
|
+
* Item one
|
|
269
|
+
* Item two
|
|
270
|
+
* Item three
|
|
271
|
+
ADOC
|
|
272
|
+
|
|
273
|
+
core = parse_to_core(adoc)
|
|
274
|
+
lists = find_all_lists(core)
|
|
275
|
+
expect(lists).not_to be_empty
|
|
276
|
+
expect(lists.first.marker_type).to eq('unordered')
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
it 'sets marker_type to ordered for numbered lists' do
|
|
280
|
+
adoc = <<~ADOC
|
|
281
|
+
= Doc
|
|
282
|
+
|
|
283
|
+
. First item
|
|
284
|
+
. Second item
|
|
285
|
+
. Third item
|
|
286
|
+
ADOC
|
|
287
|
+
|
|
288
|
+
core = parse_to_core(adoc)
|
|
289
|
+
lists = find_all_lists(core)
|
|
290
|
+
expect(lists).not_to be_empty
|
|
291
|
+
expect(lists.first.marker_type).to eq('ordered')
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
private
|
|
296
|
+
|
|
297
|
+
def find_first_table(el)
|
|
298
|
+
return el if el.is_a?(Coradoc::CoreModel::Table)
|
|
299
|
+
return nil unless el.is_a?(Coradoc::CoreModel::Base)
|
|
300
|
+
|
|
301
|
+
if el.class.attributes.key?(:children) && el.children
|
|
302
|
+
el.children.each do |child|
|
|
303
|
+
result = find_first_table(child)
|
|
304
|
+
return result if result
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
nil
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def find_all_xrefs(el)
|
|
312
|
+
xrefs = []
|
|
313
|
+
return xrefs unless el
|
|
314
|
+
|
|
315
|
+
xrefs << el if el.is_a?(Coradoc::CoreModel::InlineElement) && el.format_type == 'xref'
|
|
316
|
+
|
|
317
|
+
children = if el.respond_to?(:children) && el.children
|
|
318
|
+
el.children
|
|
319
|
+
elsif el.is_a?(Coradoc::CoreModel::Base) && el.class.attributes.key?(:children)
|
|
320
|
+
el.children
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
children&.each { |c| xrefs.concat(find_all_xrefs(c)) }
|
|
324
|
+
|
|
325
|
+
xrefs
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
def find_all_lists(el)
|
|
329
|
+
lists = []
|
|
330
|
+
return lists unless el
|
|
331
|
+
|
|
332
|
+
lists << el if el.is_a?(Coradoc::CoreModel::ListBlock)
|
|
333
|
+
|
|
334
|
+
if el.is_a?(Coradoc::CoreModel::ListBlock) && el.items
|
|
335
|
+
el.items.each { |c| lists.concat(find_all_lists(c)) }
|
|
336
|
+
elsif el.is_a?(Coradoc::CoreModel::Base) && el.class.attributes.key?(:children) && el.children
|
|
337
|
+
el.children.each { |c| lists.concat(find_all_lists(c)) }
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
lists
|
|
341
|
+
end
|
|
342
|
+
end
|
|
@@ -21,7 +21,7 @@ RSpec.describe 'AsciiDoc List Continuation' do
|
|
|
21
21
|
expect(result).to be_a(Coradoc::AsciiDoc::Model::Document)
|
|
22
22
|
|
|
23
23
|
# Navigate to the list
|
|
24
|
-
contents = result.
|
|
24
|
+
contents = result.is_a?(Coradoc::AsciiDoc::Model::Document) ? result.sections : result.contents
|
|
25
25
|
list = contents.first
|
|
26
26
|
expect(list).to be_a(Coradoc::AsciiDoc::Model::List::Unordered)
|
|
27
27
|
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require 'spec_helper'
|
|
4
4
|
|
|
5
|
-
# rubocop:disable RSpec/DescribeClass
|
|
6
5
|
RSpec.describe 'Round-Trip Conversion' do
|
|
7
6
|
# Helper to parse, transform to CoreModel, transform back, and serialize
|
|
8
7
|
def round_trip(adoc_text)
|
|
@@ -258,4 +257,3 @@ RSpec.describe 'Round-Trip Conversion' do
|
|
|
258
257
|
end
|
|
259
258
|
end
|
|
260
259
|
end
|
|
261
|
-
# rubocop:enable RSpec/DescribeClass
|
|
@@ -32,15 +32,16 @@ RSpec.describe Coradoc::AsciiDoc::Transform::FromCoreModel do
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
context 'with Block' do
|
|
35
|
-
it 'transforms a CoreModel Block to AsciiDoc Block' do
|
|
35
|
+
it 'transforms a CoreModel Block to AsciiDoc Example Block' do
|
|
36
36
|
core_block = Coradoc::CoreModel::Block.new(
|
|
37
|
+
block_semantic_type: :example,
|
|
37
38
|
delimiter_type: '====',
|
|
38
39
|
content: 'Example content'
|
|
39
40
|
)
|
|
40
41
|
|
|
41
42
|
result = described_class.transform(core_block)
|
|
42
43
|
|
|
43
|
-
expect(result).to be_a(Coradoc::AsciiDoc::Model::Block::
|
|
44
|
+
expect(result).to be_a(Coradoc::AsciiDoc::Model::Block::Example)
|
|
44
45
|
end
|
|
45
46
|
end
|
|
46
47
|
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require 'spec_helper'
|
|
4
4
|
|
|
5
|
-
# rubocop:disable RSpec/DescribeClass - This is a feature spec for the API facade
|
|
6
5
|
RSpec.describe 'Developer Experience API' do
|
|
7
6
|
# Load coradoc core and asciidoc
|
|
8
7
|
|
|
@@ -121,4 +120,3 @@ RSpec.describe 'Developer Experience API' do
|
|
|
121
120
|
end
|
|
122
121
|
end
|
|
123
122
|
end
|
|
124
|
-
# rubocop:enable RSpec/DescribeClass
|
|
@@ -41,18 +41,18 @@ RSpec.describe Coradoc::AsciiDoc::Transform::FromCoreModel do
|
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
context 'when transforming a block' do
|
|
44
|
-
it 'transforms a CoreModel block to AsciiDoc' do
|
|
44
|
+
it 'transforms a CoreModel example block to AsciiDoc' do
|
|
45
45
|
block = Coradoc::CoreModel::Block.new(
|
|
46
46
|
id: 'example-1',
|
|
47
|
+
block_semantic_type: :example,
|
|
47
48
|
delimiter_type: '====',
|
|
48
49
|
content: "Line 1\nLine 2"
|
|
49
50
|
)
|
|
50
51
|
|
|
51
52
|
result = transformer.transform(block)
|
|
52
53
|
|
|
53
|
-
expect(result).to be_a(Coradoc::AsciiDoc::Model::Block::
|
|
54
|
+
expect(result).to be_a(Coradoc::AsciiDoc::Model::Block::Example)
|
|
54
55
|
expect(result.id).to eq('example-1')
|
|
55
|
-
expect(result.delimiter).to eq('====')
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
|
|
@@ -54,6 +54,7 @@ RSpec.describe Coradoc::AsciiDoc::Transform::ToCoreModel do
|
|
|
54
54
|
result = transformer.transform(block)
|
|
55
55
|
|
|
56
56
|
expect(result).to be_a(Coradoc::CoreModel::Block)
|
|
57
|
+
expect(result.block_semantic_type).to eq('example')
|
|
57
58
|
expect(result.delimiter_type).to eq('====')
|
|
58
59
|
expect(result.content).to eq("Line 1\nLine 2")
|
|
59
60
|
end
|
|
@@ -169,40 +169,64 @@ module Coradoc
|
|
|
169
169
|
# Get renderable content (children if present, otherwise content)
|
|
170
170
|
renderable = block.renderable_content
|
|
171
171
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
semantic = resolve_block_semantic_type(block)
|
|
173
|
+
|
|
174
|
+
case semantic
|
|
175
|
+
when :paragraph
|
|
175
176
|
content = convert_content_to_html(renderable, state)
|
|
176
177
|
return "<p#{attrs}>#{content}</p>" if content && !content.empty?
|
|
177
178
|
|
|
178
179
|
''
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
# Then check delimiter_type for special blocks
|
|
182
|
-
case block.delimiter_type
|
|
183
|
-
when '----', 'source'
|
|
180
|
+
when :source_code
|
|
184
181
|
lang = block.language || block.metadata&.dig(:language)
|
|
185
182
|
lang_attr = lang ? " data-lang=\"#{escape_attribute(lang)}\"" : ''
|
|
186
183
|
"<pre#{attrs}><code#{lang_attr}>#{escape_html(block.flat_text)}</code></pre>"
|
|
187
|
-
when
|
|
184
|
+
when :quote, :verse
|
|
188
185
|
"<blockquote#{attrs}>#{convert_content_to_html(renderable, state)}</blockquote>"
|
|
189
|
-
when
|
|
186
|
+
when :example
|
|
190
187
|
"<div class=\"example\"#{attrs}>#{convert_content_to_html(renderable, state)}</div>"
|
|
191
|
-
when
|
|
188
|
+
when :sidebar
|
|
192
189
|
"<aside class=\"sidebar\"#{attrs}>#{convert_content_to_html(renderable, state)}</aside>"
|
|
193
|
-
when
|
|
190
|
+
when :literal
|
|
194
191
|
"<pre class=\"literal\"#{attrs}>#{escape_html(block.flat_text)}</pre>"
|
|
195
|
-
when
|
|
196
|
-
block.flat_text
|
|
197
|
-
when
|
|
198
|
-
|
|
199
|
-
when
|
|
192
|
+
when :pass
|
|
193
|
+
block.flat_text
|
|
194
|
+
when :listing
|
|
195
|
+
"<pre#{attrs}>#{escape_html(block.flat_text)}</pre>"
|
|
196
|
+
when :open
|
|
197
|
+
"<div#{attrs}>#{convert_content_to_html(renderable, state)}</div>"
|
|
198
|
+
when :verse
|
|
199
|
+
"<blockquote#{attrs}>#{convert_content_to_html(renderable, state)}</blockquote>"
|
|
200
|
+
when :comment, :reviewer
|
|
201
|
+
''
|
|
202
|
+
when :horizontal_rule
|
|
200
203
|
"<hr#{attrs}>"
|
|
201
204
|
else
|
|
202
205
|
"<div#{attrs}>#{convert_content_to_html(renderable, state)}</div>"
|
|
203
206
|
end
|
|
204
207
|
end
|
|
205
208
|
|
|
209
|
+
# Resolve the semantic type from a block via polymorphic dispatch.
|
|
210
|
+
# Block#resolve_semantic_type handles class-level semantic_type →
|
|
211
|
+
# block_semantic_type attribute → element_type → delimiter fallback.
|
|
212
|
+
def resolve_block_semantic_type(block)
|
|
213
|
+
block.resolve_semantic_type ||
|
|
214
|
+
resolve_format_specific_semantic(block)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Format-specific semantic mappings not covered by the core model
|
|
218
|
+
def resolve_format_specific_semantic(block)
|
|
219
|
+
delim = block.delimiter_type
|
|
220
|
+
return nil unless delim && !delim.empty?
|
|
221
|
+
|
|
222
|
+
case delim
|
|
223
|
+
when "'''", '---', '___', '***' then :horizontal_rule
|
|
224
|
+
when '[verse]' then :verse
|
|
225
|
+
when 'comment' then :comment
|
|
226
|
+
when 'paragraph' then :paragraph
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
206
230
|
# Render CoreModel structural element
|
|
207
231
|
def render_core_structural_element(element, state = {})
|
|
208
232
|
attrs = build_html_attributes(element.id, nil)
|
|
@@ -43,11 +43,10 @@ module Coradoc
|
|
|
43
43
|
# Extract ID if present
|
|
44
44
|
id = element['id']
|
|
45
45
|
|
|
46
|
-
Coradoc::CoreModel::
|
|
47
|
-
delimiter_type: '____',
|
|
46
|
+
Coradoc::CoreModel::QuoteBlock.new(
|
|
48
47
|
content: content,
|
|
49
48
|
id: id,
|
|
50
|
-
|
|
49
|
+
attribution: attribution
|
|
51
50
|
)
|
|
52
51
|
end
|
|
53
52
|
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Html
|
|
7
5
|
module Converters
|
|
6
|
+
autoload :Base, "#{__dir__}/base"
|
|
8
7
|
# Converter for SourceCode blocks
|
|
9
8
|
#
|
|
10
9
|
# SourceCode models use the `lines` attribute, while Source models use `content`.
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'base'
|
|
4
|
-
|
|
5
3
|
module Coradoc
|
|
6
4
|
module Html
|
|
7
5
|
module Converters
|
|
6
|
+
autoload :Base, "#{__dir__}/base"
|
|
8
7
|
# Converter for CoreModel::InlineElement (term) elements
|
|
9
8
|
#
|
|
10
9
|
# Terms are used in definition lists and can have types like "acronym",
|
|
@@ -50,12 +50,11 @@ module Coradoc
|
|
|
50
50
|
# Extract ID if present
|
|
51
51
|
id = element['id']
|
|
52
52
|
|
|
53
|
-
Coradoc::CoreModel::
|
|
54
|
-
delimiter_type: '[verse]',
|
|
53
|
+
Coradoc::CoreModel::VerseBlock.new(
|
|
55
54
|
content: content,
|
|
56
55
|
title: title,
|
|
57
56
|
id: id,
|
|
58
|
-
|
|
57
|
+
attribution: attribution
|
|
59
58
|
)
|
|
60
59
|
end
|
|
61
60
|
|
|
@@ -10,11 +10,10 @@ module Coradoc
|
|
|
10
10
|
cite = node['cite']
|
|
11
11
|
content = treat_children_coradoc(node, state)
|
|
12
12
|
|
|
13
|
-
Coradoc::CoreModel::
|
|
14
|
-
delimiter_type: '____',
|
|
13
|
+
Coradoc::CoreModel::QuoteBlock.new(
|
|
15
14
|
content: content,
|
|
16
15
|
id: id,
|
|
17
|
-
|
|
16
|
+
attribution: cite
|
|
18
17
|
)
|
|
19
18
|
end
|
|
20
19
|
end
|