You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by mi...@apache.org on 2021/01/02 21:35:17 UTC
[maven-doxia] branch master updated: [DOXIA-616] Markdown: Properly
expose the language specified in fenced code blocks
This is an automated email from the ASF dual-hosted git repository.
michaelo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-doxia.git
The following commit(s) were added to refs/heads/master by this push:
new b55285c [DOXIA-616] Markdown: Properly expose the language specified in fenced code blocks
b55285c is described below
commit b55285cada6195ca227a21da0168462addbac6de
Author: Bertrand Martin <be...@sentrysoftware.com>
AuthorDate: Tue Dec 29 01:15:20 2020 +0100
[DOXIA-616] Markdown: Properly expose the language specified in fenced code blocks
To properly implement this change the following task had to be performed:
* Properly expose language class in fenced code blocks
* Re-implemente metadata processing
* Add unit tests
* Add integration tests (with maven-site-plugin)
* Fix *XhtmlBaseParser* and *XhtmlBaseSink* to properly expose attributes of the PRE and CODE elements
* Fix *AbstractModuleTest* to use UTF-8 for input files
* Remove Pegdown emulation profile and embrace CommonMark
This closes #49
---
.../apache/maven/doxia/parser/XhtmlBaseParser.java | 3 +-
.../maven/doxia/sink/impl/Xhtml5BaseSink.java | 4 +-
.../maven/doxia/sink/impl/XhtmlBaseSink.java | 4 +-
.../org/apache/maven/doxia/AbstractModuleTest.java | 3 +-
doxia-modules/doxia-module-markdown/pom.xml | 75 +++++++
.../src/it/DOXIA-616-fenced-code-block/pom.xml | 69 ++++++
.../src/site/markdown/fenced-code-block.md | 26 +++
.../DOXIA-616-fenced-code-block/src/site/site.xml | 37 ++++
.../it/DOXIA-616-fenced-code-block/verify.groovy | 43 ++++
.../doxia-module-markdown/src/it/general/pom.xml | 69 ++++++
.../src/it/general/src/site/markdown/index.md | 5 +
.../src/it/general/src/site/markdown/metadata.md | 11 +
.../src/it/general/src/site/site.xml | 35 +++
.../src/it/general/verify.groovy | 55 +++++
.../doxia-module-markdown/src/it/settings.xml | 55 +++++
.../module/markdown/FlexmarkDoxiaExtension.java | 58 -----
.../module/markdown/FlexmarkDoxiaNodeRenderer.java | 146 -------------
.../doxia/module/markdown/MarkdownParser.java | 237 ++++++++++++---------
.../doxia/module/markdown/MarkdownParserTest.java | 70 +++++-
.../src/test/resources/fenced-code-block.md | 5 +
.../src/test/resources/first-heading.md | 2 +-
.../src/test/resources/metadata.md | 13 +-
.../maven/doxia/module/xhtml/XhtmlParser.java | 2 +-
pom.xml | 16 ++
24 files changed, 715 insertions(+), 328 deletions(-)
diff --git a/doxia-core/src/main/java/org/apache/maven/doxia/parser/XhtmlBaseParser.java b/doxia-core/src/main/java/org/apache/maven/doxia/parser/XhtmlBaseParser.java
index 36b1024..57049e3 100644
--- a/doxia-core/src/main/java/org/apache/maven/doxia/parser/XhtmlBaseParser.java
+++ b/doxia-core/src/main/java/org/apache/maven/doxia/parser/XhtmlBaseParser.java
@@ -509,7 +509,8 @@ public class XhtmlBaseParser
|| ( parser.getName().equals( HtmlMarkup.SAMP.toString() ) )
|| ( parser.getName().equals( HtmlMarkup.TT.toString() ) ) )
{
- sink.inline( SinkEventAttributeSet.Semantics.CODE );
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.CODE );
+ sink.inline( attribs );
}
else if ( parser.getName().equals( HtmlMarkup.A.toString() ) )
{
diff --git a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSink.java b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSink.java
index 96d86a0..2f0d9bc 100644
--- a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSink.java
+++ b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSink.java
@@ -1905,7 +1905,9 @@ public class Xhtml5BaseSink
{
if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, semantic ) )
{
- writeStartTag( tag );
+ SinkEventAttributes attributesNoSemantics = ( SinkEventAttributes ) attributes.copyAttributes();
+ attributesNoSemantics.removeAttribute( SinkEventAttributes.SEMANTICS );
+ writeStartTag( tag, attributesNoSemantics );
tags.add( 0, tag );
}
}
diff --git a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/XhtmlBaseSink.java b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/XhtmlBaseSink.java
index c4a5aa5..6cb76e1 100644
--- a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/XhtmlBaseSink.java
+++ b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/XhtmlBaseSink.java
@@ -1782,7 +1782,9 @@ public class XhtmlBaseSink
{
if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, semantic ) )
{
- writeStartTag( tag );
+ SinkEventAttributes attributesNoSemantics = ( SinkEventAttributes ) attributes.copyAttributes();
+ attributesNoSemantics.removeAttribute( SinkEventAttributes.SEMANTICS );
+ writeStartTag( tag, attributesNoSemantics );
tags.add( 0, tag );
}
}
diff --git a/doxia-core/src/test/java/org/apache/maven/doxia/AbstractModuleTest.java b/doxia-core/src/test/java/org/apache/maven/doxia/AbstractModuleTest.java
index 3a1ec80..79249a5 100644
--- a/doxia-core/src/test/java/org/apache/maven/doxia/AbstractModuleTest.java
+++ b/doxia-core/src/test/java/org/apache/maven/doxia/AbstractModuleTest.java
@@ -30,6 +30,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.Writer;
+import java.nio.charset.StandardCharsets;
/**
* Provide some common convenience methods to test Doxia modules (parsers and sinks).
@@ -172,7 +173,7 @@ public abstract class AbstractModuleTest
assertNotNull( "Could not find resource: " + baseName + "." + extension, is );
- return new InputStreamReader( is );
+ return new InputStreamReader( is, StandardCharsets.UTF_8 );
}
/**
diff --git a/doxia-modules/doxia-module-markdown/pom.xml b/doxia-modules/doxia-module-markdown/pom.xml
index 29bbac4..c72083b 100644
--- a/doxia-modules/doxia-module-markdown/pom.xml
+++ b/doxia-modules/doxia-module-markdown/pom.xml
@@ -72,5 +72,80 @@ under the License.
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
</dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ </dependency>
</dependencies>
+ <build>
+
+ <plugins>
+
+ <!-- install -->
+ <plugin>
+ <artifactId>maven-install-plugin</artifactId>
+ <executions>
+
+ <!-- integration-test -->
+ <!-- Copy the Doxia XHTML module from our working directory to the local-repo -->
+ <!-- We do that manually because the invoker:install goal (below) doesn't do it, as -->
+ <!-- it's not the artifact we're working on, but the ones that are produced by our "siblings" -->
+ <execution>
+ <id>copy-doxia-module-xhtml-to-local-repo</id>
+ <phase>integration-test</phase>
+ <goals>
+ <goal>install-file</goal>
+ </goals>
+ <configuration>
+ <localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath>
+ <file>${project.basedir}/../doxia-module-xhtml/target/doxia-module-xhtml-${project.version}.jar</file>
+ </configuration>
+ </execution>
+ <execution>
+ <id>copy-doxia-to-local-repo</id>
+ <phase>integration-test</phase>
+ <goals>
+ <goal>install-file</goal>
+ </goals>
+ <configuration>
+ <localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath>
+ <file>${project.basedir}/../../doxia-core/target/doxia-core-${project.version}.jar</file>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- maven-invoker-plugin -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <!-- <version>2.0.0</version> -->
+ <configuration>
+ <debug>false</debug>
+ <cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
+ <pomIncludes>
+ <pomInclude>**/pom.xml</pomInclude>
+ </pomIncludes>
+ <postBuildHookScript>verify</postBuildHookScript>
+ <localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath>
+ <extraArtifacts></extraArtifacts>
+ <settingsFile>src/it/settings.xml</settingsFile>
+ <goals>
+ <goal>clean</goal>
+ <goal>site</goal>
+ </goals>
+ </configuration>
+ <executions>
+ <execution>
+ <id>integration-test</id>
+ <goals>
+ <goal>install</goal>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
</project>
diff --git a/doxia-modules/doxia-module-markdown/src/it/DOXIA-616-fenced-code-block/pom.xml b/doxia-modules/doxia-module-markdown/src/it/DOXIA-616-fenced-code-block/pom.xml
new file mode 100644
index 0000000..12afb4f
--- /dev/null
+++ b/doxia-modules/doxia-module-markdown/src/it/DOXIA-616-fenced-code-block/pom.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.maven.doxia</groupId>
+ <artifactId>it</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <description>Project Description</description>
+
+ <build>
+ <plugins>
+
+ <!-- site -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-site-plugin</artifactId>
+ <version>3.9.1</version>
+ <configuration>
+ <generateReports>false</generateReports>
+ <generateProjectInfo>false</generateProjectInfo>
+ <inputEncoding>UTF-8</inputEncoding>
+ <outputEncoding>UTF-8</outputEncoding>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven.doxia</groupId>
+ <artifactId>doxia-core</artifactId>
+ <version>@project.version@</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.doxia</groupId>
+ <artifactId>doxia-module-xhtml</artifactId>
+ <version>@project.version@</version>
+ </dependency>
+ <dependency>
+ <groupId>@project.groupId@</groupId>
+ <artifactId>@project.artifactId@</artifactId>
+ <version>@project.version@</version>
+ </dependency>
+ </dependencies>
+
+ </plugin>
+
+ </plugins>
+ </build>
+
+</project>
diff --git a/doxia-modules/doxia-module-markdown/src/it/DOXIA-616-fenced-code-block/src/site/markdown/fenced-code-block.md b/doxia-modules/doxia-module-markdown/src/it/DOXIA-616-fenced-code-block/src/site/markdown/fenced-code-block.md
new file mode 100644
index 0000000..3f4da06
--- /dev/null
+++ b/doxia-modules/doxia-module-markdown/src/it/DOXIA-616-fenced-code-block/src/site/markdown/fenced-code-block.md
@@ -0,0 +1,26 @@
+author: Bertrand Martin
+
+# Fenced Code Block
+
+This is Java code and must be tagged so such.
+
+```java
+// Fenced Code Block 1
+System.out.println("Hello, Fenced Code Block!");
+```
+
+This is non-specified code:
+
+```
+# Fenced Code Block 2
+ch = fopen("/tmp/test.log", "r");
+```
+
+This is similar to indented block:
+
+ // Indented Code Block
+ System.out.println("Hello, Indented Block");
+
+And it is also different from the inline code: `System.out.println("Hello, Inline Code");`, which remains simple.
+
+And what about ```System.out.println("Inline fenced code");```?
\ No newline at end of file
diff --git a/doxia-modules/doxia-module-markdown/src/it/DOXIA-616-fenced-code-block/src/site/site.xml b/doxia-modules/doxia-module-markdown/src/it/DOXIA-616-fenced-code-block/src/site/site.xml
new file mode 100644
index 0000000..ebc6ae2
--- /dev/null
+++ b/doxia-modules/doxia-module-markdown/src/it/DOXIA-616-fenced-code-block/src/site/site.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project name="${project.name} from site.xml">
+
+ <skin>
+ <groupId>org.apache.maven.skins</groupId>
+ <artifactId>maven-fluido-skin</artifactId>
+ <version>1.9</version>
+ </skin>
+
+ <body>
+
+ <menu name="Testing">
+ <item name="Fenced Code Block" href="fenced-code-block.html" />
+ </menu>
+
+ </body>
+</project>
diff --git a/doxia-modules/doxia-module-markdown/src/it/DOXIA-616-fenced-code-block/verify.groovy b/doxia-modules/doxia-module-markdown/src/it/DOXIA-616-fenced-code-block/verify.groovy
new file mode 100644
index 0000000..b52ff05
--- /dev/null
+++ b/doxia-modules/doxia-module-markdown/src/it/DOXIA-616-fenced-code-block/verify.groovy
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+ // Verify fenced-code-block.html
+
+// File was produced
+File resultFile = new File(basedir, "target/site/fenced-code-block.html")
+assert resultFile.isFile()
+
+// Check the content
+String content = resultFile.text;
+
+// Our first fenced code block is <div class="source"><pre><code class="language-java">...</code></pre></div>
+assert content =~ '<div class="source">.*<pre.*>.*<code.*class=".*language-java.*">.*// Fenced Code Block 1'
+
+// Our second fenced code block doesn't specify a language
+assert content =~ '<div class="source">.*<pre.*>.*<code.*># Fenced Code Block 2'
+assert !(content =~ '<div class="source">.*<pre.*>.*<code.*language-.*># Fenced Code Block 2')
+
+// Our third code block is indented, and it shows the same way
+assert content =~ '<div class="source">.*<pre.*>.*<code.*>// Indented Code Block'
+
+// Then we have inline code, which must be in simple <code>
+assert content =~ 'inline code: <code>System.out.println'
+
+// The last one is inline "fenced" code block which must be in simple <code>
+assert content =~ 'And what about <code>System.out.println'
diff --git a/doxia-modules/doxia-module-markdown/src/it/general/pom.xml b/doxia-modules/doxia-module-markdown/src/it/general/pom.xml
new file mode 100644
index 0000000..12afb4f
--- /dev/null
+++ b/doxia-modules/doxia-module-markdown/src/it/general/pom.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.maven.doxia</groupId>
+ <artifactId>it</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <description>Project Description</description>
+
+ <build>
+ <plugins>
+
+ <!-- site -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-site-plugin</artifactId>
+ <version>3.9.1</version>
+ <configuration>
+ <generateReports>false</generateReports>
+ <generateProjectInfo>false</generateProjectInfo>
+ <inputEncoding>UTF-8</inputEncoding>
+ <outputEncoding>UTF-8</outputEncoding>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven.doxia</groupId>
+ <artifactId>doxia-core</artifactId>
+ <version>@project.version@</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.doxia</groupId>
+ <artifactId>doxia-module-xhtml</artifactId>
+ <version>@project.version@</version>
+ </dependency>
+ <dependency>
+ <groupId>@project.groupId@</groupId>
+ <artifactId>@project.artifactId@</artifactId>
+ <version>@project.version@</version>
+ </dependency>
+ </dependencies>
+
+ </plugin>
+
+ </plugins>
+ </build>
+
+</project>
diff --git a/doxia-modules/doxia-module-markdown/src/it/general/src/site/markdown/index.md b/doxia-modules/doxia-module-markdown/src/it/general/src/site/markdown/index.md
new file mode 100644
index 0000000..f509994
--- /dev/null
+++ b/doxia-modules/doxia-module-markdown/src/it/general/src/site/markdown/index.md
@@ -0,0 +1,5 @@
+# General Integration Tests for Doxia Markdown Module
+
+Each page is dedicated to one specific feature of the Doxia Markdown Module.
+
+Everything is tested in **verify.groovy**.
\ No newline at end of file
diff --git a/doxia-modules/doxia-module-markdown/src/it/general/src/site/markdown/metadata.md b/doxia-modules/doxia-module-markdown/src/it/general/src/site/markdown/metadata.md
new file mode 100644
index 0000000..de13a27
--- /dev/null
+++ b/doxia-modules/doxia-module-markdown/src/it/general/src/site/markdown/metadata.md
@@ -0,0 +1,11 @@
+Author: Bertrand 'Yours, Truly' Martin
+Title: Title from Header
+Keywords: smile,😉,utf-8
+Empty:
+
+ Weird : Spacing
+
+
+# Title from Title
+
+description: This description must not be included in the header
diff --git a/doxia-modules/doxia-module-markdown/src/it/general/src/site/site.xml b/doxia-modules/doxia-module-markdown/src/it/general/src/site/site.xml
new file mode 100644
index 0000000..02c04e7
--- /dev/null
+++ b/doxia-modules/doxia-module-markdown/src/it/general/src/site/site.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project name="${project.name} from site.xml">
+
+ <body>
+
+ <menu name="Getting Started">
+ <item name="Overview" href="index.html" />
+ </menu>
+
+ <menu name="Testing">
+ <item name="Metadata" href="metadata.html" />
+ </menu>
+
+ </body>
+</project>
diff --git a/doxia-modules/doxia-module-markdown/src/it/general/verify.groovy b/doxia-modules/doxia-module-markdown/src/it/general/verify.groovy
new file mode 100644
index 0000000..6c7d71b
--- /dev/null
+++ b/doxia-modules/doxia-module-markdown/src/it/general/verify.groovy
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+// Verify index.html
+
+// File was produced
+File resultFile = new File(basedir, "target/site/index.html")
+assert resultFile.isFile()
+
+
+// Verify metadata.html
+
+// File was produced
+resultFile = new File(basedir, "target/site/metadata.html")
+assert resultFile.isFile()
+
+// Check the content
+String content = resultFile.text;
+
+// <title> must contain the specified title in the metadata, not in the first heading
+assert content =~ '<title>.*Title from Header.*</title>'
+
+// Author is Bertrand, yours truly
+// Apostrophe must have been interpreted properly
+assert content =~ '<meta name="Author" content="Bertrand \'Yours, Truly\' Martin" />'
+
+// Keywords do support utf-8 smileys
+assert content =~ '<meta name="Keywords" content="smile,😉,utf-8" />'
+
+// Meta are properly trimmed
+assert content =~ '<meta name="Weird" content="Spacing" />'
+
+// Empty is empty
+assert content =~ '<meta name="Empty" content="" />'
+
+// No description is provided, as it was not part of the metadata at the beginning of the doc
+assert !(content =~ '<meta name="description"')
+
diff --git a/doxia-modules/doxia-module-markdown/src/it/settings.xml b/doxia-modules/doxia-module-markdown/src/it/settings.xml
new file mode 100644
index 0000000..a163718
--- /dev/null
+++ b/doxia-modules/doxia-module-markdown/src/it/settings.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<settings>
+ <profiles>
+ <profile>
+ <id>it-repo</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <repositories>
+ <repository>
+ <id>1local.central</id>
+ <url>@localRepositoryUrl@</url>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </repository>
+ </repositories>
+ <pluginRepositories>
+ <pluginRepository>
+ <id>1local.central</id>
+ <url>@localRepositoryUrl@</url>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </pluginRepository>
+ </pluginRepositories>
+ </profile>
+ </profiles>
+</settings>
diff --git a/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/FlexmarkDoxiaExtension.java b/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/FlexmarkDoxiaExtension.java
deleted file mode 100644
index f020d45..0000000
--- a/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/FlexmarkDoxiaExtension.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package org.apache.maven.doxia.module.markdown;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import com.vladsch.flexmark.html.HtmlRenderer;
-import com.vladsch.flexmark.util.builder.Extension;
-import com.vladsch.flexmark.util.options.DataKey;
-import com.vladsch.flexmark.util.options.MutableDataHolder;
-
-/**
- * Implements flexmark-java extension to render fenced code and indented code using doxia format
- */
-class FlexmarkDoxiaExtension implements HtmlRenderer.HtmlRendererExtension
-{
- /** Constant <code>INPUT_FILE_EXTENSION</code> */
- public static final DataKey<String> INPUT_FILE_EXTENSION = new DataKey<>( "INPUT_FILE_EXTENSION", "md" );
-
- /** {@inheritDoc} */
- @Override
- public void rendererOptions( final MutableDataHolder options )
- {
-
- }
-
- /** {@inheritDoc} */
- @Override
- public void extend( HtmlRenderer.Builder rendererBuilder, String rendererType )
- {
- rendererBuilder.nodeRendererFactory( new FlexmarkDoxiaNodeRenderer.Factory() );
- }
-
- /**
- * <p>create.</p>
- *
- * @return a {@link com.vladsch.flexmark.util.builder.Extension} object.
- */
- public static Extension create()
- {
- return new FlexmarkDoxiaExtension();
- }
-}
diff --git a/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/FlexmarkDoxiaNodeRenderer.java b/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/FlexmarkDoxiaNodeRenderer.java
deleted file mode 100644
index dadf24b..0000000
--- a/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/FlexmarkDoxiaNodeRenderer.java
+++ /dev/null
@@ -1,146 +0,0 @@
-package org.apache.maven.doxia.module.markdown;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import com.vladsch.flexmark.ast.FencedCodeBlock;
-import com.vladsch.flexmark.ast.IndentedCodeBlock;
-import com.vladsch.flexmark.html.CustomNodeRenderer;
-import com.vladsch.flexmark.html.HtmlWriter;
-import com.vladsch.flexmark.html.renderer.NodeRenderer;
-import com.vladsch.flexmark.html.renderer.NodeRendererContext;
-import com.vladsch.flexmark.html.renderer.NodeRendererFactory;
-import com.vladsch.flexmark.html.renderer.NodeRenderingHandler;
-import com.vladsch.flexmark.util.options.DataHolder;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * The node renderer that renders all the core nodes (comes last in the order of node renderers).
- */
-@SuppressWarnings( "WeakerAccess" )
-class FlexmarkDoxiaNodeRenderer implements NodeRenderer
-{
- FlexmarkDoxiaNodeRenderer( DataHolder options )
- {
- }
-
- /** {@inheritDoc} */
- @Override
- public Set<NodeRenderingHandler<?>> getNodeRenderingHandlers()
- {
- return new HashSet<NodeRenderingHandler<?>>( Arrays.asList(
- new NodeRenderingHandler<>( IndentedCodeBlock.class, new CustomNodeRenderer<IndentedCodeBlock>()
- {
- @Override
- public void render( IndentedCodeBlock node, NodeRendererContext context, HtmlWriter html )
- {
- FlexmarkDoxiaNodeRenderer.this.render( node, context, html );
- }
- } ),
- new NodeRenderingHandler<>( FencedCodeBlock.class, new CustomNodeRenderer<FencedCodeBlock>()
- {
- @Override
- public void render( FencedCodeBlock node, NodeRendererContext context, HtmlWriter html )
- {
- FlexmarkDoxiaNodeRenderer.this.render( node, context, html );
- }
- } )
- ) );
- }
-
- private void render( IndentedCodeBlock node, NodeRendererContext context, HtmlWriter html )
- {
- html.line();
- html.attr( "class", "source" ).withAttr().tag( "div" );
- html.srcPosWithEOL( node.getChars() ).tag( "pre" ).openPre();
-
- String noLanguageClass = context.getHtmlOptions().noLanguageClass.trim();
- if ( !noLanguageClass.isEmpty() )
- {
- html.attr( "class", noLanguageClass );
- }
-
- //html.srcPosWithEOL(node.getContentChars()).withAttr(CoreNodeRenderer.CODE_CONTENT).tag("code");
- String s = node.getContentChars().trimTailBlankLines().normalizeEndWithEOL();
- while ( !s.isEmpty() && s.charAt( 0 ) == '\n' )
- {
- html.raw( "<br/>" );
- s = s.substring( 1 );
- }
- html.text( s );
-
- //html.tag("/code");
- html.tag( "/pre" ).closePre();
- html.tag( "/div" );
- html.line();
- }
-
- private void render( FencedCodeBlock node, NodeRendererContext context, HtmlWriter html )
- {
- html.line();
- html.attr( "class", "source" ).withAttr().tag( "div" );
- html.srcPosWithTrailingEOL( node.getChars() ).tag( "pre" ).openPre();
-
- //BasedSequence info = node.getInfo();
- //if (info.isNotNull() && !info.isBlank()) {
- // int space = info.indexOf(' ');
- // BasedSequence language;
- // if (space == -1) {
- // language = info;
- // } else {
- // language = info.subSequence(0, space);
- // }
- // html.attr("class", context.getHtmlOptions().languageClassPrefix + language.unescape());
- //} else {
- // String noLanguageClass = context.getHtmlOptions().noLanguageClass.trim();
- // if (!noLanguageClass.isEmpty()) {
- // html.attr("class", noLanguageClass);
- // }
- //}
-
- //html.srcPosWithEOL(node.getContentChars()).withAttr(CoreNodeRenderer.CODE_CONTENT).tag("code");
- String s = node.getContentChars().normalizeEOL();
- while ( !s.isEmpty() && s.charAt( 0 ) == '\n' )
- {
- html.raw( "<br/>" );
- s = s.substring( 1 );
- }
- html.text( s );
-
- //html.tag("/code");
- html.tag( "/pre" ).closePre();
- html.tag( "/div" );
- html.line();
- }
-
- /**
- * Factory for doxia node renderer
- */
- public static class Factory implements NodeRendererFactory
- {
- @Override
- public NodeRenderer create( final DataHolder options )
- {
- return new FlexmarkDoxiaNodeRenderer( options );
- }
- }
-}
diff --git a/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownParser.java b/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownParser.java
index f40e123..1728d3e 100644
--- a/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownParser.java
+++ b/doxia-modules/doxia-module-markdown/src/main/java/org/apache/maven/doxia/module/markdown/MarkdownParser.java
@@ -24,18 +24,24 @@ import com.vladsch.flexmark.ast.HtmlCommentBlock;
import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.ast.util.TextCollectingVisitor;
import com.vladsch.flexmark.html.HtmlRenderer;
-import com.vladsch.flexmark.profiles.pegdown.Extensions;
-import com.vladsch.flexmark.profiles.pegdown.PegdownOptionsAdapter;
-import com.vladsch.flexmark.util.builder.Extension;
-import com.vladsch.flexmark.util.options.MutableDataHolder;
-import org.apache.commons.lang3.StringEscapeUtils;
-import org.apache.commons.lang3.StringUtils;
+import com.vladsch.flexmark.util.options.MutableDataSet;
+import com.vladsch.flexmark.ext.escaped.character.EscapedCharacterExtension;
+import com.vladsch.flexmark.ext.abbreviation.AbbreviationExtension;
+import com.vladsch.flexmark.ext.autolink.AutolinkExtension;
+import com.vladsch.flexmark.ext.definition.DefinitionExtension;
+import com.vladsch.flexmark.ext.typographic.TypographicExtension;
+import com.vladsch.flexmark.ext.tables.TablesExtension;
+import com.vladsch.flexmark.ext.wikilink.WikiLinkExtension;
+import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension;
+
+import org.apache.commons.io.input.CharSequenceReader;
import org.apache.maven.doxia.markup.HtmlMarkup;
import org.apache.maven.doxia.module.xhtml.XhtmlParser;
import org.apache.maven.doxia.parser.AbstractParser;
import org.apache.maven.doxia.parser.ParseException;
import org.apache.maven.doxia.parser.Parser;
import org.apache.maven.doxia.sink.Sink;
+import org.apache.maven.doxia.util.HtmlTools;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.util.IOUtil;
@@ -43,8 +49,7 @@ import org.codehaus.plexus.util.xml.pull.XmlPullParser;
import java.io.IOException;
import java.io.Reader;
-import java.io.StringReader;
-import java.util.ArrayList;
+import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -74,48 +79,97 @@ public class MarkdownParser
/**
* Regex that identifies a multimarkdown-style metadata section at the start of the document
+ *
+ * In order to ensure that we have minimal risk of false positives when slurping metadata sections, the
+ * first key in the metadata section must be one of these standard keys or else the entire metadata section is
+ * ignored.
*/
- private static final String MULTI_MARKDOWN_METADATA_SECTION =
- "^(((?:[^\\s:][^:]*):(?:.*(?:\r?\n\\p{Blank}+[^\\s].*)*\r?\n))+)(?:\\s*\r?\n)";
+ private static final Pattern METADATA_SECTION_PATTERN = Pattern.compile(
+ "\\A^\\s*"
+ + "(?:title|author|date|address|affiliation|copyright|email|keywords|language|phone|subtitle)"
+ + "\\h*:\\h*\\V*\\h*$\\v+"
+ + "(?:^\\h*[^:\\v]+\\h*:\\h*\\V*\\h*$\\v+)*",
+ Pattern.MULTILINE | Pattern.CASE_INSENSITIVE );
/**
* Regex that captures the key and value of a multimarkdown-style metadata entry.
*/
- private static final String MULTI_MARKDOWN_METADATA_ENTRY =
- "([^\\s:][^:]*):(.*(?:\r?\n\\p{Blank}+[^\\s].*)*)\r?\n";
-
- /**
- * In order to ensure that we have minimal risk of false positives when slurping metadata sections, the
- * first key in the metadata section must be one of these standard keys or else the entire metadata section is
- * ignored.
- */
- private static final String[] STANDARD_METADATA_KEYS =
- { "title", "author", "date", "address", "affiliation", "copyright", "email", "keywords", "language", "phone",
- "subtitle" };
+ private static final Pattern METADATA_ENTRY_PATTERN = Pattern.compile(
+ "^\\h*([^:\\v]+?)\\h*:\\h*(\\V*)\\h*$",
+ Pattern.MULTILINE );
/**
* <p>getType.</p>
*
* @return a int.
*/
+ @Override
public int getType()
{
return TXT_TYPE;
}
+ /**
+ * The parser of the HTML produced by Flexmark, that we will
+ * use to convert this HTML to Sink events
+ */
@Requirement
private MarkdownHtmlParser parser;
+ /**
+ * Flexmark's Markdown parser (one static instance fits all)
+ */
+ private static final com.vladsch.flexmark.parser.Parser FLEXMARK_PARSER;
+
+ /**
+ * Flexmark's HTML renderer (its output will be re-parsed and converted to Sink events)
+ */
+ private static final HtmlRenderer FLEXMARK_HTML_RENDERER;
+
+ // Initialize the Flexmark parser and renderer, once and for all
+ static
+ {
+ MutableDataSet flexmarkOptions = new MutableDataSet();
+
+ // Enable the extensions that we used to have in Pegdown
+ flexmarkOptions.set( com.vladsch.flexmark.parser.Parser.EXTENSIONS, Arrays.asList(
+ EscapedCharacterExtension.create(),
+ AbbreviationExtension.create(),
+ AutolinkExtension.create(),
+ DefinitionExtension.create(),
+ TypographicExtension.create(),
+ TablesExtension.create(),
+ WikiLinkExtension.create(),
+ StrikethroughExtension.create()
+ ) );
+
+ // Additional options on the HTML rendering
+ flexmarkOptions.set( HtmlRenderer.HTML_BLOCK_OPEN_TAG_EOL, false );
+ flexmarkOptions.set( HtmlRenderer.HTML_BLOCK_CLOSE_TAG_EOL, false );
+ flexmarkOptions.set( HtmlRenderer.MAX_TRAILING_BLANK_LINES, -1 );
+
+ // Build the Markdown parser
+ FLEXMARK_PARSER = com.vladsch.flexmark.parser.Parser.builder( flexmarkOptions ).build();
+
+ // Build the HTML renderer
+ FLEXMARK_HTML_RENDERER = HtmlRenderer.builder( flexmarkOptions )
+ .linkResolverFactory( new FlexmarkDoxiaLinkResolver.Factory() )
+ .build();
+
+ }
+
/** {@inheritDoc} */
+ @Override
public void parse( Reader source, Sink sink )
throws ParseException
{
try
{
// Markdown to HTML (using flexmark-java library)
- String html = toHtml( source );
+ CharSequence html = toHtml( source );
+
// then HTML to Sink API
- parser.parse( new StringReader( html ), sink );
+ parser.parse( new CharSequenceReader( html ), sink );
}
catch ( IOException e )
{
@@ -130,133 +184,98 @@ public class MarkdownParser
* @return HTML content generated by flexmark-java
* @throws IOException passed through
*/
- String toHtml( Reader source )
+ CharSequence toHtml( Reader source )
throws IOException
{
+ // Read the source
String text = IOUtil.toString( source );
- MutableDataHolder flexmarkOptions = PegdownOptionsAdapter.flexmarkOptions(
- Extensions.ALL & ~( Extensions.HARDWRAPS | Extensions.ANCHORLINKS ) ).toMutable();
- ArrayList<Extension> extensions = new ArrayList<>();
- for ( Extension extension : flexmarkOptions.get( com.vladsch.flexmark.parser.Parser.EXTENSIONS ) )
- {
- extensions.add( extension );
- }
-
- extensions.add( FlexmarkDoxiaExtension.create() );
- flexmarkOptions.set( com.vladsch.flexmark.parser.Parser.EXTENSIONS, extensions );
- flexmarkOptions.set( HtmlRenderer.HTML_BLOCK_OPEN_TAG_EOL, false );
- flexmarkOptions.set( HtmlRenderer.HTML_BLOCK_CLOSE_TAG_EOL, false );
- flexmarkOptions.set( HtmlRenderer.MAX_TRAILING_BLANK_LINES, -1 );
-
- com.vladsch.flexmark.parser.Parser parser = com.vladsch.flexmark.parser.Parser.builder( flexmarkOptions )
- .build();
- HtmlRenderer renderer = HtmlRenderer.builder( flexmarkOptions )
- .linkResolverFactory( new FlexmarkDoxiaLinkResolver.Factory() )
- .build();
-
+ // Now, build the HTML document
StringBuilder html = new StringBuilder( 1000 );
html.append( "<html>" );
html.append( "<head>" );
- Pattern metadataPattern = Pattern.compile( MULTI_MARKDOWN_METADATA_SECTION, Pattern.MULTILINE );
- Matcher metadataMatcher = metadataPattern.matcher( text );
+
+ // First, we interpret the "metadata" section of the document and add the corresponding HTML headers
+ Matcher metadataMatcher = METADATA_SECTION_PATTERN.matcher( text );
boolean haveTitle = false;
if ( metadataMatcher.find() )
{
- metadataPattern = Pattern.compile( MULTI_MARKDOWN_METADATA_ENTRY, Pattern.MULTILINE );
- Matcher lineMatcher = metadataPattern.matcher( metadataMatcher.group( 1 ) );
- boolean first = true;
- while ( lineMatcher.find() )
+ Matcher entryMatcher = METADATA_ENTRY_PATTERN.matcher( metadataMatcher.group( 0 ) );
+ while ( entryMatcher.find() )
{
- String key = StringUtils.trimToEmpty( lineMatcher.group( 1 ) );
- if ( first )
- {
- boolean found = false;
- for ( String k : STANDARD_METADATA_KEYS )
- {
- if ( k.equalsIgnoreCase( key ) )
- {
- found = true;
- break;
- }
- }
- if ( !found )
- {
- break;
- }
- first = false;
- }
- String value = StringUtils.trimToEmpty( lineMatcher.group( 2 ) );
+ String key = entryMatcher.group( 1 );
+ String value = entryMatcher.group( 2 );
if ( "title".equalsIgnoreCase( key ) )
{
haveTitle = true;
html.append( "<title>" );
- html.append( StringEscapeUtils.escapeXml( value ) );
+ html.append( HtmlTools.escapeHTML( value, false ) );
html.append( "</title>" );
}
- else if ( "author".equalsIgnoreCase( key ) )
- {
- html.append( "<meta name=\'author\' content=\'" );
- html.append( StringEscapeUtils.escapeXml( value ) );
- html.append( "\' />" );
- }
- else if ( "date".equalsIgnoreCase( key ) )
- {
- html.append( "<meta name=\'date\' content=\'" );
- html.append( StringEscapeUtils.escapeXml( value ) );
- html.append( "\' />" );
- }
else
{
- html.append( "<meta name=\'" );
- html.append( StringEscapeUtils.escapeXml( key ) );
- html.append( "\' content=\'" );
- html.append( StringEscapeUtils.escapeXml( value ) );
- html.append( "\' />" );
+ html.append( "<meta name='" );
+ html.append( HtmlTools.escapeHTML( key ) );
+ html.append( "' content='" );
+ html.append( HtmlTools.escapeHTML( value ) );
+ html.append( "' />" );
}
}
- if ( !first )
- {
- text = text.substring( metadataMatcher.end() );
- }
+
+ // Trim the metadata from the source
+ text = text.substring( metadataMatcher.end( 0 ) );
+
}
- Node rootNode = parser.parse( text );
- String markdownHtml = renderer.render( rootNode );
+ // Now is the time to parse the Markdown document
+ // (after we've trimmed out the metadatas, and before we check for its headings)
+ Node documentRoot = FLEXMARK_PARSER.parse( text );
- if ( !haveTitle && rootNode.hasChildren() )
+ // Special trick: if there is no title specified as a metadata in the header, we will use the first
+ // heading as the document title
+ if ( !haveTitle && documentRoot.hasChildren() )
{
- // use the first (non-comment) node only if it is a heading
- Node firstNode = rootNode.getFirstChild();
- while ( firstNode != null && !( firstNode instanceof Heading ) )
+ // Skip the comment nodes
+ Node firstNode = documentRoot.getFirstChild();
+ while ( firstNode != null && firstNode instanceof HtmlCommentBlock )
{
- if ( !( firstNode instanceof HtmlCommentBlock ) )
- {
- break;
- }
firstNode = firstNode.getNext();
}
- if ( firstNode instanceof Heading )
+ // If this first non-comment node is a heading, we use it as the document title
+ if ( firstNode != null && firstNode instanceof Heading )
{
html.append( "<title>" );
TextCollectingVisitor collectingVisitor = new TextCollectingVisitor();
String headingText = collectingVisitor.collectAndGetText( firstNode );
- html.append( StringEscapeUtils.escapeXml( headingText ) );
+ html.append( HtmlTools.escapeHTML( headingText, false ) );
html.append( "</title>" );
}
}
html.append( "</head>" );
html.append( "<body>" );
- html.append( markdownHtml );
+
+ // Convert our Markdown document to HTML and append it to our HTML
+ FLEXMARK_HTML_RENDERER.render( documentRoot, html );
+
html.append( "</body>" );
html.append( "</html>" );
- return html.toString();
+ return html;
}
/**
* Internal parser for HTML generated by the Markdown library.
+ *
+ * 2 special things:
+ * <ul>
+ * <li> DIV elements are translated as Unknown Sink events
+ * <li> PRE elements are all considered as boxed
+ * </ul>
+ * PRE elements need to be "boxed" because the XhtmlSink will surround the
+ * corresponding verbatim() Sink event with a DIV element with class="source",
+ * which is how most Maven Skin (incl. Fluido) recognize a block of code, which
+ * needs to be highlighted accordingly.
*/
@Component( role = MarkdownHtmlParser.class )
public static class MarkdownHtmlParser
@@ -268,6 +287,13 @@ public class MarkdownParser
}
@Override
+ protected void init()
+ {
+ super.init();
+ super.boxed = true;
+ }
+
+ @Override
protected boolean baseEndTag( XmlPullParser parser, Sink sink )
{
boolean visited = super.baseEndTag( parser, sink );
@@ -291,6 +317,7 @@ public class MarkdownParser
if ( parser.getName().equals( HtmlMarkup.DIV.toString() ) )
{
handleUnknown( parser, sink, TAG_TYPE_START );
+ super.boxed = true;
visited = true;
}
}
diff --git a/doxia-modules/doxia-module-markdown/src/test/java/org/apache/maven/doxia/module/markdown/MarkdownParserTest.java b/doxia-modules/doxia-module-markdown/src/test/java/org/apache/maven/doxia/module/markdown/MarkdownParserTest.java
index 8110378..fbdd547 100644
--- a/doxia-modules/doxia-module-markdown/src/test/java/org/apache/maven/doxia/module/markdown/MarkdownParserTest.java
+++ b/doxia-modules/doxia-module-markdown/src/test/java/org/apache/maven/doxia/module/markdown/MarkdownParserTest.java
@@ -165,12 +165,43 @@ public class MarkdownParserTest
{
Iterator<SinkEventElement> it = parseFileToEventTestingSink( "code" ).getEventList().iterator();
- assertEquals( it, "head", "head_", "body", "paragraph", "text", "paragraph_", "text", "unknown", "verbatim", "text", "verbatim_", "unknown", "body_" );
+ assertEquals( it, "head", "head_", "body", "paragraph", "text", "paragraph_", "text", "verbatim", "inline", "text", "inline_", "verbatim_", "body_" );
assertFalse( it.hasNext() );
}
/**
+ * Assert the verbatim sink event is fired when parsing "fenced-code-block.md".
+ *
+ * @throws Exception if the event list is not correct when parsing the document
+ */
+ public void testFencedCodeBlockSinkEvent()
+ throws Exception
+ {
+ List<SinkEventElement> eventList = parseFileToEventTestingSink( "fenced-code-block" ).getEventList();
+ Iterator<SinkEventElement> it = eventList.iterator();
+
+ assertEquals( it, "head", "head_", "body", "paragraph", "text", "paragraph_", "text", "verbatim", "inline", "text", "inline_", "verbatim_", "body_" );
+
+ assertFalse( it.hasNext() );
+
+ // PRE element must be a "verbatim" Sink event that specifies
+ // BOXED = true
+ SinkEventElement pre = eventList.get( 7 );
+ assertEquals( "verbatim", pre.getName() );
+ SinkEventAttributeSet preAtts = (SinkEventAttributeSet) pre.getArgs()[0];
+ assertTrue( preAtts.containsAttribute( SinkEventAttributes.DECORATION, "boxed" ) );
+
+ // * CODE element must be an "inline" Sink event that specifies:
+ // * SEMANTICS = "code" and CLASS = "language-java"
+ SinkEventElement code = eventList.get( 8 );
+ assertEquals( "inline", code.getName() );
+ SinkEventAttributeSet codeAtts = (SinkEventAttributeSet) code.getArgs()[0];
+ assertTrue( codeAtts.containsAttribute( SinkEventAttributes.SEMANTICS, "code" ) );
+ assertTrue( codeAtts.containsAttribute( SinkEventAttributes.CLASS, "language-java" ) );
+ }
+
+ /**
* Assert the figureGraphics sink event is fired when parsing "image.md".
*
* @throws Exception if the event list is not correct when parsing the document
@@ -223,7 +254,7 @@ public class MarkdownParserTest
public void testLinkWithAnchorAndQuery() throws Exception
{
Iterator<SinkEventElement> it = parseFileToEventTestingSink( "link_anchor_query" ).getEventList().iterator();
-
+
assertEquals( it, "head", "head_", "body", "paragraph", "link", "text", "link_", "paragraph_", "body_" );
assertFalse( it.hasNext() );
@@ -269,14 +300,36 @@ public class MarkdownParserTest
public void testMetadataSinkEvent()
throws Exception
{
- Iterator<SinkEventElement> it = parseFileToEventTestingSink( "metadata" ).getEventList().iterator();
+ List<SinkEventElement> eventList = parseFileToEventTestingSink( "metadata" ).getEventList();
+ Iterator<SinkEventElement> it = eventList.iterator();
- assertEquals( it, "head", "title", "text", "title_", "author", "text", "author_", "date", "text", "date_",
- "head_", "body", "unknown", "text", "unknown", "paragraph", "text", "paragraph_", "section1",
+ assertEquals( it, "head", "title", "text", "text", "text", "title_", "author", "text", "author_", "date", "text", "date_",
+ "unknown", "head_", "body", "unknown", "text", "unknown", "paragraph", "text", "paragraph_", "section1",
"sectionTitle1", "text", "sectionTitle1_", "paragraph", "text", "paragraph_", "section1_",
"body_" );
assertFalse( it.hasNext() );
+
+ // Title must be "A Title & a Test"
+ assertEquals( "A Title ", eventList.get( 2 ).getArgs()[0]);
+ assertEquals( "&", eventList.get( 3 ).getArgs()[0]);
+ assertEquals( " a 'Test'", eventList.get( 4 ).getArgs()[0]);
+
+ // Author must be "Somebody <so...@somewhere.org>"
+ assertEquals( "Somebody 'Nickname' Great <so...@somewhere.org>", eventList.get( 7 ).getArgs()[0]);
+
+ // Date must be "2013 © Copyleft"
+ assertEquals( "2013 \u00A9 Copyleft", eventList.get( 10 ).getArgs()[0]);
+
+ // * META element must be an "unknown" Sink event that specifies:
+ // * name = "keywords" and content = "maven,doxia,markdown"
+ SinkEventElement meta = eventList.get( 12 );
+ assertEquals( "unknown", meta.getName() );
+ assertEquals( "meta", meta.getArgs()[0] );
+ SinkEventAttributeSet metaAtts = (SinkEventAttributeSet) meta.getArgs()[2];
+ assertTrue( metaAtts.containsAttribute( SinkEventAttributes.NAME, "keywords" ) );
+ assertTrue( metaAtts.containsAttribute( "content", "maven,doxia,markdown" ) );
+
}
/**
@@ -290,8 +343,9 @@ public class MarkdownParserTest
Iterator<SinkEventElement> it = parseFileToEventTestingSink( "first-heading" ).getEventList().iterator();
// NOTE: H1 is rendered as "unknown" and H2 is "section1" (see DOXIA-203)
- assertEquals( it, "head", "title", "text", "title_", "head_", "body", "section1", "sectionTitle1", "text",
- "sectionTitle1_", "paragraph", "text", "paragraph_", "section1_", "body_" );
+ assertEquals( it, "head", "title", "text", "title_", "head_", "body", "comment", "text",
+ "section1", "sectionTitle1", "text", "sectionTitle1_", "paragraph", "text",
+ "paragraph_", "section1_", "body_" );
assertFalse( it.hasNext() );
}
@@ -358,7 +412,7 @@ public class MarkdownParserTest
{
try ( Reader reader = getTestReader( file ) )
{
- return parser.toHtml( reader );
+ return parser.toHtml( reader ).toString();
}
}
diff --git a/doxia-modules/doxia-module-markdown/src/test/resources/fenced-code-block.md b/doxia-modules/doxia-module-markdown/src/test/resources/fenced-code-block.md
new file mode 100644
index 0000000..d8df735
--- /dev/null
+++ b/doxia-modules/doxia-module-markdown/src/test/resources/fenced-code-block.md
@@ -0,0 +1,5 @@
+Below code is Java:
+
+```java
+System.out.println(helloWorld);
+```
diff --git a/doxia-modules/doxia-module-markdown/src/test/resources/first-heading.md b/doxia-modules/doxia-module-markdown/src/test/resources/first-heading.md
index 622fffe..108f199 100644
--- a/doxia-modules/doxia-module-markdown/src/test/resources/first-heading.md
+++ b/doxia-modules/doxia-module-markdown/src/test/resources/first-heading.md
@@ -1,7 +1,7 @@
-
+<!-- To be discarded -->
First heading
diff --git a/doxia-modules/doxia-module-markdown/src/test/resources/metadata.md b/doxia-modules/doxia-module-markdown/src/test/resources/metadata.md
index dac8009..97ce7f1 100644
--- a/doxia-modules/doxia-module-markdown/src/test/resources/metadata.md
+++ b/doxia-modules/doxia-module-markdown/src/test/resources/metadata.md
@@ -1,10 +1,13 @@
-title: A title
-author: Somebody
-date: 2013
-# The document
+title: A Title & a 'Test'
+author: Somebody 'Nickname' Great <so...@somewhere.org>
-Some text
+date: 2013 © Copyleft
+keywords: maven,doxia,markdown
+
+# The document with look-alike header
+
+copyright: none
## A subheading
diff --git a/doxia-modules/doxia-module-xhtml/src/main/java/org/apache/maven/doxia/module/xhtml/XhtmlParser.java b/doxia-modules/doxia-module-xhtml/src/main/java/org/apache/maven/doxia/module/xhtml/XhtmlParser.java
index 00cfc8d..470fc2f 100644
--- a/doxia-modules/doxia-module-xhtml/src/main/java/org/apache/maven/doxia/module/xhtml/XhtmlParser.java
+++ b/doxia-modules/doxia-module-xhtml/src/main/java/org/apache/maven/doxia/module/xhtml/XhtmlParser.java
@@ -53,7 +53,7 @@ public class XhtmlParser
implements XhtmlMarkup
{
/** For boxed verbatim. */
- private boolean boxed;
+ protected boolean boxed;
/** Empty elements don't write a closing tag. */
private boolean isEmptyElement;
diff --git a/pom.xml b/pom.xml
index b634aa6..da0dd4c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -207,6 +207,14 @@ under the License.
<artifactId>plexus-utils</artifactId>
<version>3.3.0</version>
</dependency>
+
+ <!-- Apache Commons IO -->
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.6</version>
+ </dependency>
+
</dependencies>
</dependencyManagement>
@@ -262,6 +270,7 @@ under the License.
<exclude>src/test/site/**/*.confluence</exclude>
<exclude>src/test/resources/**/*.twiki</exclude>
<exclude>src/test/resources/**/*.md</exclude>
+ <exclude>src/it/**/site/**/*.md</exclude>
</excludes>
</configuration>
</plugin>
@@ -317,6 +326,13 @@ under the License.
<exclude>org/apache/maven/doxia/module/fml/FmlContentParser</exclude>
<exclude>org/apache/maven/doxia/module/xdoc/XdocParser</exclude>
</excludes>
+ <ignored>
+ <!-- DOXIA-616 -->
+ <difference>
+ <differenceType>8001</differenceType>
+ <className>org/apache/maven/doxia/module/markdown/FlexmarkDoxiaNodeRenderer$Factory</className>
+ </difference>
+ </ignored>
</configuration>
</execution>
</executions>