This is an automated email from the ASF dual-hosted git repository. kwin pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/maven-doxia-converter.git
The following commit(s) were added to refs/heads/master by this push: new 6bdce4c [DOXIATOOLS-89] Macros should not be resolved (#86) 6bdce4c is described below commit 6bdce4c8c8e94852b9d4ecb99b85e8a163fbe948 Author: Konrad Windszus <k...@apache.org> AuthorDate: Tue Nov 19 12:19:39 2024 +0100 [DOXIATOOLS-89] Macros should not be resolved (#86) Instead they should be converted to the destination format. Clean up wrapper classes to directly use enum for DoxiaFormat. --- pom.xml | 3 +- .../org/apache/maven/doxia/DefaultConverter.java | 109 ++++++++++++++++++++- .../maven/doxia/wrapper/InputReaderWrapper.java | 6 +- .../maven/doxia/wrapper/OutputStreamWrapper.java | 10 +- .../java/org/apache/maven/doxia/ConverterTest.java | 32 +++++- .../apache/maven/doxia/DefaultConverterTest.java | 19 +++- src/test/resources/unit/apt/macro.apt | 12 +++ src/test/resources/unit/markdown/macro.md | 12 +++ 8 files changed, 183 insertions(+), 20 deletions(-) diff --git a/pom.xml b/pom.xml index 4b463d5..7c668c3 100644 --- a/pom.xml +++ b/pom.xml @@ -55,7 +55,7 @@ under the License. </distributionManagement> <properties> - <doxiaVersion>2.0.0</doxiaVersion> + <doxiaVersion>2.1.0-SNAPSHOT</doxiaVersion> <javaVersion>8</javaVersion> <project.build.outputTimestamp>2023-01-09T21:24:22Z</project.build.outputTimestamp> </properties> @@ -175,6 +175,7 @@ under the License. <configuration> <excludes combine.children="append"> <exclude>src/test/resources/unit/**/test.*</exclude> + <exclude>src/test/resources/unit/**/macro.*</exclude> <exclude>src/test/resources/book-1/section-*.apt</exclude> </excludes> </configuration> diff --git a/src/main/java/org/apache/maven/doxia/DefaultConverter.java b/src/main/java/org/apache/maven/doxia/DefaultConverter.java index b68617a..9a4ffae 100644 --- a/src/main/java/org/apache/maven/doxia/DefaultConverter.java +++ b/src/main/java/org/apache/maven/doxia/DefaultConverter.java @@ -35,16 +35,22 @@ import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.util.EnumSet; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Scanner; +import java.util.stream.Collectors; import com.ibm.icu.text.CharsetDetector; import com.ibm.icu.text.CharsetMatch; import org.apache.commons.io.input.XmlStreamReader; import org.apache.commons.lang3.StringUtils; +import org.apache.maven.doxia.macro.MacroExecutionException; +import org.apache.maven.doxia.macro.MacroExecutor; +import org.apache.maven.doxia.macro.MacroRequest; +import org.apache.maven.doxia.macro.manager.MacroNotFoundException; import org.apache.maven.doxia.parser.ParseException; import org.apache.maven.doxia.parser.Parser; import org.apache.maven.doxia.sink.Sink; @@ -81,6 +87,73 @@ import static java.lang.String.format; */ @Named public class DefaultConverter implements Converter { + + /** Macro formatter for different Doxia formats. + * @see <a href="https://maven.apache.org/doxia/macros/index.html">Doxia Macros</a> + */ + enum MacroFormatter { + APT("%{", "|", "=", "|", "}"), + FML("<macro name=\"", "\"", "<param name=\"", "\" value=\" />", "</macro>"), + XDOC("<macro name=\"", "\"", "<param name=\"", "\" value=\" />", "</macro>"), + XHTML("<!-- MACRO{", "|", "=", "|", "} -->"), + MARKDOWN("<!-- MACRO{", "|", "=", "|", "} -->"); + + private final String prefix; + private final String nameParameterDelimiter; + private final String parameterNameValueDelimiter; + private final String parameterDelimiter; + private final String suffix; + + public static MacroFormatter forFormat(DoxiaFormat format) { + switch (format) { + case APT: + return APT; + case FML: + return FML; + case XDOC: + return XDOC; + case XHTML: + return XHTML; + case MARKDOWN: + return MARKDOWN; + default: + throw new IllegalArgumentException("Unsupported Doxia format: " + format); + } + } + + MacroFormatter( + String prefix, + String nameParameterDelimiter, + String parameterNameValueDelimiter, + String parameterDelimiter, + String suffix) { + this.prefix = prefix; + this.nameParameterDelimiter = nameParameterDelimiter; + this.parameterNameValueDelimiter = parameterNameValueDelimiter; + this.parameterDelimiter = parameterDelimiter; + this.suffix = suffix; + } + + /** + * Formats a macro with the given name and parameters for this format. + * @param name + * @param parameters + * @return the formatted macro string to be emitted in the output + */ + public String format(String name, Map<String, Object> parameters) { + StringBuilder macro = new StringBuilder(); + macro.append(prefix).append(name); + String parameterString = parameters.entrySet().stream() + .map(e -> e.getKey() + parameterNameValueDelimiter + e.getValue()) + .collect(Collectors.joining(parameterDelimiter)); + if (!parameters.isEmpty()) { + macro.append(nameParameterDelimiter).append(parameterString); + } + macro.append(suffix); + return macro.toString(); + } + } + /** * All supported Doxia formats (either only parser, only sink or both) */ @@ -139,17 +212,43 @@ public class DefaultConverter implements Converter { /** * @param plexus not null - * @return an instance of <code>Parser</code> depending on the format. + * @param macroFormatter a formatter for macros in the target format + * @return an instance of <code>Parser</code> depending on the format which converts macros with the given {@link MacroFormatter} * @throws ComponentLookupException if could not find the Parser for the given format. * @throws IllegalArgumentException if any parameter is null */ - public Parser getParser(PlexusContainer plexus) throws ComponentLookupException { + public Parser getParser(PlexusContainer plexus, MacroFormatter macroFormatter) throws ComponentLookupException { if (!hasParser) { throw new IllegalStateException("The format " + this + " is not supported as parser!"); } Objects.requireNonNull(plexus, "plexus is required"); + Parser parser = plexus.lookup(Parser.class, roleHint); + parser.setMacroExecutor(new MacroConverterExecutor(macroFormatter)); + return parser; + } - return plexus.lookup(Parser.class, roleHint); + public static class MacroConverterExecutor implements MacroExecutor { + private final MacroFormatter macroFormatter; + + public MacroConverterExecutor(MacroFormatter macroFormatter) { + super(); + this.macroFormatter = macroFormatter; + } + + @Override + public void executeMacro(String id, MacroRequest request, Sink sink) + throws MacroExecutionException, MacroNotFoundException { + // filter out internal parameters but keep original order + Map<String, Object> parameters = request.getParameters().entrySet().stream() + .filter(e -> !MacroRequest.isInternalParameter(e.getKey())) + .collect(Collectors.toMap( + Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); + + // the format of macros differs between the parser implementations + // (https://maven.apache.org/doxia/macros/index.html) + String macro = macroFormatter.format(id, parameters); + sink.rawText(macro); + } } /** @@ -354,7 +453,7 @@ public class DefaultConverter implements Converter { try { Parser parser; try { - parser = input.getFormat().getParser(plexus); + parser = input.getFormat().getParser(plexus, MacroFormatter.forFormat(output.getFormat())); } catch (ComponentLookupException e) { throw new ConverterException("ComponentLookupException: " + e.getMessage(), e); } @@ -443,7 +542,7 @@ public class DefaultConverter implements Converter { Parser parser; try { - parser = parserFormat.getParser(plexus); + parser = parserFormat.getParser(plexus, MacroFormatter.forFormat(output.getFormat())); } catch (ComponentLookupException e) { throw new ConverterException("ComponentLookupException: " + e.getMessage(), e); } diff --git a/src/main/java/org/apache/maven/doxia/wrapper/InputReaderWrapper.java b/src/main/java/org/apache/maven/doxia/wrapper/InputReaderWrapper.java index 0d315b1..4b173d6 100644 --- a/src/main/java/org/apache/maven/doxia/wrapper/InputReaderWrapper.java +++ b/src/main/java/org/apache/maven/doxia/wrapper/InputReaderWrapper.java @@ -42,8 +42,8 @@ public class InputReaderWrapper { * @param supportedFormat not null * @throws IllegalArgumentException if the format equals AUTO_FORMAT. */ - private InputReaderWrapper(Reader reader, String format) { - this.format = DefaultConverter.DoxiaFormat.valueOf(format.toUpperCase()); + private InputReaderWrapper(Reader reader, DefaultConverter.DoxiaFormat format) { + this.format = format; if (reader == null) { throw new IllegalArgumentException("input reader is required"); @@ -66,7 +66,7 @@ public class InputReaderWrapper { * @param format not null * @return a type safe input reader */ - public static InputReaderWrapper valueOf(Reader reader, String format) { + public static InputReaderWrapper valueOf(Reader reader, DefaultConverter.DoxiaFormat format) { return new InputReaderWrapper(reader, format); } } diff --git a/src/main/java/org/apache/maven/doxia/wrapper/OutputStreamWrapper.java b/src/main/java/org/apache/maven/doxia/wrapper/OutputStreamWrapper.java index 28e84ee..7790928 100644 --- a/src/main/java/org/apache/maven/doxia/wrapper/OutputStreamWrapper.java +++ b/src/main/java/org/apache/maven/doxia/wrapper/OutputStreamWrapper.java @@ -45,8 +45,8 @@ public class OutputStreamWrapper { * @param supportedFormat not null * @throws IllegalArgumentException if any. */ - private OutputStreamWrapper(OutputStream out, String format, String encoding) { - this.format = DefaultConverter.DoxiaFormat.valueOf(format.toUpperCase()); + private OutputStreamWrapper(OutputStream out, DefaultConverter.DoxiaFormat format, String encoding) { + this.format = format; this.out = out; this.encoding = encoding; } @@ -75,11 +75,9 @@ public class OutputStreamWrapper { * @param encoding not null * @return a type safe output stream wrapper */ - public static OutputStreamWrapper valueOf(OutputStream out, String format, String encoding) { + public static OutputStreamWrapper valueOf(OutputStream out, DefaultConverter.DoxiaFormat format, String encoding) { Objects.requireNonNull(out, "output writer is required"); - if (format == null || format.isEmpty()) { - throw new IllegalArgumentException("output format is required"); - } + Objects.requireNonNull(format, "output format is required"); return new OutputStreamWrapper(out, format, encoding); } diff --git a/src/test/java/org/apache/maven/doxia/ConverterTest.java b/src/test/java/org/apache/maven/doxia/ConverterTest.java index 07ff85f..4695c2e 100644 --- a/src/test/java/org/apache/maven/doxia/ConverterTest.java +++ b/src/test/java/org/apache/maven/doxia/ConverterTest.java @@ -20,13 +20,20 @@ package org.apache.maven.doxia; import javax.inject.Inject; +import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; +import java.io.IOException; import java.io.OutputStream; +import java.io.Reader; +import java.io.StringReader; import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import org.apache.maven.doxia.DefaultConverter.DoxiaFormat; import org.apache.maven.doxia.wrapper.InputFileWrapper; @@ -43,6 +50,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertLinesMatch; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -263,9 +271,7 @@ class ConverterTest extends InjectedTest { @Test void aptWriterConverter() throws Exception { String in = getBasedir() + "/src/test/resources/unit/apt/test.apt"; - String from = "apt"; String out = getBasedir() + "/target/unit/writer/apt/test.apt.xhtml"; - String to = "xhtml"; File inFile = new File(in); File outFile = new File(out); @@ -274,8 +280,8 @@ class ConverterTest extends InjectedTest { try (OutputStream fo = new FileOutputStream(outFile)) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - InputReaderWrapper input = InputReaderWrapper.valueOf(new FileReader(inFile), from); - OutputStreamWrapper output = OutputStreamWrapper.valueOf(outputStream, to, "UTF-8"); + InputReaderWrapper input = InputReaderWrapper.valueOf(new FileReader(inFile), DoxiaFormat.APT); + OutputStreamWrapper output = OutputStreamWrapper.valueOf(outputStream, DoxiaFormat.XHTML, "UTF-8"); converter.setFormatOutput(formatOutput); converter.convert(input, output); @@ -429,4 +435,22 @@ class ConverterTest extends InjectedTest { assertEquals(DoxiaFormat.FML, autoDetectFormat("fml/test.fml")); assertEquals(DoxiaFormat.XHTML, autoDetectFormat("xhtml/test.xhtml")); } + + @Test + void testAptToMarkdownWithMacro() throws IOException, UnsupportedFormatException, ConverterException { + Path in = new File(getBasedir() + "/src/test/resources/unit/apt/macro.apt").toPath(); + Path expectedOut = new File(getBasedir() + "//src/test/resources/unit/markdown/macro.md").toPath(); + + try (ByteArrayOutputStream output = new ByteArrayOutputStream(); + Reader reader = Files.newBufferedReader(in, StandardCharsets.UTF_8); ) { + converter.convert( + InputReaderWrapper.valueOf(reader, DoxiaFormat.APT), + OutputStreamWrapper.valueOf(output, DoxiaFormat.MARKDOWN, StandardCharsets.UTF_8.name())); + + try (BufferedReader outputReader = + new BufferedReader(new StringReader(new String(output.toByteArray(), StandardCharsets.UTF_8))); ) { + assertLinesMatch(Files.readAllLines(expectedOut).stream(), outputReader.lines()); + } + } + } } diff --git a/src/test/java/org/apache/maven/doxia/DefaultConverterTest.java b/src/test/java/org/apache/maven/doxia/DefaultConverterTest.java index 8b785fd..696a1cb 100644 --- a/src/test/java/org/apache/maven/doxia/DefaultConverterTest.java +++ b/src/test/java/org/apache/maven/doxia/DefaultConverterTest.java @@ -19,9 +19,14 @@ package org.apache.maven.doxia; import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import org.apache.maven.doxia.DefaultConverter.MacroFormatter; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; class DefaultConverterTest { @@ -32,9 +37,21 @@ class DefaultConverterTest { } @Test - void testExecuteInvalidCommand() throws IOException, InterruptedException { + void testExecuteInvalidCommand() { assertThrows(IOException.class, () -> { DefaultConverter.executeCommand("invalid command"); }); } + + @Test + void testMacroFormatter() { + Map<String, Object> parameters = new HashMap<>(); + parameters.put("param1", "value1"); + parameters.put("param2", "value2"); + assertEquals("%{toc|param1=value1|param2=value2}", MacroFormatter.APT.format("toc", parameters)); + assertEquals("%{toc}", MacroFormatter.APT.format("toc", Collections.emptyMap())); + assertEquals( + "<!-- MACRO{toc|param1=value1|param2=value2} -->", MacroFormatter.MARKDOWN.format("toc", parameters)); + assertEquals("<!-- MACRO{toc} -->", MacroFormatter.MARKDOWN.format("toc", Collections.emptyMap())); + } } diff --git a/src/test/resources/unit/apt/macro.apt b/src/test/resources/unit/apt/macro.apt new file mode 100644 index 0000000..86387ee --- /dev/null +++ b/src/test/resources/unit/apt/macro.apt @@ -0,0 +1,12 @@ + ------ + Title + ------ + Author + ------ + Date + +%{toc|section=0|fromDepth=1|toDepth=3} + +Introduction + + Section1 text \ No newline at end of file diff --git a/src/test/resources/unit/markdown/macro.md b/src/test/resources/unit/markdown/macro.md new file mode 100644 index 0000000..47ea223 --- /dev/null +++ b/src/test/resources/unit/markdown/macro.md @@ -0,0 +1,12 @@ +--- +title: Title +author: + - Author +date: Date +--- + +<!-- MACRO{toc|section=0|fromDepth=1|toDepth=3} --> +# Introduction + +Section1 text +