Skip to content

Commit

Permalink
Adds support for multi-line macro inputs. Makes MacroUtils more modul…
Browse files Browse the repository at this point in the history
…ar. Adds rawTest macro. Fix #1524. (#1528)
  • Loading branch information
AndreaLaGrotteria authored Oct 25, 2024
1 parent 464442c commit aeb98f2
Show file tree
Hide file tree
Showing 10 changed files with 279 additions and 111 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package io.micronaut.guides.core;

import java.util.List;

public interface GuidesConfiguration {
String getHomePageUrl();
String getTitle();
String getLicensePath();
String getPackageName();
List<String> getFilesWithHeader();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import io.micronaut.context.annotation.ConfigurationProperties;

import java.util.List;

@ConfigurationProperties(GuidesConfigurationProperties.PREFIX)
public class GuidesConfigurationProperties implements GuidesConfiguration {
public static final String PREFIX = "guides";
Expand All @@ -12,6 +14,7 @@ public class GuidesConfigurationProperties implements GuidesConfiguration {
private static final String DEFAULT_PACKAGE_NAME = "example.micronaut";
private String licensePath = DEFAULT_LICENSEHEADER;
private String packageName = DEFAULT_PACKAGE_NAME;
private List<String> sourceFilesExtensions = List.of("java", "kotlin", "groovy");

@Override
public String getPackageName() {
Expand Down Expand Up @@ -48,4 +51,13 @@ public String getTitle() {
public void setTitle(String title) {
this.title = title;
}

@Override
public List<String> getFilesWithHeader() {
return sourceFilesExtensions;
}

public void setFilesWithHeader(List<String> sourceFilesExtensions) {
this.sourceFilesExtensions = sourceFilesExtensions;
}
}
124 changes: 75 additions & 49 deletions buildSrc/src/main/java/io/micronaut/guides/core/MacroUtils.java
Original file line number Diff line number Diff line change
@@ -1,37 +1,45 @@
package io.micronaut.guides.core;

import io.micronaut.core.annotation.NonNull;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.util.StringUtils;

import java.nio.file.Paths;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static io.micronaut.starter.api.TestFramework.SPOCK;

public final class MacroUtils {
private MacroUtils() {
}

@NonNull
public static String getSourceDir(@NonNull String slug, @NonNull GuidesOption option) {
return slug + "-" + option.getBuildTool() + "-" + option.getLanguage();
}

/**
* Adds include directives to the list of lines for the given source path and tags.
*
* @param option The {@link GuidesOption} containing the build tool and language.
* @param slug The slug representing the guide, which will be used as root folder.
* @param sourcePath The path to the source file from the guide's project root.
* @param licenseLoader The {@link LicenseLoader} to calculate the line offset. If null no line offset is added.
* @param extension The file extension of the source file.
* @param indent The indent value for the include directive. If empty no indent is added.
* @param tags The list of tags for the include directive.
* @return A list of lines with include directives.
*/
@NonNull
public static List<String> addIncludes(@NonNull GuidesOption option,
@NonNull LicenseLoader licenseLoader,
@NonNull GuidesConfiguration configuration,
@NonNull String slug,
@NonNull String sourcePath,
@NonNull LicenseLoader licenseLoader,
String indent,
@NonNull String extension,
@Nullable String indent,
@NonNull List<String> tags) {
String sourceDir = getSourceDir(slug, option);
List<String> lines = new ArrayList<>();
lines.add("[source," + option.getLanguage().toString() + "]");
String normalizedSourcePath = Paths.get(sourcePath).normalize().toString();
lines.add("." + normalizedSourcePath);
lines.add("[source," + extension + "]");
Path path = Path.of(slug, sourceDir, sourcePath);
lines.add("." + path.normalize().toString().replace(slug+"/"+sourceDir+"/", ""));
lines.add("----");

if (!tags.isEmpty()) {
Expand All @@ -40,20 +48,49 @@ public static List<String> addIncludes(@NonNull GuidesOption option,
if (StringUtils.isNotEmpty(indent)) {
attrs += "," + indent;
}
lines.add("include::{sourceDir}/" + slug + "/" + sourceDir + "/" + sourcePath + "[" + attrs + "]\n");
lines.add("include::{sourceDir}/" + path + "[" + attrs + "]\n");
}
} else {
List<String> attributes = new ArrayList<>();
attributes.add("lines=" + licenseLoader.getNumberOfLines() + "..-1");
if (fileContainsHeader(extension, configuration) && licenseLoader.getNumberOfLines() > 0) {
attributes.add("lines=" + licenseLoader.getNumberOfLines() + "..-1");
}
if (StringUtils.isNotEmpty(indent)) {
attributes.add(indent);
}
lines.add("include::{sourceDir}/" + slug + "/"+sourceDir+"/" + sourcePath + "[" + String.join(";", attributes) + "]");
lines.add("include::{sourceDir}/" + path + "[" + String.join(";", attributes) + "]");
}
lines.add("----\n");
lines.add("----");
return lines;
}

/**
* Adds include directives to the list of lines for the given source path and tags.
*
* @param option The {@link GuidesOption} containing the build tool and language.
* @param slug The slug representing the guide, which will be used as root folder.
* @param sourcePath The path to the source file from the guide's project root.
* @param licenseLoader The {@link LicenseLoader} to calculate the line offset.
* @param indent The indent value for the include directive. If empty no indent is added.
* @param tags The list of tags for the include directive.
* @return A list of lines with include directives.
*/
@NonNull
public static List<String> addIncludes(@NonNull GuidesOption option,
@NonNull LicenseLoader licenseLoader,
@NonNull GuidesConfiguration configuration,
@NonNull String slug,
@NonNull String sourcePath,
@NonNull String indent,
@NonNull List<String> tags) {
return addIncludes(option, licenseLoader, configuration, slug, sourcePath, option.getLanguage().toString(), indent, tags);
}

@NonNull
static String getSourceDir(@NonNull String slug, @NonNull GuidesOption option) {
return slug + "-" + option.getBuildTool() + "-" + option.getLanguage();
}

@NonNull
public static String extractName(@NonNull String line, @NonNull String macro) {
return line.substring(macro.length() + 1, line.indexOf('['));
Expand All @@ -68,49 +105,28 @@ public static String extractAppName(@NonNull String line) {
public static List<String> extractTags(@NonNull String line) {
String attributeValue = extractFromParametersLine(line, "tags");
if (StringUtils.isNotEmpty(attributeValue)) {
return Arrays.asList(attributeValue.split("\\|"));
return Arrays.stream(attributeValue.split("\\|")).map(it -> "tag=" + it).toList();
}

return extractTagName(line).isEmpty() ? Collections.emptyList() : Collections.singletonList(extractTagName(line));
}

@NonNull
public static String mainPath(@NonNull GuidesConfiguration guidesConfiguration,
@NonNull String appName,
@NonNull String fileName,
GuidesOption option) {
return pathByFolder(guidesConfiguration, appName, fileName, "main", option);
attributeValue = extractTagName(line);
return attributeValue.isEmpty() ? Collections.emptyList() : Collections.singletonList("tag="+attributeValue);
}

@NonNull
static String testPath(@NonNull GuidesConfiguration guidesConfiguration,
@NonNull String appName,
@NonNull String name,
GuidesOption option) {
String fileName = name;

if (name.endsWith("Test")) {
fileName = name.substring(0, name.indexOf("Test"));
fileName += option.getTestFramework() == SPOCK ? "Spec" : "Test";
}

return pathByFolder(guidesConfiguration, appName, fileName, "test", option);
}

@NonNull
private static String pathByFolder(@NonNull GuidesConfiguration guidesConfiguration,
@NonNull String appName,
@NonNull String fileName,
String folder,
GuidesOption option) {
String module = !appName.isEmpty() ? appName + "/" : "";
return module+"src/"+folder+"/"+option.getLanguage().toString()+"/" + guidesConfiguration.getPackageName().replace(".", "/") + "/"+fileName+"."+option.getLanguage().getExtension();
static String pathByFolder(@NonNull GuidesConfiguration guidesConfiguration,
@NonNull String appName,
@NonNull String fileName,
@NonNull String folder,
@NonNull GuidesOption option) {
String module = appName.isEmpty() ? "" : appName + "/";
return module + "src/" + folder + "/" + option.getLanguage().toString() + "/" + guidesConfiguration.getPackageName().replace(".", "/") + "/" +fileName + "." + option.getLanguage().getExtension();
}

@NonNull
public static String extractIndent(@NonNull String line) {
String indentValue = extractFromParametersLine(line, "indent");
return !indentValue.isEmpty() ? "indent="+indentValue : "";
return !indentValue.isEmpty() ? "indent=" + indentValue : "";
}

@NonNull
Expand All @@ -129,4 +145,14 @@ static String extractFromParametersLine(@NonNull String line, @NonNull String at
.findFirst()
.orElse("");
}

static boolean fileContainsHeader(@NonNull String extension, @NonNull GuidesConfiguration configuration) {
return configuration.getFilesWithHeader().contains(extension);
}

static List<String> findMacroLines(@NonNull String str, @NonNull String macro) {
return str.lines()
.filter(line -> line.startsWith(macro+":"))
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package io.micronaut.guides.core;

import io.micronaut.core.annotation.NonNull;
import jakarta.inject.Singleton;
import java.util.List;

import static io.micronaut.guides.core.MacroUtils.*;
import static io.micronaut.guides.core.MacroUtils.addIncludes;

@Singleton
public class RawTestMacroSubstitution implements MacroSubstitution{

private final GuidesConfiguration guidesConfiguration;
private final LicenseLoader licenseLoader;

public RawTestMacroSubstitution(GuidesConfiguration guidesConfiguration, LicenseLoader licenseLoader) {
this.guidesConfiguration = guidesConfiguration;
this.licenseLoader = licenseLoader;
}

@Override
public String substitute(String str, String slug, GuidesOption option) {
for(String line : findMacroLines(str, "rawTest")) {

String name = extractName(line, "rawTest");
String appName = extractAppName(line);
List<String> tags = extractTags(line);
String indent = extractIndent(line);
String sourcePath = rawTestPath(guidesConfiguration, appName, name, option);

List<String> lines = addIncludes(option, licenseLoader, guidesConfiguration, slug, sourcePath, option.getTestFramework().toTestFramework().getDefaultLanguage().getExtension(), indent, tags);

str = str.replace(line,String.join("\n", lines));
}
return str;
}

@NonNull
private static String rawTestPath(@NonNull GuidesConfiguration guidesConfiguration,
@NonNull String appName,
@NonNull String name,
@NonNull GuidesOption option) {
String module = appName.isEmpty() ? "" : appName + "/";
String fileExtension = option.getTestFramework().toTestFramework().getDefaultLanguage().getExtension();
String langTestFolder = option.getTestFramework().toTestFramework().getDefaultLanguage().getTestSrcDir();
return module + langTestFolder + "/" + guidesConfiguration.getPackageName().replace(".", "/") + "/" + name + "." + fileExtension;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package io.micronaut.guides.core;

import io.micronaut.core.annotation.NonNull;
import jakarta.inject.Singleton;

import java.util.Collections;
import java.util.List;

import static io.micronaut.guides.core.MacroUtils.*;
Expand All @@ -20,20 +19,26 @@ public SourceMacroSubstitution(GuidesConfiguration guidesConfiguration, LicenseL

@Override
public String substitute(String str, String slug, GuidesOption option) {
String name = extractName(str, "source");
String appName = extractAppName(str);

List<String> tagNames = extractTags(str);
List<String> tags = (tagNames != null && !tagNames.isEmpty())
? tagNames.stream().map(it -> "tag=" + it).toList()
: Collections.emptyList();
for(String line : findMacroLines(str, "source")){

String indent = extractIndent(str);
String name = extractName(line, "source");
String appName = extractAppName(line);
List<String> tags = extractTags(line);
String indent = extractIndent(line);
String sourcePath = mainPath(guidesConfiguration, appName, name, option);

String sourcePath = mainPath(guidesConfiguration, appName, name, option);
List<String> lines = addIncludes(option, licenseLoader, guidesConfiguration, slug, sourcePath, indent, tags);

List<String> lines = addIncludes(option, slug, sourcePath, licenseLoader, indent, tags);
str = str.replace(line,String.join("\n", lines));
}
return str;
}

return String.join("\n", lines);
@NonNull
private static String mainPath(@NonNull GuidesConfiguration guidesConfiguration,
@NonNull String appName,
@NonNull String fileName,
@NonNull GuidesOption option) {
return pathByFolder(guidesConfiguration, appName, fileName, "main", option);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package io.micronaut.guides.core;

import io.micronaut.core.annotation.NonNull;
import jakarta.inject.Singleton;

import java.util.Collections;
import java.util.List;

import static io.micronaut.guides.core.MacroUtils.*;
import static io.micronaut.starter.api.TestFramework.SPOCK;

@Singleton
public class TestMacroSubstitution implements MacroSubstitution{
Expand All @@ -20,20 +20,33 @@ public TestMacroSubstitution(GuidesConfiguration guidesConfiguration, LicenseLoa

@Override
public String substitute(String str, String slug, GuidesOption option) {
String name = extractName(str, "test");
String appName = extractAppName(str);
for(String line : findMacroLines(str, "test")){

String name = extractName(line, "test");
String appName = extractAppName(line);
List<String> tags = extractTags(line);
String indent = extractIndent(line);
String sourcePath = testPath(guidesConfiguration, appName, name, option);

List<String> tagNames = extractTags(str);
List<String> tags = (tagNames != null && !tagNames.isEmpty())
? tagNames.stream().map(it -> "tag=" + it).toList()
: Collections.emptyList();
List<String> lines = addIncludes(option, licenseLoader, guidesConfiguration, slug, sourcePath, indent, tags);

String indent = extractIndent(str);
str = str.replace(line,String.join("\n", lines));
}
return str;
}

String sourcePath = testPath(guidesConfiguration, appName, name, option);
@NonNull
private static String testPath(@NonNull GuidesConfiguration guidesConfiguration,
@NonNull String appName,
@NonNull String name,
@NonNull GuidesOption option) {
String fileName = name;

List<String> lines = addIncludes(option, slug, sourcePath, licenseLoader, indent, tags);
if (name.endsWith("Test")) {
fileName = name.substring(0, name.indexOf("Test"));
fileName += option.getTestFramework() == SPOCK ? "Spec" : "Test";
}

return String.join("\n", lines);
return pathByFolder(guidesConfiguration, appName, fileName, "test", option);
}
}
Loading

0 comments on commit aeb98f2

Please sign in to comment.