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

vy pushed a commit to branch feature/docgen-multi-template
in repository https://gitbox.apache.org/repos/asf/logging-log4j-tools.git

commit 3ede3369104fc91db1adffaff8b01ae8f5ae9d2c
Author: Volkan Yazıcı <vol...@yazi.ci>
AuthorDate: Wed May 8 14:26:09 2024 +0200

    Support multiple templates in `log4j-docgen:generate-documentation`
---
 .../docgen/maven/DocumentationGeneratorMojo.java   | 20 +++---
 .../docgen/generator/DocumentationGenerator.java   | 18 +++--
 .../generator/DocumentationGeneratorArgs.java      | 12 ++--
 .../docgen/generator/DocumentationTemplate.java    | 19 ++++++
 .../generator/DocumentationGeneratorTest.java      |  9 +--
 log4j-tools-internal-freemarker-util/pom.xml       | 14 ++++
 .../internal/freemarker/util/FreeMarkerUtils.java  | 70 ++++++++++++++++++--
 .../freemarker/util/FreeMarkerUtilsTest.java       | 77 ++++++++++++++++++++++
 .../.0.x.x/add-freemarker-stop-method.xml          |  9 +++
 .../.0.x.x/add-multi-doc-generator-template.xml    |  8 +++
 .../pages/log4j-docgen-asciidoctor-extension.adoc  |  1 +
 .../ROOT/pages/log4j-docgen-maven-plugin.adoc      | 24 ++++---
 12 files changed, 242 insertions(+), 39 deletions(-)

diff --git 
a/log4j-docgen-maven-plugin/src/main/java/org/apache/logging/log4j/docgen/maven/DocumentationGeneratorMojo.java
 
b/log4j-docgen-maven-plugin/src/main/java/org/apache/logging/log4j/docgen/maven/DocumentationGeneratorMojo.java
index bbb5c66..5d0ce40 100644
--- 
a/log4j-docgen-maven-plugin/src/main/java/org/apache/logging/log4j/docgen/maven/DocumentationGeneratorMojo.java
+++ 
b/log4j-docgen-maven-plugin/src/main/java/org/apache/logging/log4j/docgen/maven/DocumentationGeneratorMojo.java
@@ -17,8 +17,10 @@
 package org.apache.logging.log4j.docgen.maven;
 
 import java.io.File;
+import java.util.Arrays;
 import java.util.Set;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
 import org.apache.logging.log4j.docgen.PluginSet;
 import org.apache.logging.log4j.docgen.generator.DocumentationGenerator;
 import org.apache.logging.log4j.docgen.generator.DocumentationGeneratorArgs;
@@ -44,14 +46,14 @@ public class DocumentationGeneratorMojo extends 
AbstractDocgenMojo {
     /**
      * The template that will be used to document all types.
      */
-    @Parameter(required = true)
-    private DocumentationTemplateMojo indexTemplate;
+    @Parameter
+    private DocumentationTemplateMojo[] indexTemplates;
 
     /**
      * The template that will be used to document types.
      */
-    @Parameter(required = true)
-    private DocumentationTemplateMojo typeTemplate;
+    @Parameter
+    private DocumentationTemplateMojo[] typeTemplates;
 
     @Override
     public void execute() {
@@ -66,12 +68,14 @@ public class DocumentationGeneratorMojo extends 
AbstractDocgenMojo {
                 pluginSets,
                 classNameFilter,
                 templateDirectory.toPath(),
-                toApiModel(indexTemplate),
-                toApiModel(typeTemplate));
+                toApiModel(indexTemplates),
+                toApiModel(typeTemplates));
         DocumentationGenerator.generateDocumentation(generatorArgs);
     }
 
-    private static DocumentationTemplate toApiModel(final 
DocumentationTemplateMojo mojo) {
-        return new DocumentationTemplate(mojo.source, mojo.target);
+    private static Set<DocumentationTemplate> toApiModel(final 
DocumentationTemplateMojo[] mojos) {
+        return Arrays.stream(mojos)
+                .map(mojo -> new DocumentationTemplate(mojo.source, 
mojo.target))
+                .collect(Collectors.toSet());
     }
 }
diff --git 
a/log4j-docgen/src/main/java/org/apache/logging/log4j/docgen/generator/DocumentationGenerator.java
 
b/log4j-docgen/src/main/java/org/apache/logging/log4j/docgen/generator/DocumentationGenerator.java
index 9d26559..72dd7da 100644
--- 
a/log4j-docgen/src/main/java/org/apache/logging/log4j/docgen/generator/DocumentationGenerator.java
+++ 
b/log4j-docgen/src/main/java/org/apache/logging/log4j/docgen/generator/DocumentationGenerator.java
@@ -22,6 +22,7 @@ import static 
org.apache.logging.log4j.tools.internal.freemarker.util.FreeMarker
 import java.nio.file.Path;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import org.apache.logging.log4j.docgen.PluginSet;
@@ -39,20 +40,22 @@ public final class DocumentationGenerator {
                 .collect(Collectors.toList());
         final TypeLookup lookup = TypeLookup.of(extendedSets, 
args.classNameFilter);
         lookup.values()
-                .forEach(sourcedType -> renderType(sourcedType, lookup, 
args.templateDirectory, args.typeTemplate));
-        renderIndex(lookup, args.templateDirectory, args.indexTemplate);
+                .forEach(sourcedType -> renderType(sourcedType, lookup, 
args.templateDirectory, args.typeTemplates));
+        renderIndex(lookup, args.templateDirectory, args.indexTemplates);
     }
 
     private static void renderType(
             final ArtifactSourcedType sourcedType,
             final TypeLookup lookup,
             final Path templateDirectory,
-            final DocumentationTemplate template) {
+            final Set<DocumentationTemplate> templates) {
         final Map<String, Object> templateData = Map.of(
                 "sourcedType", sourcedType,
                 "lookup", lookup);
-        final Path targetPath = createTypeTargetPath(sourcedType, 
template.targetPath);
-        render(templateDirectory, template.name, templateData, targetPath);
+        templates.forEach(template -> {
+            final Path targetPath = createTypeTargetPath(sourcedType, 
template.targetPath);
+            render(templateDirectory, template.name, templateData, targetPath);
+        });
     }
 
     private static Path createTypeTargetPath(final ArtifactSourcedType 
sourcedType, final String targetPathPattern) {
@@ -72,8 +75,9 @@ public final class DocumentationGenerator {
     }
 
     private static void renderIndex(
-            final TypeLookup lookup, final Path templateDirectory, final 
DocumentationTemplate template) {
+            final TypeLookup lookup, final Path templateDirectory, final 
Set<DocumentationTemplate> templates) {
         final Map<String, Object> templateData = Map.of("lookup", lookup);
-        render(templateDirectory, template.name, templateData, 
Path.of(template.targetPath));
+        templates.forEach(
+                template -> render(templateDirectory, template.name, 
templateData, Path.of(template.targetPath)));
     }
 }
diff --git 
a/log4j-docgen/src/main/java/org/apache/logging/log4j/docgen/generator/DocumentationGeneratorArgs.java
 
b/log4j-docgen/src/main/java/org/apache/logging/log4j/docgen/generator/DocumentationGeneratorArgs.java
index f05d22a..6acf8bc 100644
--- 
a/log4j-docgen/src/main/java/org/apache/logging/log4j/docgen/generator/DocumentationGeneratorArgs.java
+++ 
b/log4j-docgen/src/main/java/org/apache/logging/log4j/docgen/generator/DocumentationGeneratorArgs.java
@@ -31,20 +31,20 @@ public final class DocumentationGeneratorArgs {
 
     final Path templateDirectory;
 
-    final DocumentationTemplate indexTemplate;
+    final Set<DocumentationTemplate> indexTemplates;
 
-    final DocumentationTemplate typeTemplate;
+    final Set<DocumentationTemplate> typeTemplates;
 
     public DocumentationGeneratorArgs(
             final Set<PluginSet> pluginSets,
             final Predicate<String> classNameFilter,
             final Path templateDirectory,
-            final DocumentationTemplate indexTemplate,
-            final DocumentationTemplate typeTemplate) {
+            final Set<DocumentationTemplate> indexTemplates,
+            final Set<DocumentationTemplate> typeTemplates) {
         this.pluginSets = requireNonNull(pluginSets, "pluginSets");
         this.classNameFilter = requireNonNull(classNameFilter, 
"classNameFilter");
         this.templateDirectory = requireNonNull(templateDirectory, 
"templateDirectory");
-        this.indexTemplate = requireNonNull(indexTemplate, "indexTemplate");
-        this.typeTemplate = requireNonNull(typeTemplate, "typeTemplate");
+        this.indexTemplates = requireNonNull(indexTemplates, "indexTemplates");
+        this.typeTemplates = requireNonNull(typeTemplates, "typeTemplates");
     }
 }
diff --git 
a/log4j-docgen/src/main/java/org/apache/logging/log4j/docgen/generator/DocumentationTemplate.java
 
b/log4j-docgen/src/main/java/org/apache/logging/log4j/docgen/generator/DocumentationTemplate.java
index 59219f0..32597f8 100644
--- 
a/log4j-docgen/src/main/java/org/apache/logging/log4j/docgen/generator/DocumentationTemplate.java
+++ 
b/log4j-docgen/src/main/java/org/apache/logging/log4j/docgen/generator/DocumentationTemplate.java
@@ -18,6 +18,8 @@ package org.apache.logging.log4j.docgen.generator;
 
 import static java.util.Objects.requireNonNull;
 
+import java.util.Objects;
+
 public final class DocumentationTemplate {
 
     final String name;
@@ -28,4 +30,21 @@ public final class DocumentationTemplate {
         this.name = requireNonNull(name, "name");
         this.targetPath = requireNonNull(targetPath, "targetPath");
     }
+
+    @Override
+    public boolean equals(Object instance) {
+        if (this == instance) {
+            return true;
+        }
+        if (instance == null || getClass() != instance.getClass()) {
+            return false;
+        }
+        DocumentationTemplate that = (DocumentationTemplate) instance;
+        return Objects.equals(name, that.name) && Objects.equals(targetPath, 
that.targetPath);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, targetPath);
+    }
 }
diff --git 
a/log4j-docgen/src/test/java/org/apache/logging/log4j/docgen/generator/DocumentationGeneratorTest.java
 
b/log4j-docgen/src/test/java/org/apache/logging/log4j/docgen/generator/DocumentationGeneratorTest.java
index 44d07d6..22322e1 100644
--- 
a/log4j-docgen/src/test/java/org/apache/logging/log4j/docgen/generator/DocumentationGeneratorTest.java
+++ 
b/log4j-docgen/src/test/java/org/apache/logging/log4j/docgen/generator/DocumentationGeneratorTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.logging.log4j.docgen.generator;
 
+import static java.util.Collections.singleton;
 import static 
org.apache.logging.log4j.docgen.generator.PluginSetUtils.readDescriptor;
 import static 
org.apache.logging.log4j.docgen.generator.PluginSetUtils.readDescriptors;
 import static 
org.apache.logging.log4j.tools.internal.test.util.FileTestUtils.assertDirectoryContentMatches;
@@ -58,10 +59,10 @@ class DocumentationGeneratorTest {
                 pluginSets,
                 className -> !className.startsWith("java."),
                 templateDirectory,
-                new DocumentationTemplate(
-                        "index.adoc.ftl", 
outputDir.resolve("index.adoc").toString()),
-                new DocumentationTemplate(
-                        "type.adoc.ftl", 
outputDir.resolve("%a/%c.adoc").toString()));
+                singleton(new DocumentationTemplate(
+                        "index.adoc.ftl", 
outputDir.resolve("index.adoc").toString())),
+                singleton(new DocumentationTemplate(
+                        "type.adoc.ftl", 
outputDir.resolve("%a/%c.adoc").toString())));
         DocumentationGenerator.generateDocumentation(generatorArgs);
 
         // Verify the output
diff --git a/log4j-tools-internal-freemarker-util/pom.xml 
b/log4j-tools-internal-freemarker-util/pom.xml
index 71b2b72..aeeb4c9 100644
--- a/log4j-tools-internal-freemarker-util/pom.xml
+++ b/log4j-tools-internal-freemarker-util/pom.xml
@@ -37,10 +37,24 @@
   </properties>
 
   <dependencies>
+
     <dependency>
       <groupId>org.freemarker</groupId>
       <artifactId>freemarker</artifactId>
     </dependency>
+
+    <dependency>
+      <groupId>org.junit.jupiter</groupId>
+      <artifactId>junit-jupiter-engine</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.assertj</groupId>
+      <artifactId>assertj-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+
   </dependencies>
 
 </project>
diff --git 
a/log4j-tools-internal-freemarker-util/src/main/java/org/apache/logging/log4j/tools/internal/freemarker/util/FreeMarkerUtils.java
 
b/log4j-tools-internal-freemarker-util/src/main/java/org/apache/logging/log4j/tools/internal/freemarker/util/FreeMarkerUtils.java
index ec9aec8..82c2bbc 100644
--- 
a/log4j-tools-internal-freemarker-util/src/main/java/org/apache/logging/log4j/tools/internal/freemarker/util/FreeMarkerUtils.java
+++ 
b/log4j-tools-internal-freemarker-util/src/main/java/org/apache/logging/log4j/tools/internal/freemarker/util/FreeMarkerUtils.java
@@ -23,6 +23,8 @@ import freemarker.template.DefaultObjectWrapper;
 import freemarker.template.DefaultObjectWrapperBuilder;
 import freemarker.template.Template;
 import freemarker.template.TemplateExceptionHandler;
+import freemarker.template.TemplateMethodModelEx;
+import freemarker.template.TemplateModelException;
 import freemarker.template.Version;
 import java.io.BufferedWriter;
 import java.io.IOException;
@@ -35,6 +37,7 @@ import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
+import java.util.List;
 
 public final class FreeMarkerUtils {
 
@@ -46,6 +49,52 @@ public final class FreeMarkerUtils {
 
     private FreeMarkerUtils() {}
 
+    private static final class StopMethod implements TemplateMethodModelEx {
+
+        private static final StopMethod INSTANCE = new StopMethod();
+
+        private static final TemplateModelException SIGNAL = new 
TemplateModelException();
+
+        @Override
+        public Object exec(final List arguments) throws TemplateModelException 
{
+            throw SIGNAL;
+        }
+
+        private static boolean invoked(final Throwable throwable) {
+
+            // Keep a second pointer that slowly walks the causal chain.
+            // If the fast pointer ever catches the slower pointer, then 
there's a loop.
+            Throwable slowPointer = throwable;
+            boolean advanceSlowPointer = false;
+
+            Throwable parent = throwable;
+            while (true) {
+
+                // Check the exception
+                if (parent == StopMethod.SIGNAL) {
+                    return true;
+                }
+
+                // Advance the cause
+                final Throwable cause = parent.getCause();
+                if (cause == null) {
+                    break;
+                }
+
+                // Advance pointers
+                parent = cause;
+                if (parent == slowPointer) {
+                    throw new IllegalArgumentException("loop in causal chain");
+                }
+                if (advanceSlowPointer) {
+                    slowPointer = slowPointer.getCause();
+                }
+                advanceSlowPointer = !advanceSlowPointer; // only advance 
every other iteration
+            }
+            return false;
+        }
+    }
+
     @SuppressFBWarnings("DMI_HARDCODED_ABSOLUTE_FILENAME")
     private static Configuration createConfiguration(final Path 
templateDirectory) {
         final Configuration configuration = new 
Configuration(CONFIGURATION_VERSION);
@@ -63,6 +112,7 @@ public final class FreeMarkerUtils {
         configuration.setLogTemplateExceptions(false);
         configuration.setWrapUncheckedExceptions(true);
         configuration.setFallbackOnNullLoopVariable(false);
+        configuration.setSharedVariable("stop", StopMethod.INSTANCE);
         return configuration;
     }
 
@@ -70,21 +120,31 @@ public final class FreeMarkerUtils {
     public static void render(
             final Path templateDirectory, final String templateName, final 
Object templateData, final Path outputFile) {
         try {
+
+            // Render the template
             final Configuration configuration = 
createConfiguration(templateDirectory);
             final Template template = configuration.getTemplate(templateName);
+            final StringWriter templateOutputWriter = new StringWriter();
+            template.process(templateData, templateOutputWriter);
+            final String templateOutput = templateOutputWriter.toString();
+
+            // Write the template output to the target file
             final Path outputFileParent = outputFile.getParent();
             if (outputFileParent != null) {
                 Files.createDirectories(outputFileParent);
             }
             try (final BufferedWriter outputFileWriter = 
Files.newBufferedWriter(
                     outputFile, CHARSET, StandardOpenOption.CREATE, 
StandardOpenOption.TRUNCATE_EXISTING)) {
-                template.process(templateData, outputFileWriter);
+                outputFileWriter.write(templateOutput);
             }
         } catch (final Exception error) {
-            final String message = String.format(
-                    "failed rendering template `%s` in directory `%s` to file 
`%s`",
-                    templateName, templateDirectory, outputFile);
-            throw new RuntimeException(message, error);
+            final boolean stopMethodInvoked = StopMethod.invoked(error);
+            if (!stopMethodInvoked) {
+                final String message = String.format(
+                        "failed rendering template `%s` in directory `%s` to 
file `%s`",
+                        templateName, templateDirectory, outputFile);
+                throw new RuntimeException(message, error);
+            }
         }
     }
 
diff --git 
a/log4j-tools-internal-freemarker-util/src/test/java/org/apache/logging/log4j/tools/internal/freemarker/util/FreeMarkerUtilsTest.java
 
b/log4j-tools-internal-freemarker-util/src/test/java/org/apache/logging/log4j/tools/internal/freemarker/util/FreeMarkerUtilsTest.java
new file mode 100644
index 0000000..5aeb65d
--- /dev/null
+++ 
b/log4j-tools-internal-freemarker-util/src/test/java/org/apache/logging/log4j/tools/internal/freemarker/util/FreeMarkerUtilsTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.logging.log4j.tools.internal.freemarker.util;
+
+import static java.nio.file.Files.write;
+import static 
org.apache.logging.log4j.tools.internal.freemarker.util.FreeMarkerUtils.render;
+import static 
org.apache.logging.log4j.tools.internal.freemarker.util.FreeMarkerUtils.renderString;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.Collections;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.CleanupMode;
+import org.junit.jupiter.api.io.TempDir;
+
+class FreeMarkerUtilsTest {
+
+    @Test
+    void render_should_work(@TempDir(cleanup = CleanupMode.ON_SUCCESS) final 
Path tempDir) throws Exception {
+
+        // Create the template file
+        final String templateName = "test.txt.ftl";
+        final Path templateFile = tempDir.resolve(templateName);
+        write(
+                templateFile,
+                "Hello, ${name?capitalize}!".getBytes(StandardCharsets.UTF_8),
+                StandardOpenOption.CREATE_NEW);
+
+        // Render the template
+        final Path outputFile = tempDir.resolve("test.txt");
+        render(tempDir, templateName, Collections.singletonMap("name", 
"volkan"), outputFile);
+
+        // Verify the generated content
+        assertThat(outputFile).hasContent("Hello, Volkan!");
+    }
+
+    @Test
+    void render_should_stop(@TempDir(cleanup = CleanupMode.ON_SUCCESS) final 
Path tempDir) throws Exception {
+
+        // Create the template file
+        final String templateName = "test.txt.ftl";
+        final Path templateFile = tempDir.resolve(templateName);
+        final String excessiveContentToEnsureSuccessIsNotDueToBuffering = 
String.format("%010000d\n", 1);
+        final String templateFileContent = 
excessiveContentToEnsureSuccessIsNotDueToBuffering
+                + "You might expect awesome things to get rendered.\nBut I 
tell you: they won't.\n${stop()}";
+        write(templateFile, 
templateFileContent.getBytes(StandardCharsets.UTF_8), 
StandardOpenOption.CREATE_NEW);
+
+        // Render the template
+        final Path outputFile = tempDir.resolve("test.txt");
+        render(tempDir, templateName, Collections.singletonMap("name", 
"volkan"), outputFile);
+
+        // Verify the generated content
+        assertThat(outputFile).doesNotExist();
+    }
+
+    @Test
+    void renderString_should_work() {
+        final String output = renderString("Hello, ${name?capitalize}!", 
Collections.singletonMap("name", "volkan"));
+        assertThat(output).isEqualTo("Hello, Volkan!");
+    }
+}
diff --git a/src/changelog/.0.x.x/add-freemarker-stop-method.xml 
b/src/changelog/.0.x.x/add-freemarker-stop-method.xml
new file mode 100644
index 0000000..a7b4093
--- /dev/null
+++ b/src/changelog/.0.x.x/add-freemarker-stop-method.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xmlns="https://logging.apache.org/xml/ns";
+       xsi:schemaLocation="https://logging.apache.org/xml/ns 
https://logging.apache.org/xml/ns/log4j-changelog-0.xsd";
+       type="added">
+  <issue id="122" 
link="https://github.com/apache/logging-log4j-tools/pull/122"/>
+  <description format="asciidoc">Add `stop()` FreeMarker method to skip 
template file generation.
+A use case is to have multiple `typeTemplates` in the 
`log4j-docgen:generate-documentation` configuration and skip generating certain 
files if desired.</description>
+</entry>
diff --git a/src/changelog/.0.x.x/add-multi-doc-generator-template.xml 
b/src/changelog/.0.x.x/add-multi-doc-generator-template.xml
new file mode 100644
index 0000000..9863f96
--- /dev/null
+++ b/src/changelog/.0.x.x/add-multi-doc-generator-template.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xmlns="https://logging.apache.org/xml/ns";
+       xsi:schemaLocation="https://logging.apache.org/xml/ns 
https://logging.apache.org/xml/ns/log4j-changelog-0.xsd";
+       type="added">
+  <issue id="122" 
link="https://github.com/apache/logging-log4j-tools/pull/122"/>
+  <description format="asciidoc">Support multiple index and type templates in 
the `log4j-docgen:generate-documentation` configuration</description>
+</entry>
diff --git 
a/src/site/antora/modules/ROOT/pages/log4j-docgen-asciidoctor-extension.adoc 
b/src/site/antora/modules/ROOT/pages/log4j-docgen-asciidoctor-extension.adoc
index 0b6ba93..a3e69de 100644
--- a/src/site/antora/modules/ROOT/pages/log4j-docgen-asciidoctor-extension.adoc
+++ b/src/site/antora/modules/ROOT/pages/log4j-docgen-asciidoctor-extension.adoc
@@ -49,6 +49,7 @@ That is, if `true`, `apiref:some.unknown.Class[]` will be 
converted to `<code>Cl
 Note that this only applies to types where the label is not provided.
 This flag is disabled by default.
 
+[#log4j-docgen-type-target-template]
 `log4j-docgen-type-target-template`::
 The FreeMarker template to produce the link target for individual types 
documented, for instance:
 +
diff --git a/src/site/antora/modules/ROOT/pages/log4j-docgen-maven-plugin.adoc 
b/src/site/antora/modules/ROOT/pages/log4j-docgen-maven-plugin.adoc
index 7b7f623..7b72844 100644
--- a/src/site/antora/modules/ROOT/pages/log4j-docgen-maven-plugin.adoc
+++ b/src/site/antora/modules/ROOT/pages/log4j-docgen-maven-plugin.adoc
@@ -56,18 +56,24 @@ The `generate-documentation` goal generates an 
AsciiDoc-formatted documentation
   </typeFilter>
 
   
<templateDirectory>${project.basedir}/src/docgen-templates</templateDirectory>
-  <indexTemplate>
-    <source>index.adoc.ftl</source>
-    
<target>${project.build.directory}/generated-site/asciidoc/plugin-reference/index.adoc</target>
-  </indexTemplate>
-  <typeTemplate>
-    <source>type.adoc.ftl</source>
-    <!-- `target` must be in sync. with the 
`log4j-docgen-type-template-target` configuration of 
`log4j-docgen-asciidoctor-extension`! -->
-    
<target>${project.build.directory}/generated-site/asciidoc/plugin-reference/%g/%a/%c.adoc</target>
-  </typeTemplate>
+
+  <indexTemplates>
+    <template>
+      <source>index.adoc.ftl</source>
+      
<target>${project.build.directory}/generated-site/asciidoc/plugin-reference/index.adoc</target>
+    </template>
+  </indexTemplates>
+
+  <typeTemplates>
+    <template>
+      <source>type.adoc.ftl</source>
+      
<target>${project.build.directory}/generated-site/asciidoc/plugin-reference/%g/%a/%c.adoc</target><!--1-->
+    </template>
+  </typeTemplates>
 
 </configuration>
 ----
+<1> `target` must be in sync. with 
xref:log4j-docgen-asciidoctor-extension.adoc#log4j-docgen-type-target-template[the
 `log4j-docgen-type-target-template` configuration of 
`log4j-docgen-asciidoctor-extension`].
 
 The `generate-documentation` goal configuration also accepts the following 
parameters:
 

Reply via email to