asciidoctor_vaped 0.1.0
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 +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +46 -0
- data/exe/asciidoctor_vaped +6 -0
- data/lib/asciidoctor_vaped/ast/document.rb +34 -0
- data/lib/asciidoctor_vaped/ast/element.rb +17 -0
- data/lib/asciidoctor_vaped/ast/node.rb +53 -0
- data/lib/asciidoctor_vaped/ast/text.rb +40 -0
- data/lib/asciidoctor_vaped/cli.rb +59 -0
- data/lib/asciidoctor_vaped/converter/base_converter.rb +68 -0
- data/lib/asciidoctor_vaped/converter/docbook.rb +116 -0
- data/lib/asciidoctor_vaped/converter/html.rb +119 -0
- data/lib/asciidoctor_vaped/converter/node.rb +92 -0
- data/lib/asciidoctor_vaped/converter.rb +6 -0
- data/lib/asciidoctor_vaped/error.rb +5 -0
- data/lib/asciidoctor_vaped/parser/blocks/admonition.rb +18 -0
- data/lib/asciidoctor_vaped/parser/blocks/common/base_node.rb +23 -0
- data/lib/asciidoctor_vaped/parser/blocks/common/blank_line.rb +19 -0
- data/lib/asciidoctor_vaped/parser/blocks/common/comment.rb +19 -0
- data/lib/asciidoctor_vaped/parser/blocks/delimited/delimited_node.rb +62 -0
- data/lib/asciidoctor_vaped/parser/blocks/delimited/example.rb +18 -0
- data/lib/asciidoctor_vaped/parser/blocks/delimited/listing.rb +14 -0
- data/lib/asciidoctor_vaped/parser/blocks/delimited/literal.rb +14 -0
- data/lib/asciidoctor_vaped/parser/blocks/delimited/open.rb +18 -0
- data/lib/asciidoctor_vaped/parser/blocks/delimited/passthrough.rb +14 -0
- data/lib/asciidoctor_vaped/parser/blocks/delimited/quote.rb +18 -0
- data/lib/asciidoctor_vaped/parser/blocks/delimited/sidebar.rb +18 -0
- data/lib/asciidoctor_vaped/parser/blocks/heading.rb +19 -0
- data/lib/asciidoctor_vaped/parser/blocks/lists/list_base.rb +29 -0
- data/lib/asciidoctor_vaped/parser/blocks/lists/list_item.rb +24 -0
- data/lib/asciidoctor_vaped/parser/blocks/lists/ordered_list.rb +16 -0
- data/lib/asciidoctor_vaped/parser/blocks/lists/unordered_list.rb +16 -0
- data/lib/asciidoctor_vaped/parser/blocks/metadata/caption.rb +17 -0
- data/lib/asciidoctor_vaped/parser/blocks/metadata/document_attribute.rb +18 -0
- data/lib/asciidoctor_vaped/parser/blocks/metadata/element_attributes.rb +86 -0
- data/lib/asciidoctor_vaped/parser/blocks/paragraph.rb +20 -0
- data/lib/asciidoctor_vaped/parser/blocks/tables/table.rb +58 -0
- data/lib/asciidoctor_vaped/parser/blocks/tables/table_cell.rb +13 -0
- data/lib/asciidoctor_vaped/parser/blocks/tables/table_row.rb +15 -0
- data/lib/asciidoctor_vaped/parser/blocks.rb +39 -0
- data/lib/asciidoctor_vaped/parser/context.rb +51 -0
- data/lib/asciidoctor_vaped/parser/inline.rb +60 -0
- data/lib/asciidoctor_vaped/parser/inlines/emphasis.rb +19 -0
- data/lib/asciidoctor_vaped/parser/inlines/link.rb +20 -0
- data/lib/asciidoctor_vaped/parser/inlines/monospace.rb +19 -0
- data/lib/asciidoctor_vaped/parser/inlines/strong.rb +19 -0
- data/lib/asciidoctor_vaped/parser/inlines/url.rb +19 -0
- data/lib/asciidoctor_vaped/parser.rb +72 -0
- data/lib/asciidoctor_vaped/reader.rb +47 -0
- data/lib/asciidoctor_vaped/version.rb +5 -0
- data/lib/asciidoctor_vaped.rb +52 -0
- data/sig/asciidoctor_vaped.rbs +53 -0
- metadata +96 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 8dc18c51e42240a5c3889e9a43d1d7ce0ec56465e0d778d0db52192a7bf4d908
|
|
4
|
+
data.tar.gz: df065d747398d3d880254b426e0306c2c3b20e925af498f6c32bad7c7bfa0f07
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: ee9174d4094c2657d88507c9be7dcfb13fe335383e78ce8da3fa6ff54f66af63a9dd9ffa9bf72c0d3aa08bd46a05d564ea2392c37abe7e4980a12953a94cef73
|
|
7
|
+
data.tar.gz: d582db8090a31c3c58967eaf99920f4219d84cc58abfad85d55624cfb8b663456e5d98d974294302f7e1ead2ef49ad4f9652e56086ea9a288dc22d593300e177
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kaben
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# AsciidoctorVaped
|
|
2
|
+
|
|
3
|
+
I vibed this project inspired by [Asciidoctor](https://asciidoctor.org). It has a long history,
|
|
4
|
+
but I can't read lots of if-else statements. So, I made this.
|
|
5
|
+
It is still in development. Be careful to use.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Install the gem and add to the application's Gemfile by executing:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bundle add asciidoctor_vaped
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
gem install asciidoctor_vaped
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
# just print a html file from adoc file.
|
|
25
|
+
asciidoctor_vaped demo.adoc
|
|
26
|
+
|
|
27
|
+
# this can accept a text.
|
|
28
|
+
asciidoctor_vaped -s 'hello *world*'
|
|
29
|
+
|
|
30
|
+
# or print something different like docbook.
|
|
31
|
+
asciidoctor_vaped demo.adoc demo.dkb
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Development
|
|
35
|
+
|
|
36
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
37
|
+
|
|
38
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
39
|
+
|
|
40
|
+
## Contributing
|
|
41
|
+
|
|
42
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/asciidoctor_vaped.
|
|
43
|
+
|
|
44
|
+
## License
|
|
45
|
+
|
|
46
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "node"
|
|
4
|
+
|
|
5
|
+
module AsciidoctorVaped
|
|
6
|
+
module AST
|
|
7
|
+
class Document < Node
|
|
8
|
+
attr_accessor :doctitle
|
|
9
|
+
attr_reader :attributes
|
|
10
|
+
|
|
11
|
+
def initialize(source, attributes: {})
|
|
12
|
+
@attributes = attributes.dup
|
|
13
|
+
@source = source
|
|
14
|
+
super()
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def context
|
|
18
|
+
:document
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def source
|
|
22
|
+
@source.dup
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def register_attribute(name, value)
|
|
26
|
+
attributes[name.to_s] = value
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def to_h
|
|
30
|
+
super.merge(doctitle:)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "node"
|
|
4
|
+
|
|
5
|
+
module AsciidoctorVaped
|
|
6
|
+
module AST
|
|
7
|
+
class Element < Node
|
|
8
|
+
attr_reader :context, :attributes
|
|
9
|
+
|
|
10
|
+
def initialize(context, attributes: {}, children: [])
|
|
11
|
+
@context = context
|
|
12
|
+
@attributes = attributes
|
|
13
|
+
super(children:)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AsciidoctorVaped
|
|
4
|
+
module AST
|
|
5
|
+
class Node
|
|
6
|
+
TEXT_CONTEXTS = %i[text link strong emphasis monospace].freeze
|
|
7
|
+
|
|
8
|
+
attr_reader :children
|
|
9
|
+
attr_accessor :parent
|
|
10
|
+
|
|
11
|
+
def initialize(children: [])
|
|
12
|
+
@children = []
|
|
13
|
+
append_children(children)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def <<(node)
|
|
17
|
+
append(node)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def append(node)
|
|
21
|
+
node.parent = self
|
|
22
|
+
children << node
|
|
23
|
+
node
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def append_children(nodes)
|
|
27
|
+
nodes.each { |node| append(node) }
|
|
28
|
+
self
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def text
|
|
32
|
+
children.select { |child| TEXT_CONTEXTS.include?(child.context) }.map(&:text).join
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def parse_inline
|
|
36
|
+
append_children(Parser::Inline.parse(text))
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def sections
|
|
40
|
+
children.select { |child| child.context == :section }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def to_h
|
|
44
|
+
{
|
|
45
|
+
context:,
|
|
46
|
+
text:,
|
|
47
|
+
attributes:,
|
|
48
|
+
children: children.map(&:to_h)
|
|
49
|
+
}
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "node"
|
|
4
|
+
|
|
5
|
+
module AsciidoctorVaped
|
|
6
|
+
module AST
|
|
7
|
+
class Text < Node
|
|
8
|
+
attr_accessor :value
|
|
9
|
+
|
|
10
|
+
def initialize(value)
|
|
11
|
+
@value = value
|
|
12
|
+
super()
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def context
|
|
16
|
+
:text
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def text
|
|
20
|
+
value
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def text=(value)
|
|
24
|
+
self.value = value
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def children
|
|
28
|
+
[]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def to_h
|
|
32
|
+
{
|
|
33
|
+
context:,
|
|
34
|
+
text:,
|
|
35
|
+
children: []
|
|
36
|
+
}
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../asciidoctor_vaped"
|
|
4
|
+
|
|
5
|
+
module AsciidoctorVaped
|
|
6
|
+
class CLI
|
|
7
|
+
def initialize(argv, out: $stdout, err: $stderr)
|
|
8
|
+
@argv = argv.dup
|
|
9
|
+
@out = out
|
|
10
|
+
@err = err
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def run
|
|
14
|
+
return string_mode if @argv.first == "-s"
|
|
15
|
+
return usage(1) if @argv.empty?
|
|
16
|
+
|
|
17
|
+
file_mode
|
|
18
|
+
rescue Errno::ENOENT => error
|
|
19
|
+
@err.puts error.message
|
|
20
|
+
1
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def string_mode
|
|
26
|
+
@argv.shift
|
|
27
|
+
source = @argv.shift
|
|
28
|
+
return usage(1) unless source
|
|
29
|
+
|
|
30
|
+
@out.puts AsciidoctorVaped.convert(source, backend: :docbook, header_footer: false)
|
|
31
|
+
0
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def file_mode
|
|
35
|
+
input = @argv.shift
|
|
36
|
+
output = @argv.shift || default_output(input)
|
|
37
|
+
File.write(output, AsciidoctorVaped.convert(File.read(input), backend: backend_for(output)))
|
|
38
|
+
0
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def default_output(input)
|
|
42
|
+
"#{File.basename(input, File.extname(input))}.html"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def backend_for(output)
|
|
46
|
+
case File.extname(output).downcase
|
|
47
|
+
when ".dkb", ".xml" then :docbook
|
|
48
|
+
else :html
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def usage(status)
|
|
53
|
+
@err.puts "Usage:"
|
|
54
|
+
@err.puts " asciidoctor_vaped FILE [OUTPUT.html]"
|
|
55
|
+
@err.puts " asciidoctor_vaped -s STRING"
|
|
56
|
+
status
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../parser/inline"
|
|
4
|
+
|
|
5
|
+
module AsciidoctorVaped
|
|
6
|
+
module Converter
|
|
7
|
+
class BaseConverter
|
|
8
|
+
TEXT_NODE_CONTEXTS = %i[text link strong emphasis monospace].freeze
|
|
9
|
+
|
|
10
|
+
def initialize(options = {})
|
|
11
|
+
@options = options
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def convert(_document)
|
|
15
|
+
raise NotImplementedError, "#{self.class} must implement #convert"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def escape(value)
|
|
21
|
+
value.to_s
|
|
22
|
+
.gsub("&", "&")
|
|
23
|
+
.gsub("<", "<")
|
|
24
|
+
.gsub(">", ">")
|
|
25
|
+
.gsub('"', """)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def escape_attr(value)
|
|
29
|
+
escape(value).gsub('"', """)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def tag(name, content, attrs = {})
|
|
33
|
+
"<#{name}#{html_attrs attrs}>#{content}</#{name}>"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def html_attrs(attrs)
|
|
37
|
+
attrs.compact.map { |key, value| %( #{key}="#{escape_attr value}") }.join
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def render_nodes(node)
|
|
41
|
+
child_nodes(node).map { |child| convert_node(child) }.join("\n")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def render_content(node)
|
|
45
|
+
child_nodes(node).empty? ? render_text(node) : render_nodes(node)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def render_text(value)
|
|
49
|
+
nodes = value.respond_to?(:children) ? text_children(value) : Parser::Inline.parse(value)
|
|
50
|
+
return escape(value.text.to_s) if nodes.empty? && value.respond_to?(:text)
|
|
51
|
+
|
|
52
|
+
nodes.map { |node| convert_node(node) }.join
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def child_nodes(node)
|
|
56
|
+
node.children.reject { |child| text_node?(child) }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def text_children(node)
|
|
60
|
+
node.children.select { |child| text_node?(child) }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def text_node?(node)
|
|
64
|
+
TEXT_NODE_CONTEXTS.include?(node.context)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AsciidoctorVaped
|
|
4
|
+
module Converter
|
|
5
|
+
class DocBook < BaseConverter
|
|
6
|
+
include Converter::Node
|
|
7
|
+
|
|
8
|
+
def convert(document)
|
|
9
|
+
title = document.doctitle || "Untitled"
|
|
10
|
+
body = render_nodes(document)
|
|
11
|
+
%(<article>\n<title>#{escape title}</title>\n#{body}\n</article>)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def paragraph_tag
|
|
17
|
+
"para"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def section(node)
|
|
21
|
+
body = render_nodes(node)
|
|
22
|
+
%(<section>\n<title>#{render_text node}</title>\n#{body}\n</section>)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def listing(node)
|
|
26
|
+
language = node.attributes[:language]
|
|
27
|
+
attrs = language ? %( language="#{escape_attr language}") : ""
|
|
28
|
+
"<programlisting#{attrs}>#{escape node.text}</programlisting>"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def literal_tag
|
|
32
|
+
"literallayout"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def open(node)
|
|
36
|
+
render_content(node)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def list(node)
|
|
40
|
+
tag_name = node.context == :olist ? "orderedlist" : "itemizedlist"
|
|
41
|
+
items = node.children.map { |item| "<listitem><para>#{render_text item}</para></listitem>" }.join("\n")
|
|
42
|
+
"<#{tag_name}>\n#{items}\n</#{tag_name}>"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def table(node)
|
|
46
|
+
rows = node.children.map do |row|
|
|
47
|
+
cells = row.children.map { |cell| "<entry>#{render_text cell}</entry>" }.join
|
|
48
|
+
"<row>#{cells}</row>"
|
|
49
|
+
end.join("\n")
|
|
50
|
+
"<informaltable>\n<tgroup cols=\"#{column_count node}\">\n<tbody>\n#{rows}\n</tbody>\n</tgroup>\n</informaltable>"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def admonition(node)
|
|
54
|
+
name = node.attributes.fetch(:name, "note").to_s.downcase
|
|
55
|
+
"<#{name}>#{paragraph_content node}</#{name}>"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def example(node)
|
|
59
|
+
titled_node("example", node)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def quote(node)
|
|
63
|
+
titled_node("blockquote", node)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def sidebar(node)
|
|
67
|
+
titled_node("sidebar", node)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def titled_node(tag_name, node)
|
|
71
|
+
title = node.attributes[:title] ? "<title>#{render_text node.attributes[:title]}</title>\n" : ""
|
|
72
|
+
"<#{tag_name}>\n#{title}#{paragraph_content node}\n</#{tag_name}>"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def paragraph_content(node)
|
|
76
|
+
child_nodes(node).empty? ? "<para>#{render_text node}</para>" : render_nodes(node)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def column_count(node)
|
|
80
|
+
node.children.map { |row| row.children.length }.max || 1
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def title_tag
|
|
84
|
+
"title"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def title_attrs
|
|
88
|
+
{}
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def link_tag
|
|
92
|
+
"link"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def link_attrs(node)
|
|
96
|
+
{ "xlink:href": node.attributes.fetch(:target) }
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def strong_tag
|
|
100
|
+
"emphasis"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def strong_attrs
|
|
104
|
+
{ role: "strong" }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def emphasis_tag
|
|
108
|
+
"emphasis"
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def monospace_tag
|
|
112
|
+
"literal"
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AsciidoctorVaped
|
|
4
|
+
module Converter
|
|
5
|
+
class HTML < BaseConverter
|
|
6
|
+
include Converter::Node
|
|
7
|
+
|
|
8
|
+
def convert(document)
|
|
9
|
+
title = document.doctitle || "Untitled"
|
|
10
|
+
body = render_nodes(document)
|
|
11
|
+
return body if @options[:header_footer] == false
|
|
12
|
+
|
|
13
|
+
%(<!DOCTYPE html>
|
|
14
|
+
<html>
|
|
15
|
+
<head>
|
|
16
|
+
<meta charset="utf-8">
|
|
17
|
+
<title>#{escape title}</title>
|
|
18
|
+
</head>
|
|
19
|
+
<body>
|
|
20
|
+
#{body}
|
|
21
|
+
</body>
|
|
22
|
+
</html>)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def paragraph_tag
|
|
26
|
+
"p"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def section(node)
|
|
30
|
+
level = node.attributes.fetch(:level, 1)
|
|
31
|
+
heading = "h#{[level + 1, 6].min}"
|
|
32
|
+
%(<div class="sect#{level}">\n<#{heading}>#{render_text node}</#{heading}>\n#{render_nodes node}\n</div>)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def listing(node)
|
|
36
|
+
language = node.attributes[:language]
|
|
37
|
+
code_attrs = language ? %( class="language-#{escape_attr language}" data-lang="#{escape_attr language}") : ""
|
|
38
|
+
%(<div class="listingblock">\n#{title node}\n<div class="content">\n<pre class="highlight"><code#{code_attrs}>#{escape node.text}</code></pre>\n</div>\n</div>)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def literal_tag
|
|
42
|
+
"pre"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def list(node)
|
|
46
|
+
tag_name = list_tag(node)
|
|
47
|
+
items = node.children.map { |item| list_item(item) }.join("\n")
|
|
48
|
+
%(<div class="#{node.context}">\n<#{tag_name}>\n#{items}\n</#{tag_name}>\n</div>)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def list_item(node)
|
|
52
|
+
"<li>#{render_content node}</li>"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def table(node)
|
|
56
|
+
rows = node.children.map { |row| table_row(row) }.join("\n")
|
|
57
|
+
%(<table class="tableblock frame-all grid-all stretch">\n<tbody>\n#{rows}\n</tbody>\n</table>)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def table_row(row)
|
|
61
|
+
cells = row.children.map { |cell| %(<td class="tableblock halign-left valign-top">#{render_text cell}</td>) }
|
|
62
|
+
"<tr>\n#{cells.join("\n")}\n</tr>"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def admonition(node)
|
|
66
|
+
name = node.attributes.fetch(:name, "note").to_s
|
|
67
|
+
%(<div class="admonitionblock #{escape_attr name.downcase}">\n<table>\n<tr>\n<td class="icon"><div class="title">#{escape name.capitalize}</div></td>\n<td class="content">#{render_content node}</td>\n</tr>\n</table>\n</div>)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def example(node)
|
|
71
|
+
wrapped_node("exampleblock", node)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def quote(node)
|
|
75
|
+
wrapped_node("quoteblock", node)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def sidebar(node)
|
|
79
|
+
wrapped_node("sidebarblock", node)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def title_tag
|
|
83
|
+
"div"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def title_attrs
|
|
87
|
+
{ class: "title" }
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def link_tag
|
|
91
|
+
"a"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def link_attrs(node)
|
|
95
|
+
{ href: node.attributes.fetch(:target) }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def strong_tag
|
|
99
|
+
"strong"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def emphasis_tag
|
|
103
|
+
"em"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def monospace_tag
|
|
107
|
+
"code"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def wrapped_node(class_name, node)
|
|
111
|
+
%(<div class="#{class_name}">\n#{title node}\n<div class="content">#{render_content node}</div>\n</div>)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def list_tag(node)
|
|
115
|
+
node.context == :olist ? "ol" : "ul"
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AsciidoctorVaped
|
|
4
|
+
module Converter
|
|
5
|
+
module Node
|
|
6
|
+
NODE_RENDERERS = {
|
|
7
|
+
section: :section,
|
|
8
|
+
paragraph: :paragraph,
|
|
9
|
+
listing: :listing,
|
|
10
|
+
literal: :literal,
|
|
11
|
+
ulist: :list,
|
|
12
|
+
olist: :list,
|
|
13
|
+
table: :table,
|
|
14
|
+
admonition: :admonition,
|
|
15
|
+
example: :example,
|
|
16
|
+
quote: :quote,
|
|
17
|
+
sidebar: :sidebar,
|
|
18
|
+
pass: :pass,
|
|
19
|
+
open: :open,
|
|
20
|
+
text: :text,
|
|
21
|
+
link: :link,
|
|
22
|
+
strong: :strong,
|
|
23
|
+
emphasis: :emphasis,
|
|
24
|
+
monospace: :monospace
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def convert_node(node)
|
|
30
|
+
send(NODE_RENDERERS.fetch(node.context, :fallback), node)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def paragraph(node)
|
|
34
|
+
tag(paragraph_tag, render_text(node))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def literal(node)
|
|
38
|
+
tag(literal_tag, escape(node.text))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def pass(node)
|
|
42
|
+
node.text.to_s
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def open(node)
|
|
46
|
+
render_content(node)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def text(node)
|
|
50
|
+
escape(node.text)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def link(node)
|
|
54
|
+
tag(link_tag, render_text(node), link_attrs(node))
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def strong(node)
|
|
58
|
+
tag(strong_tag, render_text(node), strong_attrs)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def emphasis(node)
|
|
62
|
+
tag(emphasis_tag, render_text(node), emphasis_attrs)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def monospace(node)
|
|
66
|
+
tag(monospace_tag, escape(node.text), monospace_attrs)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def fallback(node)
|
|
70
|
+
render_text(node.text.to_s)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def title(node)
|
|
74
|
+
return "" unless node.attributes[:title]
|
|
75
|
+
|
|
76
|
+
tag(title_tag, render_text(node.attributes[:title]), title_attrs)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def strong_attrs
|
|
80
|
+
{}
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def emphasis_attrs
|
|
84
|
+
{}
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def monospace_attrs
|
|
88
|
+
{}
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|