diff --git a/pom.xml b/pom.xml index db44116..5830915 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.whelk.asciidoc asciidoc-template-maven-plugin - 1.0.7-RELEASE + 1.0.8-SNAPSHOT maven-plugin Asciidoc Template Plugin @@ -67,6 +67,17 @@ 1.18.12 provided + + org.junit.jupiter + junit-jupiter-api + 5.7.0-RC1 + test + + + org.assertj + assertj-core + 3.16.1 + diff --git a/src/main/java/io/whelk/asciidoc/TemplateMojo.java b/src/main/java/io/whelk/asciidoc/TemplateMojo.java index ab89b60..a8fdfc0 100644 --- a/src/main/java/io/whelk/asciidoc/TemplateMojo.java +++ b/src/main/java/io/whelk/asciidoc/TemplateMojo.java @@ -2,9 +2,16 @@ import java.nio.file.Files; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; +import lombok.Value; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -14,10 +21,15 @@ import org.apache.maven.project.MavenProject; import lombok.SneakyThrows; +import org.assertj.core.util.VisibleForTesting; @Mojo(name = "build", defaultPhase = LifecyclePhase.PACKAGE) public class TemplateMojo extends AbstractMojo { + public static final String TAG = "tag"; + + public static final String TAG_END = "end"; + @Parameter(property = "templateDirectory") String templateDirectory; @@ -45,10 +57,8 @@ public void execute() throws MojoExecutionException, MojoFailureException { @SneakyThrows private List readLines(String first, String... more) { - return Files - .readAllLines(Paths.get(first, more)) - .stream() - .collect(Collectors.toList()); + return new ArrayList<>(Files + .readAllLines(Paths.get(first, more))); } private List updateLines(List lines) { @@ -67,13 +77,62 @@ private List updateLine(final String line) { } private boolean matchesIncludeLine(final String line) { - return line.startsWith("include::") && - line.endsWith(".adoc[]"); + return line.startsWith("include::") && + line.endsWith("]"); + } + + @VisibleForTesting + List updateIncludeLine(final String line) { + var pathAndOptions = extractPathAndOptions(line); + if (pathAndOptions.optionMap.containsKey(TAG)) { + return readTaggedLines(templateDirectory, pathAndOptions); + } + return this.readLines(templateDirectory, pathAndOptions.path); + } + + @SneakyThrows + private List readTaggedLines(String templateDirectory, PathAndOptions path) { + ArrayList lines = new ArrayList<>(Files + .readAllLines(Paths.get(templateDirectory, path.path))); + String tag = path.optionMap.get(TAG); + AtomicReference startHasBeenReached = new AtomicReference<>(false); + AtomicReference endHasBeenReached = new AtomicReference<>(false); + List taggedLines = lines.stream().filter(x -> { + boolean foundStart = x.contains(TAG + "::" + tag); + boolean foundEnd = x.contains(TAG_END + "::" + tag); + if (!startHasBeenReached.get()) { + startHasBeenReached.set(foundStart); + } + if (startHasBeenReached.get() && !endHasBeenReached.get()) { + endHasBeenReached.set(foundEnd); + } + boolean thisIsATagLine = foundStart || foundEnd; + return !thisIsATagLine && startHasBeenReached.get() && !endHasBeenReached.get(); + }).collect(Collectors.toList()); + return taggedLines; + } + + @Value + static + class PathAndOptions { + String path; + Map optionMap; } - private List updateIncludeLine(final String line) { - var path = line.substring(9, line.length() - 2); - return this.readLines(templateDirectory, path); + @VisibleForTesting + PathAndOptions extractPathAndOptions(String line) { + int pathStart = 9; + Pattern pattern = Pattern.compile("\\[.*\\]$"); + Matcher matcher = pattern.matcher(line); + boolean found = matcher.find(); + String[] allOptions = matcher.group().replaceAll("[\\[\\]]", "").split(","); + Map optionMap = Arrays.asList(allOptions).stream() + .filter(x -> x.trim().length() > 0) + .map(x -> x.split("=")) + .collect(Collectors.toMap(x -> x[0], x -> x[1])); + int pathEnd = matcher.start(); + String path = line.substring(pathStart, pathEnd); + return new PathAndOptions(path, optionMap); } private void setDefaultConfiguration() { diff --git a/src/test/java/io/whelk/asciidoc/TemplateMojoTest.java b/src/test/java/io/whelk/asciidoc/TemplateMojoTest.java new file mode 100644 index 0000000..5010194 --- /dev/null +++ b/src/test/java/io/whelk/asciidoc/TemplateMojoTest.java @@ -0,0 +1,37 @@ +package io.whelk.asciidoc; + +import io.whelk.asciidoc.TemplateMojo.PathAndOptions; + +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +public class TemplateMojoTest { + + // tag::exampleShort[] + String test = "this is a small test"; + // end::exampleShort[] + + @Test + void testFilePathExtraction() { + TemplateMojo templateMojo = new TemplateMojo(); + + assertThat(templateMojo.extractPathAndOptions("include::otherFile.adoc[]")) + .isEqualTo(new PathAndOptions("otherFile.adoc", Map.of())); + + assertThat(templateMojo.extractPathAndOptions("include::src/test/java/io/whelk/asciidoc/TemplateMojoTest.java[tag=exampleShort]")) + .isEqualTo(new PathAndOptions("src/test/java/io/whelk/asciidoc/TemplateMojoTest.java", Map.of("tag", "exampleShort"))); + } + + @Test + void includeJavaCode() { + TemplateMojo templateMojo = new TemplateMojo(); + templateMojo.templateDirectory = "./"; + + assertThat(templateMojo.updateIncludeLine("include::src/test/java/io/whelk/asciidoc/TemplateMojoTest.java[tag=exampleShort]")) + .containsOnly(" String test = \"this is a small test\";"); + } + +}