reverse_adoc 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/macos.yml +27 -0
- data/.github/workflows/ubuntu.yml +27 -0
- data/.github/workflows/windows.yml +30 -0
- data/.hound.yml +3 -0
- data/.rubocop.yml +10 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +25 -0
- data/README.adoc +290 -0
- data/Rakefile +14 -0
- data/bin/reverse_adoc +67 -0
- data/bin/w2a +85 -0
- data/lib/reverse_asciidoctor.rb +70 -0
- data/lib/reverse_asciidoctor/cleaner.rb +90 -0
- data/lib/reverse_asciidoctor/config.rb +53 -0
- data/lib/reverse_asciidoctor/converters.rb +33 -0
- data/lib/reverse_asciidoctor/converters/a.rb +38 -0
- data/lib/reverse_asciidoctor/converters/aside.rb +14 -0
- data/lib/reverse_asciidoctor/converters/audio.rb +34 -0
- data/lib/reverse_asciidoctor/converters/base.rb +24 -0
- data/lib/reverse_asciidoctor/converters/blockquote.rb +18 -0
- data/lib/reverse_asciidoctor/converters/br.rb +11 -0
- data/lib/reverse_asciidoctor/converters/bypass.rb +77 -0
- data/lib/reverse_asciidoctor/converters/code.rb +15 -0
- data/lib/reverse_asciidoctor/converters/div.rb +14 -0
- data/lib/reverse_asciidoctor/converters/drop.rb +18 -0
- data/lib/reverse_asciidoctor/converters/em.rb +18 -0
- data/lib/reverse_asciidoctor/converters/figure.rb +21 -0
- data/lib/reverse_asciidoctor/converters/h.rb +19 -0
- data/lib/reverse_asciidoctor/converters/head.rb +18 -0
- data/lib/reverse_asciidoctor/converters/hr.rb +11 -0
- data/lib/reverse_asciidoctor/converters/ignore.rb +12 -0
- data/lib/reverse_asciidoctor/converters/img.rb +80 -0
- data/lib/reverse_asciidoctor/converters/li.rb +24 -0
- data/lib/reverse_asciidoctor/converters/mark.rb +12 -0
- data/lib/reverse_asciidoctor/converters/math.rb +20 -0
- data/lib/reverse_asciidoctor/converters/ol.rb +46 -0
- data/lib/reverse_asciidoctor/converters/p.rb +17 -0
- data/lib/reverse_asciidoctor/converters/pass_through.rb +9 -0
- data/lib/reverse_asciidoctor/converters/pre.rb +38 -0
- data/lib/reverse_asciidoctor/converters/q.rb +12 -0
- data/lib/reverse_asciidoctor/converters/strong.rb +17 -0
- data/lib/reverse_asciidoctor/converters/sub.rb +12 -0
- data/lib/reverse_asciidoctor/converters/sup.rb +12 -0
- data/lib/reverse_asciidoctor/converters/table.rb +64 -0
- data/lib/reverse_asciidoctor/converters/td.rb +67 -0
- data/lib/reverse_asciidoctor/converters/text.rb +65 -0
- data/lib/reverse_asciidoctor/converters/th.rb +16 -0
- data/lib/reverse_asciidoctor/converters/tr.rb +22 -0
- data/lib/reverse_asciidoctor/converters/video.rb +36 -0
- data/lib/reverse_asciidoctor/errors.rb +10 -0
- data/lib/reverse_asciidoctor/version.rb +3 -0
- data/reverse_adoc.gemspec +35 -0
- data/spec/assets/anchors.html +22 -0
- data/spec/assets/basic.html +58 -0
- data/spec/assets/code.html +22 -0
- data/spec/assets/escapables.html +15 -0
- data/spec/assets/from_the_wild.html +23 -0
- data/spec/assets/full_example.html +49 -0
- data/spec/assets/html_fragment.html +3 -0
- data/spec/assets/lists.html +137 -0
- data/spec/assets/minimum.html +4 -0
- data/spec/assets/paragraphs.html +24 -0
- data/spec/assets/quotation.html +12 -0
- data/spec/assets/tables.html +99 -0
- data/spec/assets/unknown_tags.html +9 -0
- data/spec/components/anchors_spec.rb +21 -0
- data/spec/components/basic_spec.rb +49 -0
- data/spec/components/code_spec.rb +28 -0
- data/spec/components/escapables_spec.rb +23 -0
- data/spec/components/from_the_wild_spec.rb +17 -0
- data/spec/components/html_fragment_spec.rb +11 -0
- data/spec/components/lists_spec.rb +86 -0
- data/spec/components/paragraphs_spec.rb +15 -0
- data/spec/components/quotation_spec.rb +12 -0
- data/spec/components/tables_spec.rb +31 -0
- data/spec/components/unknown_tags_spec.rb +39 -0
- data/spec/lib/reverse_asciidoctor/cleaner_spec.rb +157 -0
- data/spec/lib/reverse_asciidoctor/config_spec.rb +26 -0
- data/spec/lib/reverse_asciidoctor/converters/aside_spec.rb +12 -0
- data/spec/lib/reverse_asciidoctor/converters/audio_spec.rb +18 -0
- data/spec/lib/reverse_asciidoctor/converters/blockquote_spec.rb +24 -0
- data/spec/lib/reverse_asciidoctor/converters/br_spec.rb +9 -0
- data/spec/lib/reverse_asciidoctor/converters/code_spec.rb +18 -0
- data/spec/lib/reverse_asciidoctor/converters/div_spec.rb +18 -0
- data/spec/lib/reverse_asciidoctor/converters/figure_spec.rb +13 -0
- data/spec/lib/reverse_asciidoctor/converters/img_spec.rb +28 -0
- data/spec/lib/reverse_asciidoctor/converters/li_spec.rb +13 -0
- data/spec/lib/reverse_asciidoctor/converters/mark_spec.rb +10 -0
- data/spec/lib/reverse_asciidoctor/converters/p_spec.rb +12 -0
- data/spec/lib/reverse_asciidoctor/converters/pre_spec.rb +45 -0
- data/spec/lib/reverse_asciidoctor/converters/q_spec.rb +10 -0
- data/spec/lib/reverse_asciidoctor/converters/strong_spec.rb +20 -0
- data/spec/lib/reverse_asciidoctor/converters/text_spec.rb +62 -0
- data/spec/lib/reverse_asciidoctor/converters/video_spec.rb +18 -0
- data/spec/lib/reverse_asciidoctor/converters_spec.rb +19 -0
- data/spec/lib/reverse_asciidoctor_spec.rb +37 -0
- data/spec/spec_helper.rb +21 -0
- metadata +299 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
# Unless run with ReverseAsciidoctor.config.mathml2asciimath,
|
2
|
+
# this is cheating: we're injecting MathML into Asciidoctor, but
|
3
|
+
# Asciidoctor only understands AsciiMath or LaTeX
|
4
|
+
|
5
|
+
require "mathml2asciimath"
|
6
|
+
|
7
|
+
module ReverseAsciidoctor
|
8
|
+
module Converters
|
9
|
+
class Math < Base
|
10
|
+
def convert(node, state = {})
|
11
|
+
stem = node.to_s.gsub(/\n/, " ")
|
12
|
+
stem = MathML2AsciiMath.m2a(stem) if ReverseAsciidoctor.config.mathml2asciimath
|
13
|
+
stem = stem.gsub(/\[/, "\\[").gsub(/\]/, "\\]").gsub(/\(\(([^\)]+)\)\)/, "(\\1)") unless stem.nil?
|
14
|
+
" stem:[" << stem << "] "
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
register :math, Math.new
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module ReverseAsciidoctor
|
2
|
+
module Converters
|
3
|
+
class Ol < Base
|
4
|
+
def convert(node, state = {})
|
5
|
+
id = node['id']
|
6
|
+
anchor = id ? "[[#{id}]]\n" : ""
|
7
|
+
ol_count = state.fetch(:ol_count, 0) + 1
|
8
|
+
attrs = ol_attrs(node)
|
9
|
+
"\n#{anchor}#{attrs}" << treat_children(node, state.merge(ol_count: ol_count))
|
10
|
+
end
|
11
|
+
|
12
|
+
def number_style(node)
|
13
|
+
style = case node["style"]
|
14
|
+
when "1" then "arabic"
|
15
|
+
when "A" then "upperalpha"
|
16
|
+
when "a" then "loweralpha"
|
17
|
+
when "I" then "upperroman"
|
18
|
+
when "i" then "lowerroman"
|
19
|
+
else
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def ol_attrs(node)
|
25
|
+
style = number_style(node)
|
26
|
+
reversed = "%reversed" if node["reversed"]
|
27
|
+
start = "start=#{node['start']}" if node["start"]
|
28
|
+
type = "type=#{node['type']}" if node["type"]
|
29
|
+
attrs = []
|
30
|
+
attrs << style if style
|
31
|
+
attrs << reversed if reversed
|
32
|
+
attrs << start if start
|
33
|
+
attrs << type if type
|
34
|
+
if attrs.empty?
|
35
|
+
""
|
36
|
+
else
|
37
|
+
"[#{attrs.join(',')}]\n"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
register :ol, Ol.new
|
43
|
+
register :ul, Ol.new
|
44
|
+
register :dir, Ol.new
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ReverseAsciidoctor
|
2
|
+
module Converters
|
3
|
+
class P < Base
|
4
|
+
def convert(node, state = {})
|
5
|
+
id = node['id']
|
6
|
+
anchor = id ? "[[#{id}]]\n" : ""
|
7
|
+
if state[:tdsinglepara]
|
8
|
+
"#{anchor}" << treat_children(node, state).strip
|
9
|
+
else
|
10
|
+
"\n\n#{anchor}" << treat_children(node, state).strip << "\n\n"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
register :p, P.new
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module ReverseAsciidoctor
|
2
|
+
module Converters
|
3
|
+
class Pre < Base
|
4
|
+
def convert(node, state = {})
|
5
|
+
id = node['id']
|
6
|
+
anchor = id ? "[[#{id}]]\n" : ""
|
7
|
+
lang = language(node)
|
8
|
+
content = treat_children(node, state)
|
9
|
+
if lang
|
10
|
+
"\n\n#{anchor}[source,#{lang}]\n----\n" << content.lines.to_a.join("") << "\n----\n\n"
|
11
|
+
else
|
12
|
+
"\n\n#{anchor}....\n" << content.lines.to_a.join("") << "\n....\n\n"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def treat(node, state)
|
19
|
+
node.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
def language(node)
|
23
|
+
lang = language_from_highlight_class(node)
|
24
|
+
lang || language_from_confluence_class(node)
|
25
|
+
end
|
26
|
+
|
27
|
+
def language_from_highlight_class(node)
|
28
|
+
node.parent['class'].to_s[/highlight-([a-zA-Z0-9]+)/, 1]
|
29
|
+
end
|
30
|
+
|
31
|
+
def language_from_confluence_class(node)
|
32
|
+
node['class'].to_s[/brush:\s?(:?.*);/, 1]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
register :pre, Pre.new
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ReverseAsciidoctor
|
2
|
+
module Converters
|
3
|
+
class Strong < Base
|
4
|
+
def convert(node, state = {})
|
5
|
+
content = treat_children(node, state.merge(already_strong: true))
|
6
|
+
if content.strip.empty? || state[:already_strong]
|
7
|
+
content
|
8
|
+
else
|
9
|
+
"#{content[/^\s*/]}*#{content.strip}*#{content[/\s*$/]}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
register :strong, Strong.new
|
15
|
+
register :b, Strong.new
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module ReverseAsciidoctor
|
2
|
+
module Converters
|
3
|
+
class Table < Base
|
4
|
+
def convert(node, state = {})
|
5
|
+
id = node['id']
|
6
|
+
anchor = id ? "[[#{id}]]\n" : ""
|
7
|
+
title = extract_title(node)
|
8
|
+
title = ".#{title}\n" unless title.empty?
|
9
|
+
attrs = style(node)
|
10
|
+
"\n\n#{anchor}#{attrs}#{title}|===\n" << treat_children(node, state) << "\n|===\n"
|
11
|
+
end
|
12
|
+
|
13
|
+
def extract_title(node)
|
14
|
+
title = node.at("./caption")
|
15
|
+
return "" if title.nil?
|
16
|
+
treat_children(title, {})
|
17
|
+
end
|
18
|
+
|
19
|
+
def frame(node)
|
20
|
+
case node["frame"]
|
21
|
+
when "void"
|
22
|
+
"frame=none"
|
23
|
+
when "hsides"
|
24
|
+
"frame=topbot"
|
25
|
+
when "vsides"
|
26
|
+
"frame=sides"
|
27
|
+
when "box", "border"
|
28
|
+
"frame=all"
|
29
|
+
else
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def rules(node)
|
35
|
+
case node["rules"]
|
36
|
+
when "all"
|
37
|
+
"rules=all"
|
38
|
+
when "rows"
|
39
|
+
"rules=rows"
|
40
|
+
when "cols"
|
41
|
+
"rules=cols"
|
42
|
+
when "none"
|
43
|
+
"rules=none"
|
44
|
+
else
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def style(node)
|
50
|
+
width = "width=#{node['width']}" if node['width']
|
51
|
+
attrs = []
|
52
|
+
frame_attr = frame(node)
|
53
|
+
rules_attr = rules(node)
|
54
|
+
attrs << width if width
|
55
|
+
attrs << frame_attr if frame_attr
|
56
|
+
attrs << rules_attr if rules_attr
|
57
|
+
return "" if attrs.empty?
|
58
|
+
"[#{attrs.join(',')}]\n"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
register :table, Table.new
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module ReverseAsciidoctor
|
2
|
+
module Converters
|
3
|
+
class Td < Base
|
4
|
+
def convert(node, state = {})
|
5
|
+
id = node['id']
|
6
|
+
anchor = id ? "[[#{id}]]" : ""
|
7
|
+
colrowattr = colrow(node['colspan'], node['rowspan'])
|
8
|
+
alignattr = alignstyle(node)
|
9
|
+
style = cellstyle(node)
|
10
|
+
singlepara = node.elements.size == 1 && node.elements.first.name == "p"
|
11
|
+
state[:tdsinglepara] = singlepara if singlepara
|
12
|
+
adoccell = node.at(".//ul | .//ol | .//pre | .//blockquote | .//br | .//hr") ||
|
13
|
+
node.at(".//p") && !singlepara
|
14
|
+
style = "a" if adoccell
|
15
|
+
delim = adoccell ? "\n" : " "
|
16
|
+
content = treat_children(node, state)
|
17
|
+
"#{colrowattr}#{alignattr}#{style}| #{anchor}#{content}#{delim}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def cellstyle(node)
|
21
|
+
""
|
22
|
+
end
|
23
|
+
|
24
|
+
def colrow(colspan, rowspan)
|
25
|
+
if colspan && rowspan
|
26
|
+
"#{colspan}.#{rowspan}+"
|
27
|
+
elsif colspan
|
28
|
+
"#{colspan}+"
|
29
|
+
elsif rowspan
|
30
|
+
".#{rowspan}+"
|
31
|
+
else
|
32
|
+
""
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def alignstyle(node)
|
37
|
+
align = node["align"]
|
38
|
+
valign = node["valign"]
|
39
|
+
a = case align
|
40
|
+
when "left" then "<"
|
41
|
+
when "center" then "^"
|
42
|
+
when "right" then ">"
|
43
|
+
else
|
44
|
+
""
|
45
|
+
end
|
46
|
+
v = case valign
|
47
|
+
when "top" then "<"
|
48
|
+
when "middle" then "^"
|
49
|
+
when "bottom" then ">"
|
50
|
+
else
|
51
|
+
""
|
52
|
+
end
|
53
|
+
if align && valign
|
54
|
+
"#{a}.#{v}"
|
55
|
+
elsif align
|
56
|
+
a
|
57
|
+
elsif valign
|
58
|
+
".#{v}"
|
59
|
+
else
|
60
|
+
""
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
register :td, Td.new
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module ReverseAsciidoctor
|
2
|
+
module Converters
|
3
|
+
class Text < Base
|
4
|
+
def convert(node, state = {})
|
5
|
+
if node.text.strip.empty?
|
6
|
+
treat_empty(node, state)
|
7
|
+
else
|
8
|
+
treat_text(node)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def treat_empty(node, state)
|
15
|
+
parent = node.parent.name.to_sym
|
16
|
+
if [:ol, :ul].include?(parent) # Otherwise the identation is broken
|
17
|
+
''
|
18
|
+
elsif state[:tdsinglepara]
|
19
|
+
''
|
20
|
+
elsif node.text == ' ' # Regular whitespace text node
|
21
|
+
' '
|
22
|
+
else
|
23
|
+
''
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def treat_text(node)
|
28
|
+
text = node.text
|
29
|
+
text = preserve_nbsp(text)
|
30
|
+
text = remove_border_newlines(text)
|
31
|
+
text = remove_inner_newlines(text)
|
32
|
+
text = escape_keychars(text)
|
33
|
+
|
34
|
+
text = preserve_keychars_within_backticks(text)
|
35
|
+
text = preserve_tags(text)
|
36
|
+
|
37
|
+
text
|
38
|
+
end
|
39
|
+
|
40
|
+
def preserve_nbsp(text)
|
41
|
+
text.gsub(/\u00A0/, " ")
|
42
|
+
end
|
43
|
+
|
44
|
+
def preserve_tags(text)
|
45
|
+
text.gsub(/[<>]/, '>' => '\>', '<' => '\<')
|
46
|
+
end
|
47
|
+
|
48
|
+
def remove_border_newlines(text)
|
49
|
+
text.gsub(/\A\n+/, '').gsub(/\n+\z/, '')
|
50
|
+
end
|
51
|
+
|
52
|
+
def remove_inner_newlines(text)
|
53
|
+
text.tr("\n\t", ' ').squeeze(' ')
|
54
|
+
end
|
55
|
+
|
56
|
+
def preserve_keychars_within_backticks(text)
|
57
|
+
text.gsub(/`.*?`/) do |match|
|
58
|
+
match.gsub('\_', '_').gsub('\*', '*')
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
register :text, Text.new
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ReverseAsciidoctor
|
2
|
+
module Converters
|
3
|
+
class Tr < Base
|
4
|
+
def convert(node, state = {})
|
5
|
+
content = treat_children(node, state).rstrip
|
6
|
+
result = "#{content}\n"
|
7
|
+
table_header_row?(node) ? result + underline_for(node) : result
|
8
|
+
end
|
9
|
+
|
10
|
+
def table_header_row?(node)
|
11
|
+
# node.element_children.all? {|child| child.name.to_sym == :th}
|
12
|
+
node.previous_element.nil?
|
13
|
+
end
|
14
|
+
|
15
|
+
def underline_for(node)
|
16
|
+
"\n"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
register :tr, Tr.new
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module ReverseAsciidoctor
|
2
|
+
module Converters
|
3
|
+
class Video < Base
|
4
|
+
def convert(node, state = {})
|
5
|
+
autoplay = node['autoplay']
|
6
|
+
loop_attr = node['loop']
|
7
|
+
controls = node['controls']
|
8
|
+
src = node['src']
|
9
|
+
id = node['id']
|
10
|
+
anchor = id ? "[[#{id}]]\n" : ""
|
11
|
+
title = extract_title(node)
|
12
|
+
title = ".#{title}\n" unless title.empty?
|
13
|
+
[anchor, title, "video::", src, "[", options(node), "]"].join("")
|
14
|
+
end
|
15
|
+
|
16
|
+
def options(node)
|
17
|
+
autoplay = node['autoplay']
|
18
|
+
loop_attr = node['loop']
|
19
|
+
controls = node['controls']
|
20
|
+
width = node['width']
|
21
|
+
ret = ""
|
22
|
+
if autoplay || loop_attr || controls
|
23
|
+
out = []
|
24
|
+
out << "autoplay" if autoplay
|
25
|
+
out << "loop" if loop_attr
|
26
|
+
out << "controls" if controls
|
27
|
+
out << "width=#{width}" if width
|
28
|
+
ret = %{options="#{out.join(',')}"}
|
29
|
+
end
|
30
|
+
ret
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
register :video, Video.new
|
35
|
+
end
|
36
|
+
end
|