Skip to content

Commit

Permalink
Generate Quarkus Maven Plugin Config Docs
Browse files Browse the repository at this point in the history
resolves: quarkusio#1204
  • Loading branch information
michalvavrik authored and Alasdair Preston committed Sep 14, 2022
1 parent 9bfd447 commit f7b6773
Show file tree
Hide file tree
Showing 12 changed files with 437 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ final public class Constants {
public static final String DASH = "-";
public static final String ADOC_EXTENSION = ".adoc";
public static final String DIGIT_OR_LOWERCASE = "^[a-z0-9]+$";
public static final String NEW_LINE = "\n";
public static final String SECTION_TITLE_L1 = "= ";

public static final String PARENT = "<<parent>>";
public static final String NO_DEFAULT = "<<no default>>";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.quarkus.annotation.processor.generate_doc;

import java.io.IOException;
import java.io.Writer;
import java.util.List;

/**
* Represent one output file, its items are going to be appended to the file
*/
interface ConfigDoc {

List<WriteItem> getWriteItems();

/**
* An item is a summary table, note below the table, ...
*/
interface WriteItem {
void accept(Writer writer) throws IOException;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package io.quarkus.annotation.processor.generate_doc;

import static io.quarkus.annotation.processor.Constants.SUMMARY_TABLE_ID_VARIABLE;
import static java.util.Objects.requireNonNull;

import java.util.ArrayList;
import java.util.List;

import io.quarkus.annotation.processor.Constants;

/**
* {@link ConfigDoc} builder
*/
class ConfigDocBuilder {

/**
* Declare AsciiDoc variable
*/
private static final String DECLARE_VAR = "\n:%s: %s\n";
private final DocFormatter summaryTableDocFormatter;
protected final List<ConfigDoc.WriteItem> writeItems = new ArrayList<>();

public ConfigDocBuilder() {
summaryTableDocFormatter = new SummaryTableDocFormatter();
}

protected ConfigDocBuilder(boolean showEnvVars) {
summaryTableDocFormatter = new SummaryTableDocFormatter(showEnvVars);
}

/**
* Add documentation in a summary table and descriptive format
*/
public final ConfigDocBuilder addSummaryTable(String initialAnchorPrefix, boolean activateSearch,
List<ConfigDocItem> configDocItems, String fileName,
boolean includeConfigPhaseLegend) {

writeItems.add(writer -> {

// Create var with unique value for each summary table that will make DURATION_FORMAT_NOTE (see below) unique
var fileNameWithoutExtension = fileName.substring(0, fileName.length() - Constants.ADOC_EXTENSION.length());
writer.append(String.format(DECLARE_VAR, SUMMARY_TABLE_ID_VARIABLE, fileNameWithoutExtension));

summaryTableDocFormatter.format(writer, initialAnchorPrefix, activateSearch, configDocItems,
includeConfigPhaseLegend);

boolean hasDuration = false, hasMemory = false;
for (ConfigDocItem item : configDocItems) {
if (item.hasDurationInformationNote()) {
hasDuration = true;
}

if (item.hasMemoryInformationNote()) {
hasMemory = true;
}
}

if (hasDuration) {
writer.append(Constants.DURATION_FORMAT_NOTE);
}

if (hasMemory) {
writer.append(Constants.MEMORY_SIZE_FORMAT_NOTE);
}
});
return this;
}

public boolean hasWriteItems() {
return !writeItems.isEmpty();
}

/**
* Passed strings are appended to the file
*/
public final ConfigDocBuilder write(String... strings) {
requireNonNull(strings);
writeItems.add(writer -> {
for (String str : strings) {
writer.append(str);
}
});
return this;
}

public final ConfigDoc build() {
final List<ConfigDoc.WriteItem> docItemsCopy = List.copyOf(writeItems);
return () -> docItemsCopy;
}

}
Original file line number Diff line number Diff line change
@@ -1,65 +1,47 @@
package io.quarkus.annotation.processor.generate_doc;

import static io.quarkus.annotation.processor.Constants.SUMMARY_TABLE_ID_VARIABLE;

import java.io.IOException;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

import io.quarkus.annotation.processor.Constants;

final public class ConfigDocWriter {
private final DocFormatter summaryTableDocFormatter = new SummaryTableDocFormatter();
private static final String DECLARE_VAR = "\n:%s: %s\n";

/**
* Write all extension configuration in AsciiDoc format in `{root}/target/asciidoc/generated/config/` directory
*/
public void writeAllExtensionConfigDocumentation(ConfigDocGeneratedOutput output)
throws IOException {
generateDocumentation(Constants.GENERATED_DOCS_PATH.resolve(output.getFileName()), output.getAnchorPrefix(),
output.isSearchable(), output.getConfigDocItems(), output.getFileName());
}

/**
* Generate documentation in a summary table and descriptive format
*
*/
private void generateDocumentation(Path targetPath, String initialAnchorPrefix, boolean activateSearch,
List<ConfigDocItem> configDocItems, String fileName)
throws IOException {
if (configDocItems.isEmpty()) {
if (output.getConfigDocItems().isEmpty()) {
return;
}

try (Writer writer = Files.newBufferedWriter(targetPath)) {

// Create var with unique value for each summary table that will make DURATION_FORMAT_NOTE (see below) unique
var fileNameWithoutExtension = fileName.substring(0, fileName.length() - Constants.ADOC_EXTENSION.length());
writer.append(String.format(DECLARE_VAR, SUMMARY_TABLE_ID_VARIABLE, fileNameWithoutExtension));

summaryTableDocFormatter.format(writer, initialAnchorPrefix, activateSearch, configDocItems);
// Create single summary table
final var configDocBuilder = new ConfigDocBuilder().addSummaryTable(output.getAnchorPrefix(), output.isSearchable(),
output.getConfigDocItems(), output.getFileName(), true);

boolean hasDuration = false, hasMemory = false;
for (ConfigDocItem item : configDocItems) {
if (item.hasDurationInformationNote()) {
hasDuration = true;
}

if (item.hasMemoryInformationNote()) {
hasMemory = true;
}
}
generateDocumentation(output.getFileName(), configDocBuilder);
}

if (hasDuration) {
writer.append(Constants.DURATION_FORMAT_NOTE);
}
public void generateDocumentation(String fileName, ConfigDocBuilder configDocBuilder) throws IOException {
generateDocumentation(
// Resolve output file path
Constants.GENERATED_DOCS_PATH.resolve(fileName),
// Write all items
configDocBuilder.build());
}

if (hasMemory) {
writer.append(Constants.MEMORY_SIZE_FORMAT_NOTE);
private void generateDocumentation(Path targetPath, ConfigDoc configDoc)
throws IOException {
try (Writer writer = Files.newBufferedWriter(targetPath)) {
for (ConfigDoc.WriteItem writeItem : configDoc.getWriteItems()) {
// Write documentation item, f.e. summary table
writeItem.accept(writer);
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ default String getAnchor(String string) {
return string.toLowerCase();
}

void format(Writer writer, String initialAnchorPrefix, boolean activateSearch, List<ConfigDocItem> configDocItems)
throws IOException;
void format(Writer writer, String initialAnchorPrefix, boolean activateSearch, List<ConfigDocItem> configDocItems,
boolean includeConfigPhaseLegend) throws IOException;

void format(Writer writer, ConfigDocKey configDocKey) throws IOException;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ final class JavaDocParser {
private static final Pattern START_OF_LINE = Pattern.compile("^", Pattern.MULTILINE);
private static final Pattern REPLACE_WINDOWS_EOL = Pattern.compile("\r\n");
private static final Pattern REPLACE_MACOS_EOL = Pattern.compile("\r");
private static final Pattern STARTING_SPACE = Pattern.compile("^ +");

private static final String BACKTICK = "`";
private static final String HASH = "#";
Expand Down Expand Up @@ -269,7 +270,21 @@ private void appendHtml(StringBuilder sb, Node node) {
sb.append(NEW_LINE);
break;
case TEXT_NODE:
appendEscapedAsciiDoc(sb, ((TextNode) childNode).text());
String text = ((TextNode) childNode).text();

if (text.isEmpty()) {
break;
}

// Indenting the first line of a paragraph by one or more spaces makes the block literal
// Please see https://docs.asciidoctor.org/asciidoc/latest/verbatim/literal-blocks/ for more info
// This prevents literal blocks f.e. after <br>
final var startingSpaceMatcher = STARTING_SPACE.matcher(text);
if (sb.length() > 0 && '\n' == sb.charAt(sb.length() - 1) && startingSpaceMatcher.find()) {
text = startingSpaceMatcher.replaceFirst("");
}

appendEscapedAsciiDoc(sb, text);
break;
default:
appendHtml(sb, childNode);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package io.quarkus.annotation.processor.generate_doc;

import static io.quarkus.annotation.processor.Constants.EMPTY;
import static io.quarkus.annotation.processor.Constants.NEW_LINE;
import static io.quarkus.annotation.processor.Constants.SECTION_TITLE_L1;

import java.util.ArrayList;
import java.util.List;

import io.quarkus.annotation.processor.Constants;

public final class MavenConfigDocBuilder extends ConfigDocBuilder {

public MavenConfigDocBuilder() {
super(false);
}

private final JavaDocParser javaDocParser = new JavaDocParser();

public void addTableTitle(String goalTitle) {
write(SECTION_TITLE_L1, goalTitle, NEW_LINE);
}

public void addNewLine() {
write(NEW_LINE);
}

public void addTableDescription(String goalDescription) {
write(NEW_LINE, javaDocParser.parseConfigDescription(goalDescription), NEW_LINE);
}

public GoalParamsBuilder newGoalParamsBuilder() {
return new GoalParamsBuilder(javaDocParser);
}

private static abstract class TableBuilder {

protected final List<ConfigDocItem> configDocItems = new ArrayList<>();

/**
* Section name that is displayed in a table header
*/
abstract protected String getSectionName();

public List<ConfigDocItem> build() {

// a summary table
final ConfigDocSection parameterSection = new ConfigDocSection();
parameterSection.setShowSection(true);
parameterSection.setName(getSectionName());
parameterSection.setSectionDetailsTitle(getSectionName());
parameterSection.setOptional(false);
parameterSection.setConfigDocItems(List.copyOf(configDocItems));

// topConfigDocItem wraps the summary table
final ConfigDocItem topConfigDocItem = new ConfigDocItem();
topConfigDocItem.setConfigDocSection(parameterSection);

return List.of(topConfigDocItem);
}

public boolean tableIsNotEmpty() {
return !configDocItems.isEmpty();
}
}

public static final class GoalParamsBuilder extends TableBuilder {

private final JavaDocParser javaDocParser;

private GoalParamsBuilder(JavaDocParser javaDocParser) {
this.javaDocParser = javaDocParser;
}

public void addParam(String type, String name, String defaultValue, boolean required, String description) {
final ConfigDocKey configDocKey = new ConfigDocKey();
configDocKey.setType(type);
configDocKey.setKey(name);
configDocKey.setConfigPhase(ConfigPhase.RUN_TIME);
configDocKey.setDefaultValue(defaultValue == null ? Constants.EMPTY : defaultValue);
if (description != null && !description.isBlank()) {
configDocKey.setConfigDoc(javaDocParser.parseConfigDescription(description));
} else {
configDocKey.setConfigDoc(EMPTY);
}
configDocKey.setOptional(!required);
final ConfigDocItem configDocItem = new ConfigDocItem();
configDocItem.setConfigDocKey(configDocKey);
configDocItems.add(configDocItem);
}

@Override
protected String getSectionName() {
return "Parameter";
}
}

}
Loading

0 comments on commit f7b6773

Please sign in to comment.