Skip to content

Commit

Permalink
Add support for recovering from missing top level header
Browse files Browse the repository at this point in the history
Signed-off-by: Jarno Elovirta <jarno@elovirta.com>
  • Loading branch information
jelovirt committed May 11, 2024
1 parent 53ca716 commit 98ee818
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 18 deletions.
46 changes: 33 additions & 13 deletions src/main/java/com/elovirta/dita/markdown/MarkdownParserImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -130,25 +130,43 @@ protected void validate(Document root) {
* If document doesn't start with H1, generate H1 from YAML metadata or file name.
*/
protected Document preprocess(Document root, URI input) throws SAXException {
if (DitaRenderer.WIKI.get(options) && isWiki(root)) {
generateRootHeading(root, input);
}
if (DitaRenderer.FIX_ROOT_HEADING.get(options) && isWiki(root)) {
if (errorHandler != null) {
errorHandler.warning(
new SAXParseException(MESSAGES.getString("error.missing_title"), null, input.toString(), 1, 1)
);
if (isWiki(root)) {
if (DitaRenderer.WIKI.get(options)) {
generateRootHeading(root, input);
} else if (DitaRenderer.FIX_ROOT_HEADING.get(options)) {
if (errorHandler != null) {
errorHandler.warning(
new SAXParseException(MESSAGES.getString("error.missing_title"), null, input.toString(), 1, 1)
);
}
generateRootHeading(root, input);
} else if (MarkdownReader.PROCESSING_MODE.get(options)) {
if (errorHandler != null) {
errorHandler.error(
new SAXParseException(MESSAGES.getString("error.missing_title"), null, input.toString(), 1, 1)
);
}
} else {
if (errorHandler != null) {
errorHandler.warning(
new SAXParseException(MESSAGES.getString("error.missing_title"), null, input.toString(), 1, 1)
);
}
generateRootHeading(root, null);
}
generateRootHeading(root, input);
}
return root;
}

/**
* Generate root heading using YAML header or input file name. If neither YAML or file name is not available, create empty heading.
*
*/
private void generateRootHeading(Document root, URI input) {
final YamlFrontMatterBlock yaml = root.getFirstChild() instanceof YamlFrontMatterBlock
? (YamlFrontMatterBlock) root.getFirstChild()
: null;
String title = getTextFromFile(input);
String title = input != null ? getTextFromFile(input) : null;
final Heading heading = new Heading();
if (yaml != null) {
final AbstractYamlFrontMatterVisitor v = new AbstractYamlFrontMatterVisitor();
Expand All @@ -170,9 +188,11 @@ private void generateRootHeading(Document root, URI input) {
}
}
heading.setLevel(1);
final AnchorLink anchorLink = new AnchorLink();
anchorLink.appendChild(new Text(title));
heading.appendChild(anchorLink);
if (title != null) {
final AnchorLink anchorLink = new AnchorLink();
anchorLink.appendChild(new Text(title));
heading.appendChild(anchorLink);
}
root.prependChild(heading);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class MarkdownReader implements XMLReader {
private static final ServiceLoader<SchemaProvider> schemaLoader = ServiceLoader.load(SchemaProvider.class);

public static final DataKey<Collection<String>> FORMATS = new DataKey<>("FORMATS", List.of("markdown", "md"));
/** Strict processing mode. */
public static final DataKey<Boolean> PROCESSING_MODE = new DataKey<>("PROCESSING_MODE", false);

/**
Expand Down
27 changes: 27 additions & 0 deletions src/test/java/com/elovirta/dita/markdown/MarkdownReaderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,20 @@
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Map;
import javax.xml.transform.Transformer;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXSource;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.opentest4j.AssertionFailedError;
import org.w3c.dom.Document;
import org.xml.sax.*;
import org.xml.sax.helpers.XMLFilterImpl;
import org.xmlunit.builder.DiffBuilder;
import org.xmlunit.diff.DefaultComparisonFormatter;
import org.xmlunit.diff.Diff;

public class MarkdownReaderTest extends AbstractReaderTest {

Expand Down Expand Up @@ -140,6 +148,25 @@ public void test_missingHeader(String file) throws Exception {
final TestErrorHandler errorHandler = new TestErrorHandler();
reader.setErrorHandler(errorHandler);

run(getSrc() + file, getExp() + "wiki/" + file.replaceAll("\\.md$", ".dita"));

assertEquals(1, errorHandler.warnings.size());
final SAXParseException e = errorHandler.warnings.get(0);
assertEquals("Document content doesn't start with heading", e.getMessage());
assertEquals("classpath:/markdown/" + file, e.getSystemId());
assertNull(e.getPublicId());
assertEquals(1, e.getLineNumber());
assertEquals(1, e.getColumnNumber());
}

@ParameterizedTest
@ValueSource(strings = { "missing_root_header.md", "missing_root_header_with_yaml.md" })
public void test_emptyHeader(String file) throws Exception {
reader =
new MarkdownReader(new MutableDataSet().set(Parser.EXTENSIONS, singletonList(YamlFrontMatterExtension.create())));
final TestErrorHandler errorHandler = new TestErrorHandler();
reader.setErrorHandler(errorHandler);

run(file);

assertEquals(1, errorHandler.warnings.size());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public void run(final String input) throws Exception {
run(getSrc() + input, getExp() + input.replaceAll("\\.(md|html)$", ".dita"));
}

void run(final String input, final String expFile) throws Exception {
protected void run(final String input, final String expFile) throws Exception {
final Document act;
try (final InputStream in = getClass().getResourceAsStream("/" + input)) {
act = db.newDocument();
Expand Down
4 changes: 2 additions & 2 deletions src/test/resources/dita/missing_root_header.dita
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<topic xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/" class="- topic/topic "
specializations="@props/audience @props/deliveryTarget @props/otherprops @props/platform @props/product"
id="missing-root-header" ditaarch:DITAArchVersion="2.0">
<title class="- topic/title ">missing root header</title>
id="" ditaarch:DITAArchVersion="2.0">
<title class="- topic/title "></title>
<body class="- topic/body ">
<p class="- topic/p ">Root topic content.</p>
</body>
Expand Down
4 changes: 2 additions & 2 deletions src/test/resources/dita/missing_root_header_with_yaml.dita
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<topic xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/" class="- topic/topic "
specializations="@props/audience @props/deliveryTarget @props/otherprops @props/platform @props/product"
id="yaml-title" ditaarch:DITAArchVersion="2.0">
<title class="- topic/title ">YAML Title</title>
id="" ditaarch:DITAArchVersion="2.0">
<title class="- topic/title "></title>
<body class="- topic/body ">
<p class="- topic/p ">Root topic content.</p>
</body>
Expand Down
16 changes: 16 additions & 0 deletions src/test/resources/dita/wiki/missing_root_header.dita
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<topic xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/" class="- topic/topic "
specializations="@props/audience @props/deliveryTarget @props/otherprops @props/platform @props/product"
id="missing-root-header" ditaarch:DITAArchVersion="2.0">
<title class="- topic/title ">missing root header</title>
<body class="- topic/body ">
<p class="- topic/p ">Root topic content.</p>
</body>
<topic class="- topic/topic "
specializations="@props/audience @props/deliveryTarget @props/otherprops @props/platform @props/product"
id="nested-topic" ditaarch:DITAArchVersion="2.0">
<title class="- topic/title ">Nested Topic</title>
<body class="- topic/body ">
<p class="- topic/p ">Nested topic content.</p>
</body>
</topic>
</topic>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<topic xmlns:ditaarch="http://dita.oasis-open.org/architecture/2005/" class="- topic/topic "
specializations="@props/audience @props/deliveryTarget @props/otherprops @props/platform @props/product"
id="yaml-title" ditaarch:DITAArchVersion="2.0">
<title class="- topic/title ">YAML Title</title>
<body class="- topic/body ">
<p class="- topic/p ">Root topic content.</p>
</body>
</topic>

0 comments on commit 98ee818

Please sign in to comment.