Skip to content

Commit 912de34

Browse files
authored
Refactor of AST traversal method (#944)
* Solve limitations in the current method used to traverse the AST. The new method does not look externally (outside of NodeProcessors) but instead injects NodeSinker into the NodeProcessors so each one decides if further traversal needs to happen. This has simplified the code notably, and removes the need for specific dependency injection. * Changes in how HTML content is generated: * Empty document no longer generated empty <h1></h1> * Empty literal no longer generated empty <pre></pre> * Sections are now wrapped around <div> elements for better organization.
1 parent 4bbd255 commit 912de34

34 files changed

+485
-430
lines changed

CHANGELOG.adoc

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ Improvements::
2323
* Added support for AsciidoctorJ v3.0.0 (#651)
2424
* Add compatibility with maven-site-plugin v3.20.0 and Doxia v2.0.0 (#933)
2525
* Add support for code blocks titles in asciidoctor-parser-doxia-module (#935)
26+
* Refactor AST traversal method in asciidoctor-parser-doxia-module (#944)
27+
* Empty titles in document or empty literals no longer generate <h1> or <pre> in asciidoctor-parser-doxia-module (#944)
28+
* Sections are now wrapped in <div> in asciidoctor-parser-doxia-module (#944)
2629

2730
Build / Infrastructure::
2831

asciidoctor-maven-commons/src/main/java/org/asciidoctor/maven/site/HeadParser.java

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
* This allows Doxia to build:
1010
* - breadcrumbs
1111
* - HTML head's meta elements
12+
*
13+
* @since 3.0.0
1214
*/
1315
public class HeadParser {
1416

asciidoctor-parser-doxia-module/src/main/java/org/asciidoctor/maven/site/parser/AsciidoctorAstDoxiaParser.java

+11-11
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.io.File;
66
import java.io.IOException;
77
import java.io.Reader;
8+
import java.util.List;
89
import java.util.logging.Logger;
910

1011
import org.apache.maven.doxia.parser.AbstractTextParser;
@@ -28,6 +29,7 @@
2829
import org.asciidoctor.maven.site.SiteConversionConfiguration;
2930
import org.asciidoctor.maven.site.SiteConversionConfigurationParser;
3031
import org.asciidoctor.maven.site.SiteLogHandlerDeserializer;
32+
import org.asciidoctor.maven.site.parser.processors.DescriptionListNodeProcessor;
3133
import org.codehaus.plexus.component.annotations.Component;
3234
import org.codehaus.plexus.util.IOUtil;
3335
import org.codehaus.plexus.util.xml.Xpp3Dom;
@@ -82,7 +84,7 @@ public void parse(Reader reader, Sink sink, String reference) throws ParseExcept
8284
final Asciidoctor asciidoctor = Asciidoctor.Factory.create();
8385

8486
SiteConversionConfiguration conversionConfig = new SiteConversionConfigurationParser(project)
85-
.processAsciiDocConfig(siteConfig, defaultOptions(siteDirectory), defaultAttributes());
87+
.processAsciiDocConfig(siteConfig, defaultOptions(siteDirectory), defaultAttributes());
8688
for (String require : conversionConfig.getRequires()) {
8789
requireLibrary(asciidoctor, require);
8890
}
@@ -98,7 +100,7 @@ public void parse(Reader reader, Sink sink, String reference) throws ParseExcept
98100
try {
99101
// process log messages according to mojo configuration
100102
new LogRecordsProcessors(logHandler, siteDirectory, errorMessage -> logger.error(errorMessage))
101-
.processLogRecords(memoryLogHandler);
103+
.processLogRecords(memoryLogHandler);
102104

103105
} catch (Exception exception) {
104106
throw new ParseException(exception.getMessage(), exception);
@@ -110,10 +112,8 @@ public void parse(Reader reader, Sink sink, String reference) throws ParseExcept
110112
new HeadParser(sink)
111113
.parse(headerMetadata);
112114

113-
sink.body();
114-
final NodesSinker nodesSinker = new NodesSinker(sink);
115-
nodesSinker.processNode(document);
116-
sink.body_();
115+
new NodeSinker(sink)
116+
.sink(document);
117117
}
118118

119119
private MemoryLogHandler asciidoctorLoggingSetup(Asciidoctor asciidoctor, LogHandler logHandler, File siteDirectory) {
@@ -148,15 +148,15 @@ protected File resolveSiteDirectory(MavenProject project, Xpp3Dom siteConfig) {
148148

149149
protected OptionsBuilder defaultOptions(File siteDirectory) {
150150
return Options.builder()
151-
.backend("xhtml")
152-
.safe(SafeMode.UNSAFE)
153-
.baseDir(new File(siteDirectory, ROLE_HINT));
151+
.backend("xhtml")
152+
.safe(SafeMode.UNSAFE)
153+
.baseDir(new File(siteDirectory, ROLE_HINT));
154154
}
155155

156156
protected AttributesBuilder defaultAttributes() {
157157
return Attributes.builder()
158-
.attribute("idprefix", "@")
159-
.attribute("showtitle", "@");
158+
.attribute("idprefix", "@")
159+
.attribute("showtitle", "@");
160160
}
161161

162162
private void requireLibrary(Asciidoctor asciidoctor, String require) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package org.asciidoctor.maven.site.parser;
2+
3+
import java.util.Arrays;
4+
import java.util.List;
5+
6+
import org.apache.maven.doxia.sink.Sink;
7+
import org.asciidoctor.ast.StructuralNode;
8+
import org.asciidoctor.maven.site.parser.processors.DescriptionListNodeProcessor;
9+
import org.asciidoctor.maven.site.parser.processors.DocumentNodeProcessor;
10+
import org.asciidoctor.maven.site.parser.processors.ImageNodeProcessor;
11+
import org.asciidoctor.maven.site.parser.processors.ListItemNodeProcessor;
12+
import org.asciidoctor.maven.site.parser.processors.ListingNodeProcessor;
13+
import org.asciidoctor.maven.site.parser.processors.LiteralNodeProcessor;
14+
import org.asciidoctor.maven.site.parser.processors.NoOpNodeProcessor;
15+
import org.asciidoctor.maven.site.parser.processors.OrderedListNodeProcessor;
16+
import org.asciidoctor.maven.site.parser.processors.ParagraphNodeProcessor;
17+
import org.asciidoctor.maven.site.parser.processors.PreambleNodeProcessor;
18+
import org.asciidoctor.maven.site.parser.processors.SectionNodeProcessor;
19+
import org.asciidoctor.maven.site.parser.processors.TableNodeProcessor;
20+
import org.asciidoctor.maven.site.parser.processors.UnorderedListNodeProcessor;
21+
22+
/**
23+
* Factory and repository for NodeProcessors.
24+
*
25+
* @author abelsromero
26+
* @since 3.1.0
27+
*/
28+
public class NodeSinker {
29+
30+
private final List<NodeProcessor> nodeProcessors;
31+
32+
private final NodeProcessor noOpProcessor;
33+
34+
public NodeSinker(Sink sink) {
35+
nodeProcessors = Arrays.asList(
36+
new DescriptionListNodeProcessor(sink, this),
37+
new DocumentNodeProcessor(sink, this),
38+
new ImageNodeProcessor(sink, this),
39+
new ListItemNodeProcessor(sink, this),
40+
new ListingNodeProcessor(sink, this),
41+
new ListingNodeProcessor(sink, this),
42+
new LiteralNodeProcessor(sink, this),
43+
new OrderedListNodeProcessor(sink, this),
44+
new ParagraphNodeProcessor(sink, this),
45+
new PreambleNodeProcessor(sink, this),
46+
new SectionNodeProcessor(sink, this),
47+
new TableNodeProcessor(sink, this),
48+
new UnorderedListNodeProcessor(sink, this)
49+
);
50+
noOpProcessor = new NoOpNodeProcessor(sink, this);
51+
}
52+
53+
/**
54+
* Returns first NodeProcessor that can treat the node.
55+
**/
56+
private NodeProcessor get(StructuralNode node) {
57+
return nodeProcessors.stream()
58+
.filter(nodeProcessor -> nodeProcessor.applies(node))
59+
.findFirst()
60+
.orElse(noOpProcessor);
61+
}
62+
63+
public void sink(StructuralNode node) {
64+
get(node).process(node);
65+
}
66+
}

asciidoctor-parser-doxia-module/src/main/java/org/asciidoctor/maven/site/parser/NodesSinker.java

-99
This file was deleted.

asciidoctor-parser-doxia-module/src/main/java/org/asciidoctor/maven/site/parser/processors/AbstractSinkNodeProcessor.java

+17-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import org.apache.maven.doxia.sink.Sink;
44
import org.asciidoctor.ast.ContentNode;
5+
import org.asciidoctor.ast.StructuralNode;
6+
import org.asciidoctor.maven.site.parser.NodeSinker;
57

68
/**
79
* Recommended base case to build a {@link org.asciidoctor.maven.site.parser.NodeProcessor}.
@@ -12,14 +14,17 @@
1214
public class AbstractSinkNodeProcessor {
1315

1416
private final Sink sink;
17+
private final NodeSinker nodeSinker;
1518

1619
/**
1720
* Constructor.
1821
*
19-
* @param sink Doxia {@link Sink}
22+
* @param sink Doxia {@link Sink}
23+
* @param nodeSinker
2024
*/
21-
public AbstractSinkNodeProcessor(Sink sink) {
25+
public AbstractSinkNodeProcessor(Sink sink, NodeSinker nodeSinker) {
2226
this.sink = sink;
27+
this.nodeSinker = nodeSinker;
2328
}
2429

2530
/**
@@ -31,6 +36,16 @@ protected Sink getSink() {
3136
return sink;
3237
}
3338

39+
/**
40+
* Delegates the processing of the new node to the appropriate processor.
41+
* Similar to {@link org.asciidoctor.maven.site.parser.NodeProcessor#process(StructuralNode)}
42+
* but this selects the processor from the ones available.
43+
*
44+
* @param node Node to process
45+
*/
46+
protected void sink(StructuralNode node) {
47+
nodeSinker.sink(node);
48+
}
3449

3550
/**
3651
* Tests for the presence of an attribute in current and parent nodes.

asciidoctor-parser-doxia-module/src/main/java/org/asciidoctor/maven/site/parser/processors/DescriptionListNodeProcessor.java

+6-15
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import org.asciidoctor.ast.ListItem;
99
import org.asciidoctor.ast.StructuralNode;
1010
import org.asciidoctor.maven.site.parser.NodeProcessor;
11+
import org.asciidoctor.maven.site.parser.NodeSinker;
1112

1213
/**
1314
* Description list processor.
@@ -17,24 +18,14 @@
1718
*/
1819
public class DescriptionListNodeProcessor extends AbstractSinkNodeProcessor implements NodeProcessor {
1920

20-
private ListItemNodeProcessor itemNodeProcessor;
21-
2221
/**
2322
* Constructor.
2423
*
25-
* @param sink Doxia {@link Sink}
26-
*/
27-
public DescriptionListNodeProcessor(Sink sink) {
28-
super(sink);
29-
}
30-
31-
/**
32-
* Inject a {@link ListItemNodeProcessor}.
33-
*
34-
* @param nodeProcessor {@link ListItemNodeProcessor}
24+
* @param sink Doxia {@link Sink}
25+
* @param nodeSinker
3526
*/
36-
public void setItemNodeProcessor(ListItemNodeProcessor nodeProcessor) {
37-
this.itemNodeProcessor = nodeProcessor;
27+
public DescriptionListNodeProcessor(Sink sink, NodeSinker nodeSinker) {
28+
super(sink, nodeSinker);
3829
}
3930

4031
@Override
@@ -67,7 +58,7 @@ public void process(StructuralNode node) {
6758
if (description.getBlocks().isEmpty()) {
6859
sink.rawText(description.getText());
6960
} else {
70-
itemNodeProcessor.process(description);
61+
super.sink(description);
7162
}
7263
sink.definition_();
7364
}

asciidoctor-parser-doxia-module/src/main/java/org/asciidoctor/maven/site/parser/processors/DocumentNodeProcessor.java

+18-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
import org.apache.maven.doxia.sink.Sink;
44
import org.asciidoctor.ast.StructuralNode;
55
import org.asciidoctor.maven.site.parser.NodeProcessor;
6+
import org.asciidoctor.maven.site.parser.NodeSinker;
7+
8+
import static org.asciidoctor.maven.commons.StringUtils.isNotBlank;
69

710
/**
811
* Root document processor.
@@ -17,8 +20,8 @@ public class DocumentNodeProcessor extends AbstractSinkNodeProcessor implements
1720
*
1821
* @param sink Doxia {@link Sink}
1922
*/
20-
public DocumentNodeProcessor(Sink sink) {
21-
super(sink);
23+
public DocumentNodeProcessor(Sink sink, NodeSinker nodeSinker) {
24+
super(sink, nodeSinker);
2225
}
2326

2427
@Override
@@ -28,7 +31,18 @@ public boolean applies(StructuralNode node) {
2831

2932
@Override
3033
public void process(StructuralNode node) {
31-
// NOTE: H1 generation fixed in doxia 2.0.0-MX
32-
getSink().rawText(String.format("<h1>%s</h1>", node.getTitle()));
34+
final Sink sink = getSink();
35+
36+
sink.body();
37+
String title = node.getTitle();
38+
if (isNotBlank(title)) {
39+
sink.sectionTitle1();
40+
sink.rawText(title);
41+
sink.sectionTitle1_();
42+
}
43+
node.getBlocks()
44+
.forEach(this::sink);
45+
46+
sink.body_();
3347
}
3448
}

0 commit comments

Comments
 (0)