Skip to content

Commit 48beddb

Browse files
authored
Merge pull request #59 from Timmmm/tags_sections
Add section tree output to the tags backend
2 parents 0f6a459 + 7a8b9a6 commit 48beddb

File tree

1 file changed

+58
-1
lines changed

1 file changed

+58
-1
lines changed

converters/tags.rb

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,26 @@
11
require 'json'
22

3+
# This is an Asciidoctor backend that allows extracting the content
4+
# from tagged snippets of text.
35
class TagsConverter
46
include Asciidoctor::Converter
57
register_for("tags")
68

9+
# Hash{String => String} - map from tag ID to its text contents.
710
@tag_map = {}
11+
# Array<String> - the stack of currently open sections in the
12+
# section tree. Each `Section` contains
13+
#
14+
# * title: String - Section title.
15+
# * id: String - Generated ID for the title which can be used for HTML links.
16+
# * children: Array<Section> - Child sections.
17+
# * tags: Array<String> - List of tags in this section directly (not in children).
18+
#
19+
# This always starts with a root section with an empty title and id.
20+
@section_stack = []
21+
22+
# Prefix on IDs that we require. We can't look at all IDs because
23+
# it includes a load of auto-generated ones.
824
@prefix = ""
925

1026
def initialize(backend, opts = {})
@@ -18,23 +34,64 @@ def initialize(backend, opts = {})
1834
# `node` is an `AbstractNode`.
1935
def convert(node, transform = node.node_name, opts = nil)
2036
if transform == "document" then
37+
# This is the top level node. First clear the outputs.
2138
@tag_map = {}
39+
# Root node of the section tree. For simplicity we always
40+
# have one root node with an empty title.
41+
@section_stack = [{
42+
"title" => "",
43+
"id" => "",
44+
"children" => [],
45+
"tags" => [],
46+
}]
47+
2248
# Calling node.content will recursively call convert() on all the nodes
2349
# and also expand blocks, creating inline nodes. We call this to convert
2450
# all nodes to text, and record their content in the tag map. Then we
2551
# throw away the text and output the tag map as JSON instead.
2652
node.content
53+
54+
# We must always add and remove an equal number of sections from the stack
55+
# and we started with one so should end with one.
56+
fail "Tags backend section logic error" if @section_stack.length != 1
57+
2758
JSON.pretty_generate({
2859
"tags": @tag_map,
60+
"sections": @section_stack.first,
2961
})
3062
else
31-
# Output the text content of this node.
63+
64+
# If it's a section add it to the section tree.
65+
if transform == "section" then
66+
section = {
67+
"title" => node.title,
68+
"id" => node.id,
69+
"children" => [],
70+
"tags" => [],
71+
}
72+
73+
@section_stack.last["children"] << section
74+
@section_stack << section
75+
end
76+
77+
# Recursively get the text content of this node.
3278
content = if node.inline? then node.text else node.content end
79+
80+
# Capture the content in the tag map and section tree if
81+
# this node is tagged appropriately.
3382
unless node.id.nil?
3483
if node.id.start_with?(@prefix)
3584
@tag_map[node.id] = content
85+
@section_stack.last["tags"] << node.id
3686
end
3787
end
88+
89+
# If it's a section, we've recursed through it (via `node.content`)
90+
# so pop it from the stack.
91+
if transform == "section" then
92+
@section_stack.pop()
93+
end
94+
3895
content
3996
end
4097
end

0 commit comments

Comments
 (0)