You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by kw...@apache.org on 2024/11/04 15:53:13 UTC

(maven-doxia-converter) 01/01: [DOXIATOOLS-89] Macros should not be resolved

This is an automated email from the ASF dual-hosted git repository.

kwin pushed a commit to branch feature/keep-macros
in repository https://gitbox.apache.org/repos/asf/maven-doxia-converter.git

commit 50b7189fb51718c99b3ad1579f907321e2e80eb1
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Mon Nov 4 16:53:03 2024 +0100

    [DOXIATOOLS-89] Macros should not be resolved
    
    Instead they should be converted to the destination format
---
 pom.xml                                            |   3 +-
 .../org/apache/maven/doxia/DefaultConverter.java   | 113 ++++++++++++++++++++-
 .../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   |  43 ++++++++
 src/test/resources/unit/apt/macro.apt              |  12 +++
 src/test/resources/unit/markdown/macro.md          |  12 +++
 8 files changed, 212 insertions(+), 19 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 11a8783..55f22cf 100644
--- a/src/main/java/org/apache/maven/doxia/DefaultConverter.java
+++ b/src/main/java/org/apache/maven/doxia/DefaultConverter.java
@@ -32,15 +32,21 @@ import java.io.Reader;
 import java.io.Writer;
 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.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;
@@ -77,6 +83,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)
      */
@@ -133,19 +206,49 @@ public class DefaultConverter implements Converter {
             return firstElement != null;
         }
 
+        public String formatMacro(String name, Map<String, Object> parameters) {
+
+            return format("%{%s|%s}", name, parameters.toString());
+        }
         /**
          * @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;
+        }
+
+        public static class MacroConverterExecutor implements MacroExecutor {
+            private final MacroFormatter macroFormatter;
 
-            return plexus.lookup(Parser.class, roleHint);
+            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);
+            }
         }
 
         /**
@@ -272,7 +375,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);
             }
@@ -355,7 +458,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
new file mode 100644
index 0000000..c2fccab
--- /dev/null
+++ b/src/test/java/org/apache/maven/doxia/DefaultConverterTest.java
@@ -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.
+ */
+package org.apache.maven.doxia;
+
+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;
+
+class DefaultConverterTest {
+
+    @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..483d7c4
--- /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
+