diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/ExtensionAnnotationProcessor.java b/core/processor/src/main/java/io/quarkus/annotation/processor/ExtensionAnnotationProcessor.java index 06a8df7615b88c..fa3758b7c61a72 100644 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/ExtensionAnnotationProcessor.java +++ b/core/processor/src/main/java/io/quarkus/annotation/processor/ExtensionAnnotationProcessor.java @@ -23,11 +23,10 @@ import io.quarkus.annotation.processor.documentation.config.model.Extension; import io.quarkus.annotation.processor.documentation.config.util.Types; import io.quarkus.annotation.processor.extension.ExtensionBuildProcessor; -import io.quarkus.annotation.processor.generate_doc.LegacyConfigDocExtensionProcessor; import io.quarkus.annotation.processor.util.Config; import io.quarkus.annotation.processor.util.Utils; -@SupportedOptions({ Options.LEGACY_CONFIG_ROOT, Options.GENERATE_DOC, Options.GENERATE_LEGACY_CONFIG_DOC }) +@SupportedOptions({ Options.LEGACY_CONFIG_ROOT, Options.GENERATE_DOC }) public class ExtensionAnnotationProcessor extends AbstractProcessor { private static final String DEBUG = "debug-extension-annotation-processor"; @@ -48,10 +47,6 @@ public synchronized void init(ProcessingEnvironment processingEnv) { // for now, we generate the old config doc by default but we will change this behavior soon if (generateDoc) { extensionProcessors.add(new ConfigDocExtensionProcessor()); - - if (!"false".equals(processingEnv.getOptions().get(Options.GENERATE_LEGACY_CONFIG_DOC))) { - extensionProcessors.add(new LegacyConfigDocExtensionProcessor()); - } } this.extensionProcessors = Collections.unmodifiableList(extensionProcessors); diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/Options.java b/core/processor/src/main/java/io/quarkus/annotation/processor/Options.java index dbbd252be8e317..0d11b2104a373a 100644 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/Options.java +++ b/core/processor/src/main/java/io/quarkus/annotation/processor/Options.java @@ -3,6 +3,5 @@ public final class Options { public static final String LEGACY_CONFIG_ROOT = "legacyConfigRoot"; - public static final String GENERATE_LEGACY_CONFIG_DOC = "generateLegacyConfigDoc"; public static final String GENERATE_DOC = "generateDoc"; } diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/discovery/ParsedJavadocSection.java b/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/discovery/ParsedJavadocSection.java index 5342e394c48701..e93fce5e7b400f 100644 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/discovery/ParsedJavadocSection.java +++ b/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/discovery/ParsedJavadocSection.java @@ -1,4 +1,4 @@ package io.quarkus.annotation.processor.documentation.config.discovery; -public record ParsedJavadocSection(String title, String description) { +public record ParsedJavadocSection(String title, String details) { } \ No newline at end of file diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/formatter/JavadocToAsciidocTransformer.java b/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/formatter/JavadocToAsciidocTransformer.java index 62100a8596f180..2775f2360a6cf3 100644 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/formatter/JavadocToAsciidocTransformer.java +++ b/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/formatter/JavadocToAsciidocTransformer.java @@ -30,7 +30,6 @@ public final class JavadocToAsciidocTransformer { private static final Pattern REPLACE_MACOS_EOL = Pattern.compile("\r"); private static final Pattern STARTING_SPACE = Pattern.compile("^ +"); - private static final String EMPTY = ""; private static final String DOT = "."; private static final String BACKTICK = "`"; @@ -112,12 +111,16 @@ public ParsedJavadoc parseConfigItemJavadoc(String rawJavadoc) { .map(JavadocDescription::toText) .findFirst(); + if (description != null && description.isBlank()) { + description = null; + } + return new ParsedJavadoc(description, since.isPresent() ? since.get() : null, originalFormat); } public ParsedJavadocSection parseConfigSectionJavadoc(String javadocComment) { if (javadocComment == null || javadocComment.trim().isEmpty()) { - return new ParsedJavadocSection(EMPTY, EMPTY); + return new ParsedJavadocSection(null, null); } // the parser expects all the lines to start with "* " @@ -133,19 +136,28 @@ public ParsedJavadocSection parseConfigSectionJavadoc(String javadocComment) { } if (asciidoc == null || asciidoc.isBlank()) { - return new ParsedJavadocSection(EMPTY, EMPTY); + return new ParsedJavadocSection(null, null); + } + + final int newLineIndex = asciidoc.indexOf(NEW_LINE); + final int dotIndex = asciidoc.indexOf(DOT); + + final int endOfTitleIndex; + if (newLineIndex > 0 && newLineIndex < dotIndex) { + endOfTitleIndex = newLineIndex; + } else { + endOfTitleIndex = dotIndex; } - final int endOfTitleIndex = asciidoc.indexOf(DOT); if (endOfTitleIndex == -1) { - final String title = asciidoc.replaceAll("^([^\\w])+", EMPTY).trim(); + final String title = asciidoc.replaceAll("^([^\\w])+", "").trim(); - return new ParsedJavadocSection(title, EMPTY); + return new ParsedJavadocSection(title, null); } else { - final String title = asciidoc.substring(0, endOfTitleIndex).replaceAll("^([^\\w])+", EMPTY).trim(); + final String title = asciidoc.substring(0, endOfTitleIndex).replaceAll("^([^\\w])+", "").trim(); final String details = asciidoc.substring(endOfTitleIndex + 1).trim(); - return new ParsedJavadocSection(title, details); + return new ParsedJavadocSection(title, details.isBlank() ? null : details); } } diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/util/ConfigNamingUtil.java b/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/util/ConfigNamingUtil.java index 1cb8a1090b6a97..100e78e9898e14 100644 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/util/ConfigNamingUtil.java +++ b/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/util/ConfigNamingUtil.java @@ -42,7 +42,7 @@ public static String getRootPrefix(String prefix, String name, String simpleClas return rootPrefix; } - private static String deriveConfigRootName(String simpleClassName, String prefix, ConfigPhase configPhase) { + static String deriveConfigRootName(String simpleClassName, String prefix, ConfigPhase configPhase) { String simpleNameInLowerCase = simpleClassName.toLowerCase(); int length = simpleNameInLowerCase.length(); diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/util/JavadocUtil.java b/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/util/JavadocUtil.java index 3e356f54a77aae..c9970cefcf8d32 100644 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/util/JavadocUtil.java +++ b/core/processor/src/main/java/io/quarkus/annotation/processor/documentation/config/util/JavadocUtil.java @@ -10,10 +10,10 @@ public final class JavadocUtil { - private static final String VERTX_JAVA_DOC_SITE = "https://vertx.io/docs/apidocs/"; - private static final String OFFICIAL_JAVA_DOC_BASE_LINK = "https://docs.oracle.com/en/java/javase/17/docs/api/"; - private static final String AGROAL_API_JAVA_DOC_SITE = "https://javadoc.io/doc/io.agroal/agroal-api/latest/"; - private static final String LOG_LEVEL_REDIRECT_URL = "https://javadoc.io/doc/org.jboss.logmanager/jboss-logmanager/latest/org/jboss/logmanager/Level.html"; + static final String VERTX_JAVA_DOC_SITE = "https://vertx.io/docs/apidocs/"; + static final String OFFICIAL_JAVA_DOC_BASE_LINK = "https://docs.oracle.com/en/java/javase/17/docs/api/"; + static final String AGROAL_API_JAVA_DOC_SITE = "https://javadoc.io/doc/io.agroal/agroal-api/latest/"; + static final String LOG_LEVEL_REDIRECT_URL = "https://javadoc.io/doc/org.jboss.logmanager/jboss-logmanager/latest/org/jboss/logmanager/Level.html"; private static final Pattern PACKAGE_PATTERN = Pattern.compile("^(\\w+)\\.(\\w+)\\..*$"); diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/extension/ExtensionBuildProcessor.java b/core/processor/src/main/java/io/quarkus/annotation/processor/extension/ExtensionBuildProcessor.java index de94fa8e122b36..0c408d0bb494f8 100644 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/extension/ExtensionBuildProcessor.java +++ b/core/processor/src/main/java/io/quarkus/annotation/processor/extension/ExtensionBuildProcessor.java @@ -21,7 +21,6 @@ import io.quarkus.annotation.processor.ExtensionProcessor; import io.quarkus.annotation.processor.Outputs; import io.quarkus.annotation.processor.documentation.config.util.Types; -import io.quarkus.annotation.processor.generate_doc.Constants; import io.quarkus.annotation.processor.util.Config; import io.quarkus.annotation.processor.util.Utils; @@ -51,15 +50,15 @@ public void process(Set annotations, RoundEnvironment rou processBuildStep(roundEnv, annotation); break; case Types.ANNOTATION_RECORDER: - trackAnnotationUsed(Constants.ANNOTATION_RECORDER); + trackAnnotationUsed(Types.ANNOTATION_RECORDER); processRecorder(roundEnv, annotation); break; case Types.ANNOTATION_CONFIG_ROOT: - trackAnnotationUsed(Constants.ANNOTATION_CONFIG_ROOT); + trackAnnotationUsed(Types.ANNOTATION_CONFIG_ROOT); processConfigRoot(roundEnv, annotation); break; case Types.ANNOTATION_CONFIG_GROUP: - trackAnnotationUsed(Constants.ANNOTATION_CONFIG_GROUP); + trackAnnotationUsed(Types.ANNOTATION_CONFIG_GROUP); processConfigGroup(roundEnv, annotation); break; } @@ -103,10 +102,10 @@ private void validateRecordBuildSteps(TypeElement clazz) { continue; } ExecutableElement ex = (ExecutableElement) e; - if (!utils.element().isAnnotationPresent(ex, Constants.ANNOTATION_BUILD_STEP)) { + if (!utils.element().isAnnotationPresent(ex, Types.ANNOTATION_BUILD_STEP)) { continue; } - if (!utils.element().isAnnotationPresent(ex, Constants.ANNOTATION_RECORD)) { + if (!utils.element().isAnnotationPresent(ex, Types.ANNOTATION_RECORD)) { continue; } @@ -118,7 +117,7 @@ private void validateRecordBuildSteps(TypeElement clazz) { if (parameterTypeElement == null) { allTypesResolvable = false; } else { - if (utils.element().isAnnotationPresent(parameterTypeElement, Constants.ANNOTATION_RECORDER)) { + if (utils.element().isAnnotationPresent(parameterTypeElement, Types.ANNOTATION_RECORDER)) { if (parameterTypeElement.getModifiers().contains(Modifier.FINAL)) { utils.processingEnv().getMessager().printMessage(Diagnostic.Kind.ERROR, "Class '" + parameterTypeElement.getQualifiedName() @@ -176,7 +175,7 @@ private void processConfigGroup(RoundEnvironment roundEnv, TypeElement annotatio } private void validateAnnotationUsage() { - if (isAnnotationUsed(Constants.ANNOTATION_BUILD_STEP) && isAnnotationUsed(Constants.ANNOTATION_RECORDER)) { + if (isAnnotationUsed(Types.ANNOTATION_BUILD_STEP) && isAnnotationUsed(Types.ANNOTATION_RECORDER)) { utils.processingEnv().getMessager().printMessage(Diagnostic.Kind.ERROR, "Detected use of @Recorder annotation in 'deployment' module. Classes annotated with @Recorder must be part of the extension's 'runtime' module"); } diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDoc.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDoc.java deleted file mode 100644 index 0ad3e5a327d4d5..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDoc.java +++ /dev/null @@ -1,20 +0,0 @@ -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 getWriteItems(); - - /** - * An item is a summary table, note below the table, ... - */ - interface WriteItem { - void accept(Writer writer) throws IOException; - } -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocBuilder.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocBuilder.java deleted file mode 100644 index 60e8eeddb6ba90..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocBuilder.java +++ /dev/null @@ -1,89 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import static io.quarkus.annotation.processor.generate_doc.Constants.SUMMARY_TABLE_ID_VARIABLE; -import static java.util.Objects.requireNonNull; - -import java.util.ArrayList; -import java.util.List; - -/** - * {@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 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 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 docItemsCopy = List.copyOf(writeItems); - return () -> docItemsCopy; - } - -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocElement.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocElement.java deleted file mode 100644 index e23d313841fbe3..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocElement.java +++ /dev/null @@ -1,35 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import static io.quarkus.annotation.processor.generate_doc.ConfigPhase.COMPARATOR; - -import java.io.IOException; -import java.io.Writer; - -public interface ConfigDocElement { - void accept(Writer writer, DocFormatter docFormatter) throws IOException; - - ConfigPhase getConfigPhase(); - - boolean isWithinAMap(); - - String getTopLevelGrouping(); - - /** - * - * Map config will be at the end of generated doc. - * Order build time config first - * Otherwise maintain source code order. - */ - default int compare(ConfigDocElement item) { - if (isWithinAMap()) { - if (item.isWithinAMap()) { - return COMPARATOR.compare(getConfigPhase(), item.getConfigPhase()); - } - return 1; - } else if (item.isWithinAMap()) { - return -1; - } - - return COMPARATOR.compare(getConfigPhase(), item.getConfigPhase()); - } -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocGeneratedOutput.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocGeneratedOutput.java deleted file mode 100644 index 215b15f6c53e04..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocGeneratedOutput.java +++ /dev/null @@ -1,68 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import java.util.List; -import java.util.Objects; - -public class ConfigDocGeneratedOutput { - private final String fileName; - private final boolean searchable; - private final boolean hasAnchorPrefix; - private final List configDocItems; - - public ConfigDocGeneratedOutput(String fileName, boolean searchable, List configDocItems, - boolean hasAnchorPrefix) { - this.fileName = fileName; - this.searchable = searchable; - this.configDocItems = configDocItems; - this.hasAnchorPrefix = hasAnchorPrefix; - } - - public String getFileName() { - return fileName; - } - - public boolean isSearchable() { - return searchable; - } - - public List getConfigDocItems() { - return configDocItems; - } - - public String getAnchorPrefix() { - if (!hasAnchorPrefix) { - return Constants.EMPTY; - } - - String anchorPrefix = fileName; - if (fileName.endsWith(Constants.ADOC_EXTENSION)) { - anchorPrefix = anchorPrefix.substring(0, anchorPrefix.length() - 5); - } - - return anchorPrefix + "_"; - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - ConfigDocGeneratedOutput that = (ConfigDocGeneratedOutput) o; - return Objects.equals(fileName, that.fileName); - } - - @Override - public int hashCode() { - return Objects.hash(fileName); - } - - @Override - public String toString() { - return "ConfigItemsOutput{" + - "fileName='" + fileName + '\'' + - ", searchable=" + searchable + - ", configDocItems=" + configDocItems + - '}'; - } -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItem.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItem.java deleted file mode 100644 index 3055ab5165bd7c..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItem.java +++ /dev/null @@ -1,170 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import java.io.IOException; -import java.io.Writer; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; - -/** - * A config doc item is either a config section {@link ConfigDocSection} or a config key {@link ConfigDocKey} - */ -@JsonInclude(JsonInclude.Include.NON_NULL) -final public class ConfigDocItem implements ConfigDocElement, Comparable { - private ConfigDocKey configDocKey; - private ConfigDocSection configDocSection; - - public ConfigDocItem() { - } - - public ConfigDocItem(ConfigDocSection configDocSection, ConfigDocKey configDocKey) { - this.configDocSection = configDocSection; - this.configDocKey = configDocKey; - } - - public ConfigDocKey getConfigDocKey() { - return configDocKey; - } - - public void setConfigDocKey(ConfigDocKey configDocKey) { - this.configDocKey = configDocKey; - } - - public ConfigDocSection getConfigDocSection() { - return configDocSection; - } - - public void setConfigDocSection(ConfigDocSection configDocSection) { - this.configDocSection = configDocSection; - } - - @JsonIgnore - boolean isConfigSection() { - return configDocSection != null; - } - - @JsonIgnore - boolean isConfigKey() { - return configDocKey != null; - } - - @Override - public String toString() { - return "ConfigDocItem{" + - "configDocSection=" + configDocSection + - ", configDocKey=" + configDocKey + - '}'; - } - - @Override - public void accept(Writer writer, DocFormatter docFormatter) throws IOException { - if (isConfigSection()) { - configDocSection.accept(writer, docFormatter); - } else if (isConfigKey()) { - configDocKey.accept(writer, docFormatter); - } - } - - @JsonIgnore - @Override - public ConfigPhase getConfigPhase() { - if (isConfigSection()) { - return configDocSection.getConfigPhase(); - } else if (isConfigKey()) { - return configDocKey.getConfigPhase(); - } - - return null; - } - - @JsonIgnore - @Override - public boolean isWithinAMap() { - if (isConfigSection()) { - return configDocSection.isWithinAMap(); - } else if (isConfigKey()) { - return configDocKey.isWithinAMap(); - } - - return false; - } - - @Override - @JsonIgnore - public String getTopLevelGrouping() { - if (isConfigKey()) { - return configDocKey.getTopLevelGrouping(); - } else if (isConfigSection()) { - return configDocSection.getTopLevelGrouping(); - } - - return null; - } - - @JsonIgnore - public boolean isWithinAConfigGroup() { - if (isConfigSection()) { - return true; - } else if (isConfigKey() && configDocKey.isWithinAConfigGroup()) { - return true; - } - - return false; - } - - /** - * TODO determine section ordering - * - * @param item - * @return - */ - @Override - public int compareTo(ConfigDocItem item) { - // ensure that different config objects in the same extension don't cross streams - if (isConfigKey() && item.isConfigKey() && (!getTopLevelGrouping().equals(item.getTopLevelGrouping()))) { - return getTopLevelGrouping().compareTo(item.getTopLevelGrouping()); - } - - if (isConfigSection() && item.isConfigKey()) { - return 1; // push sections to the end of the list - } else if (isConfigKey() && item.isConfigSection()) { - return -1; // push section to the end of the list - } - - return compare(item); - } - - public boolean hasDurationInformationNote() { - if (isConfigKey()) { - return DocGeneratorUtil.hasDurationInformationNote(configDocKey); - } else if (isConfigSection()) { - return configDocSection.hasDurationInformationNote(); - } - return false; - } - - public boolean hasMemoryInformationNote() { - if (isConfigKey()) { - return DocGeneratorUtil.hasMemoryInformationNote(configDocKey); - } else if (isConfigSection()) { - return configDocSection.hasMemoryInformationNote(); - } - return false; - } - - public void configPhase(ConfigPhase phase) { - if (isConfigKey()) { - configDocKey.setConfigPhase(phase); - } else { - configDocSection.setConfigPhase(phase); - } - } - - public void withinAMap(boolean withinAMap) { - if (isConfigKey()) { - configDocKey.setWithinAMap(configDocKey.isWithinAMap() || withinAMap); - } else { - configDocSection.setWithinAMap(configDocSection.isWithinAMap() || withinAMap); - } - } -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItemFinder.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItemFinder.java deleted file mode 100644 index e12797fc59e6da..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItemFinder.java +++ /dev/null @@ -1,686 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import static io.quarkus.annotation.processor.generate_doc.Constants.ANNOTATION_CONFIG_DOC_DEFAULT; -import static io.quarkus.annotation.processor.generate_doc.Constants.ANNOTATION_CONFIG_DOC_ENUM_VALUE; -import static io.quarkus.annotation.processor.generate_doc.Constants.ANNOTATION_CONFIG_DOC_IGNORE; -import static io.quarkus.annotation.processor.generate_doc.Constants.ANNOTATION_CONFIG_DOC_MAP_KEY; -import static io.quarkus.annotation.processor.generate_doc.Constants.ANNOTATION_CONFIG_DOC_SECTION; -import static io.quarkus.annotation.processor.generate_doc.Constants.ANNOTATION_CONFIG_ITEM; -import static io.quarkus.annotation.processor.generate_doc.Constants.ANNOTATION_CONFIG_WITH_DEFAULT; -import static io.quarkus.annotation.processor.generate_doc.Constants.ANNOTATION_CONFIG_WITH_NAME; -import static io.quarkus.annotation.processor.generate_doc.Constants.ANNOTATION_CONFIG_WITH_PARENT_NAME; -import static io.quarkus.annotation.processor.generate_doc.Constants.ANNOTATION_CONFIG_WITH_UNNAMED_KEY; -import static io.quarkus.annotation.processor.generate_doc.Constants.ANNOTATION_CONVERT_WITH; -import static io.quarkus.annotation.processor.generate_doc.Constants.ANNOTATION_DEFAULT_CONVERTER; -import static io.quarkus.annotation.processor.generate_doc.Constants.DOT; -import static io.quarkus.annotation.processor.generate_doc.Constants.EMPTY; -import static io.quarkus.annotation.processor.generate_doc.Constants.HYPHENATED_ELEMENT_NAME; -import static io.quarkus.annotation.processor.generate_doc.Constants.LIST_OF_CONFIG_ITEMS_TYPE_REF; -import static io.quarkus.annotation.processor.generate_doc.Constants.NEW_LINE; -import static io.quarkus.annotation.processor.generate_doc.Constants.NO_DEFAULT; -import static io.quarkus.annotation.processor.generate_doc.Constants.OBJECT_MAPPER; -import static io.quarkus.annotation.processor.generate_doc.Constants.PARENT; -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.getJavaDocSiteLink; -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.getKnownGenericType; -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.hyphenate; -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.hyphenateEnumValue; -import static java.util.Collections.emptyList; -import static java.util.stream.Collectors.toList; -import static javax.lang.model.element.Modifier.ABSTRACT; - -import java.io.IOException; -import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Properties; -import java.util.Set; -import java.util.stream.Collectors; - -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.Name; -import javax.lang.model.element.TypeElement; -import javax.lang.model.type.ArrayType; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.ExecutableType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; - -import com.fasterxml.jackson.core.JsonProcessingException; - -import io.quarkus.annotation.processor.generate_doc.JavaDocParser.SectionHolder; - -class ConfigDocItemFinder { - - private static final String COMMA = ","; - private static final String BACK_TICK = "`"; - private static final String NAMED_MAP_CONFIG_ITEM_FORMAT = ".\"%s\""; - private static final Set PRIMITIVE_TYPES = new HashSet<>( - Arrays.asList("byte", "short", "int", "long", "float", "double", "boolean", "char")); - - private final JavaDocParser javaDocParser = new JavaDocParser(); - private final JavaDocParser enumJavaDocParser = new JavaDocParser(true); - private final ScannedConfigDocsItemHolder holder = new ScannedConfigDocsItemHolder(); - - private final Set configRoots; - private final Properties javaDocProperties; - private final Map configGroupQualifiedNameToTypeElementMap; - private final FsMap allConfigurationGroups; - private final FsMap allConfigurationRoots; - private final boolean configMapping; - - public ConfigDocItemFinder(Set configRoots, - Map configGroupQualifiedNameToTypeElementMap, - Properties javaDocProperties, FsMap allConfigurationGroups, FsMap allConfigurationRoots, - boolean configMapping) { - this.configRoots = configRoots; - this.configGroupQualifiedNameToTypeElementMap = configGroupQualifiedNameToTypeElementMap; - this.javaDocProperties = javaDocProperties; - this.allConfigurationGroups = allConfigurationGroups; - this.allConfigurationRoots = allConfigurationRoots; - this.configMapping = configMapping; - } - - /** - * Find configuration items from current encountered configuration roots. - * Scan configuration group first and record them in a properties file as they can be shared across - * different modules. - * - */ - ScannedConfigDocsItemHolder findInMemoryConfigurationItems() throws IOException { - for (Map.Entry entry : configGroupQualifiedNameToTypeElementMap.entrySet()) { - ConfigPhase buildTime = ConfigPhase.BUILD_TIME; - final List configDocItems = recursivelyFindConfigItems(entry.getValue(), EMPTY, EMPTY, buildTime, - false, 1, - false, configMapping); - allConfigurationGroups.put(entry.getKey(), OBJECT_MAPPER.writeValueAsString(configDocItems)); - } - - for (ConfigRootInfo configRootInfo : configRoots) { - final int sectionLevel = 0; - final TypeElement element = configRootInfo.getClazz(); - String rootName = configRootInfo.getName(); - ConfigPhase configPhase = configRootInfo.getConfigPhase(); - final List configDocItems = recursivelyFindConfigItems(element, rootName, rootName, configPhase, - false, sectionLevel, true, configMapping); - holder.addConfigRootItems(configRootInfo, configDocItems); - allConfigurationRoots.put(configRootInfo.getClazz().toString(), OBJECT_MAPPER.writeValueAsString(configDocItems)); - } - - return holder; - } - - /** - * Recursively find config item found in a config root or config group given as {@link Element} - */ - private List recursivelyFindConfigItems(Element element, String rootName, String parentName, - ConfigPhase configPhase, boolean withinAMap, int sectionLevel, boolean generateSeparateConfigGroupDocsFiles, - boolean configMapping) - throws JsonProcessingException { - List configDocItems = new ArrayList<>(); - TypeElement asTypeElement = (TypeElement) element; - List superTypes = new ArrayList<>(); - superTypes.add(asTypeElement.getSuperclass()); - superTypes.addAll(asTypeElement.getInterfaces()); - - for (TypeMirror superType : superTypes) { - if (superType.getKind() != TypeKind.NONE && !superType.toString().equals(Object.class.getName())) { - String key = superType.toString(); - String rawConfigItems = allConfigurationGroups.get(key); - if (rawConfigItems == null) { - rawConfigItems = allConfigurationRoots.get(key); - } - final List superTypeConfigItems; - if (rawConfigItems == null) { // element not yet scanned - Element superElement = ((DeclaredType) superType).asElement(); - superTypeConfigItems = recursivelyFindConfigItems(superElement, rootName, parentName, - configPhase, withinAMap, sectionLevel, generateSeparateConfigGroupDocsFiles, - configMapping); - } else { - superTypeConfigItems = OBJECT_MAPPER.readValue(rawConfigItems, LIST_OF_CONFIG_ITEMS_TYPE_REF); - } - - configDocItems.addAll(superTypeConfigItems); - } - } - - for (Element enclosedElement : element.getEnclosedElements()) { - if (!shouldProcessElement(enclosedElement, configMapping)) { - continue; - } - - boolean isStaticField = enclosedElement - .getModifiers() - .stream() - .anyMatch(Modifier.STATIC::equals); - - if (isStaticField) { - continue; - } - - String name = null; - String defaultValue = NO_DEFAULT; - String defaultValueDoc = EMPTY; - List acceptedValues = null; - final TypeElement clazz = (TypeElement) element; - final String fieldName = enclosedElement.getSimpleName().toString(); - final String javaDocKey = clazz.getQualifiedName().toString() + DOT + fieldName; - final List annotationMirrors = enclosedElement.getAnnotationMirrors(); - final String rawJavaDoc = javaDocProperties.getProperty(javaDocKey); - boolean useHyphenateEnumValue = true; - - String hyphenatedFieldName = hyphenate(fieldName); - String configDocMapKey = hyphenatedFieldName; - boolean unnamedMapKey = false; - boolean isDeprecated = false; - boolean generateDocumentation = true; - ConfigDocSection configSection = new ConfigDocSection(); - configSection.setTopLevelGrouping(rootName); - configSection.setWithinAMap(withinAMap); - configSection.setConfigPhase(configPhase); - - for (AnnotationMirror annotationMirror : annotationMirrors) { - String annotationName = annotationMirror.getAnnotationType().toString(); - if (annotationName.equals(Deprecated.class.getName())) { - isDeprecated = true; - break; - } - if (annotationName.equals(ANNOTATION_CONFIG_ITEM) - || annotationName.equals(ANNOTATION_CONFIG_DOC_MAP_KEY)) { - for (Map.Entry entry : annotationMirror - .getElementValues().entrySet()) { - final String key = entry.getKey().toString(); - final Object value = entry.getValue().getValue(); - if (annotationName.equals(ANNOTATION_CONFIG_DOC_MAP_KEY) && "value()".equals(key)) { - configDocMapKey = value.toString(); - } else if (annotationName.equals(ANNOTATION_CONFIG_ITEM)) { - if ("name()".equals(key)) { - switch (value.toString()) { - case HYPHENATED_ELEMENT_NAME: - name = parentName + DOT + hyphenatedFieldName; - break; - case PARENT: - name = parentName; - break; - default: - name = parentName + DOT + value; - } - } else if ("defaultValue()".equals(key)) { - defaultValue = value.toString(); - } else if ("defaultValueDocumentation()".equals(key)) { - defaultValueDoc = value.toString(); - } else if ("generateDocumentation()".equals(key)) { - generateDocumentation = (Boolean) value; - } - } - } - } else if (annotationName.equals(ANNOTATION_CONFIG_DOC_SECTION)) { - final SectionHolder sectionHolder = javaDocParser.parseConfigSection(rawJavaDoc, sectionLevel); - configSection.setShowSection(true); - configSection.setSectionDetails(sectionHolder.details); - configSection.setSectionDetailsTitle(sectionHolder.title); - configSection.setName(parentName + DOT + hyphenatedFieldName); - } else if (annotationName.equals(ANNOTATION_DEFAULT_CONVERTER) - || annotationName.equals(ANNOTATION_CONVERT_WITH)) { - useHyphenateEnumValue = false; - } - - // Mappings - if (annotationName.equals(ANNOTATION_CONFIG_WITH_NAME)) { - name = parentName + DOT + annotationMirror.getElementValues().values().iterator().next().getValue(); - } else if (annotationName.equals(ANNOTATION_CONFIG_WITH_PARENT_NAME)) { - name = parentName; - } else if (annotationName.equals(ANNOTATION_CONFIG_DOC_DEFAULT)) { - defaultValueDoc = annotationMirror.getElementValues().values().iterator().next().getValue().toString(); - } else if (annotationName.equals(ANNOTATION_CONFIG_WITH_DEFAULT)) { - defaultValue = annotationMirror.getElementValues().values().isEmpty() ? null - : annotationMirror.getElementValues().values().iterator().next().getValue().toString(); - } else if (annotationName.equals(ANNOTATION_CONFIG_WITH_UNNAMED_KEY)) { - unnamedMapKey = true; - } else if (annotationName.equals(ANNOTATION_CONFIG_DOC_IGNORE)) { - generateDocumentation = false; - } - } - - if (isDeprecated) { - continue; // do not include deprecated config items - } - if (!generateDocumentation) { - continue; // documentation for this item was explicitly disabled - } - - if (name == null) { - name = parentName + DOT + hyphenatedFieldName; - } - if (NO_DEFAULT.equals(defaultValue)) { - defaultValue = EMPTY; - } - - TypeMirror typeMirror = unwrapTypeMirror(enclosedElement.asType()); - String type = getType(typeMirror); - - if (isConfigGroup(type)) { - List groupConfigItems = readConfigGroupItems(configPhase, rootName, name, emptyList(), type, - configSection, withinAMap, generateSeparateConfigGroupDocsFiles, configMapping); - DocGeneratorUtil.appendConfigItemsIntoExistingOnes(configDocItems, groupConfigItems); - } else { - final ConfigDocKey configDocKey = new ConfigDocKey(); - configDocKey.setWithinAMap(withinAMap); - boolean list = false; - boolean optional = false; - if (!typeMirror.getKind().isPrimitive()) { - DeclaredType declaredType = (DeclaredType) typeMirror; - TypeElement typeElement = (TypeElement) declaredType.asElement(); - Name qualifiedName = typeElement.getQualifiedName(); - optional = qualifiedName.toString().startsWith(Optional.class.getName()) - || qualifiedName.contentEquals(Map.class.getName()); - list = qualifiedName.contentEquals(List.class.getName()) - || qualifiedName.contentEquals(Set.class.getName()); - - List typeArguments = declaredType.getTypeArguments(); - if (!typeArguments.isEmpty()) { - // FIXME: this is super dodgy: we should check the type!! - if (typeArguments.size() == 2) { - type = getType(typeArguments.get(1)); - List additionalNames; - if (unnamedMapKey) { - additionalNames = List - .of(name + String.format(NAMED_MAP_CONFIG_ITEM_FORMAT, configDocMapKey)); - } else { - name += String.format(NAMED_MAP_CONFIG_ITEM_FORMAT, configDocMapKey); - additionalNames = emptyList(); - } - if (isConfigGroup(type)) { - List groupConfigItems = readConfigGroupItems(configPhase, rootName, name, - additionalNames, type, configSection, true, generateSeparateConfigGroupDocsFiles, - configMapping); - DocGeneratorUtil.appendConfigItemsIntoExistingOnes(configDocItems, groupConfigItems); - continue; - } else { - configDocKey.setWithinAMap(true); - } - } else { - // FIXME: this is for Optional and List - TypeMirror realTypeMirror = typeArguments.get(0); - String typeInString = realTypeMirror.toString(); - - if (optional) { - if (isConfigGroup(typeInString)) { - if (!configSection.isShowSection()) { - final SectionHolder sectionHolder = javaDocParser.parseConfigSection( - rawJavaDoc, - sectionLevel); - configSection.setSectionDetails(sectionHolder.details); - configSection.setSectionDetailsTitle(sectionHolder.title); - configSection.setName(parentName + DOT + hyphenatedFieldName); - configSection.setShowSection(true); - } - configSection.setOptional(true); - List groupConfigItems = readConfigGroupItems(configPhase, rootName, name, - emptyList(), typeInString, configSection, withinAMap, - generateSeparateConfigGroupDocsFiles, configMapping); - DocGeneratorUtil.appendConfigItemsIntoExistingOnes(configDocItems, groupConfigItems); - continue; - } else if ((typeInString.startsWith(List.class.getName()) - || typeInString.startsWith(Set.class.getName()) - || realTypeMirror.getKind() == TypeKind.ARRAY)) { - list = true; - DeclaredType declaredRealType = (DeclaredType) typeMirror; - typeArguments = declaredRealType.getTypeArguments(); - if (!typeArguments.isEmpty()) { - realTypeMirror = typeArguments.get(0); - } - } - } - - type = simpleTypeToString(realTypeMirror); - if (isEnumType(realTypeMirror)) { - if (defaultValueDoc.isBlank()) { - if (useHyphenateEnumValue) { - defaultValue = Arrays.stream(defaultValue.split(COMMA)) - .map(defaultEnumValue -> hyphenateEnumValue(defaultEnumValue.trim())) - .collect(Collectors.joining(COMMA)); - } - } else { - defaultValue = defaultValueDoc; - } - acceptedValues = extractEnumValues(realTypeMirror, useHyphenateEnumValue, - clazz.getQualifiedName().toString()); - configDocKey.setEnum(true); - } else { - if (!defaultValueDoc.isBlank()) { - defaultValue = defaultValueDoc; - } - } - } - } else { - type = simpleTypeToString(declaredType); - - if (defaultValueDoc.isBlank()) { - if (isEnumType(declaredType)) { - defaultValue = hyphenateEnumValue(defaultValue); - acceptedValues = extractEnumValues(declaredType, useHyphenateEnumValue, - clazz.getQualifiedName().toString()); - configDocKey.setEnum(true); - } else if (isDurationType(declaredType) && !defaultValue.isEmpty()) { - defaultValue = DocGeneratorUtil.normalizeDurationValue(defaultValue); - } - } else { - defaultValue = defaultValueDoc; - } - } - } - - configDocKey.setKey(name); - configDocKey.setAdditionalKeys(emptyList()); - configDocKey.setType(type); - configDocKey.setList(list); - configDocKey.setOptional(optional); - configDocKey.setWithinAConfigGroup(sectionLevel > 0); - configDocKey.setTopLevelGrouping(rootName); - configDocKey.setConfigPhase(configPhase); - configDocKey.setDefaultValue(defaultValue); - configDocKey.setDocMapKey(configDocMapKey); - javaDocParser.parseConfigDescription(rawJavaDoc, configDocKey::setConfigDoc, configDocKey::setSince); - configDocKey.setEnvironmentVariable(DocGeneratorUtil.toEnvVarName(name)); - configDocKey.setAcceptedValues(acceptedValues); - configDocKey.setJavaDocSiteLink(getJavaDocSiteLink(type)); - ConfigDocItem configDocItem = new ConfigDocItem(); - configDocItem.setConfigDocKey(configDocKey); - - // If there is already a config item with the same key it comes from a super type, and we need to override it - ConfigDocItem parent = null; - for (ConfigDocItem docItem : configDocItems) { - if (docItem.getConfigDocKey() != null && docItem.getConfigDocKey().getKey().equals(configDocKey.getKey())) { - parent = docItem; - break; - } - } - // We may want to merge the metadata, but let's keep this simple for now - if (parent != null) { - configDocItems.remove(parent); - } - configDocItems.add(configDocItem); - } - } - - return configDocItems; - } - - private TypeMirror unwrapTypeMirror(TypeMirror typeMirror) { - if (typeMirror instanceof DeclaredType) { - return typeMirror; - } - - if (typeMirror instanceof ExecutableType) { - ExecutableType executableType = (ExecutableType) typeMirror; - return executableType.getReturnType(); - } - - return typeMirror; - } - - private String getType(TypeMirror typeMirror) { - if (typeMirror instanceof DeclaredType) { - DeclaredType declaredType = (DeclaredType) typeMirror; - TypeElement typeElement = (TypeElement) declaredType.asElement(); - return typeElement.getQualifiedName().toString(); - } - return typeMirror.toString(); - } - - private boolean isConfigGroup(String type) { - if (type.startsWith("java.") || PRIMITIVE_TYPES.contains(type)) { - return false; - } - return configGroupQualifiedNameToTypeElementMap.containsKey(type) || allConfigurationGroups.hasKey(type); - } - - private boolean shouldProcessElement(final Element enclosedElement, final boolean configMapping) { - if (enclosedElement.getKind().isField()) { - return true; - } - - if (!configMapping && enclosedElement.getKind() == ElementKind.METHOD) { - return false; - } - - // A ConfigMapping method - if (enclosedElement.getKind().equals(ElementKind.METHOD)) { - ExecutableElement method = (ExecutableElement) enclosedElement; - // Skip toString method, because mappings can include it and generate it - if (method.getSimpleName().contentEquals("toString") && method.getParameters().size() == 0) { - return false; - } - Element enclosingElement = enclosedElement.getEnclosingElement(); - return enclosingElement.getModifiers().contains(ABSTRACT) && enclosedElement.getModifiers().contains(ABSTRACT); - } - - return false; - } - - private String simpleTypeToString(TypeMirror typeMirror) { - if (typeMirror.getKind().isPrimitive()) { - return typeMirror.toString(); - } else if (typeMirror.getKind() == TypeKind.ARRAY) { - return simpleTypeToString(((ArrayType) typeMirror).getComponentType()); - } - - final String knownGenericType = getKnownGenericType((DeclaredType) typeMirror); - - if (knownGenericType != null) { - return knownGenericType; - } - - List typeArguments = ((DeclaredType) typeMirror).getTypeArguments(); - if (!typeArguments.isEmpty()) { - return simpleTypeToString(typeArguments.get(0)); - } - - return getType(typeMirror); - } - - private List extractEnumValues(TypeMirror realTypeMirror, boolean useHyphenatedEnumValue, String javaDocKey) { - Element declaredTypeElement = ((DeclaredType) realTypeMirror).asElement(); - List acceptedValues = new ArrayList<>(); - - for (Element field : declaredTypeElement.getEnclosedElements()) { - if (field.getKind() == ElementKind.ENUM_CONSTANT) { - String enumValue = field.getSimpleName().toString(); - - // Find enum constant description - final String constantJavaDocKey = javaDocKey + DOT + enumValue; - final String rawJavaDoc = javaDocProperties.getProperty(constantJavaDocKey); - - String explicitEnumValueName = extractEnumValueName(field); - if (explicitEnumValueName != null) { - enumValue = explicitEnumValueName; - } else { - enumValue = useHyphenatedEnumValue ? hyphenateEnumValue(enumValue) : enumValue; - } - if (rawJavaDoc != null && !rawJavaDoc.isBlank()) { - // Show enum constant description as a Tooltip - String javaDoc = enumJavaDocParser.parseConfigDescription(rawJavaDoc); - acceptedValues.add(String.format(Constants.TOOLTIP, enumValue, - javaDoc.replace("

", EMPTY).replace("

", EMPTY).replace(NEW_LINE, " "))); - } else { - acceptedValues.add(Constants.CODE_DELIMITER - + enumValue + Constants.CODE_DELIMITER); - } - } - } - - return acceptedValues; - } - - private String extractEnumValueName(Element enumField) { - for (AnnotationMirror annotationMirror : enumField.getAnnotationMirrors()) { - String annotationName = annotationMirror.getAnnotationType().toString(); - if (annotationName.equals(ANNOTATION_CONFIG_DOC_ENUM_VALUE)) { - for (var entry : annotationMirror.getElementValues().entrySet()) { - var key = entry.getKey().toString(); - var value = entry.getValue().getValue(); - if ("value()".equals(key)) { - return value.toString(); - } - } - } - } - return null; - } - - private boolean isEnumType(TypeMirror realTypeMirror) { - return realTypeMirror instanceof DeclaredType - && ((DeclaredType) realTypeMirror).asElement().getKind() == ElementKind.ENUM; - } - - private boolean isDurationType(TypeMirror realTypeMirror) { - return realTypeMirror.toString().equals(Duration.class.getName()); - } - - /** - * Scan or parse configuration items of a given configuration group. - *

- * If the configuration group is already scanned, retrieve the scanned items and parse them - * If not, make sure that items of a given configuration group are properly scanned and the record of scanned - * configuration group if properly updated afterwards. - * - */ - private List readConfigGroupItems( - ConfigPhase configPhase, - String topLevelRootName, - String parentName, - List additionalNames, - String configGroup, - ConfigDocSection configSection, - boolean withinAMap, - boolean generateSeparateConfigGroupDocs, - boolean configMapping) - throws JsonProcessingException { - - configSection.setConfigGroupType(configGroup); - if (configSection.getSectionDetailsTitle() == null) { - configSection.setSectionDetailsTitle(parentName); - } - - if (configSection.getName() == null) { - configSection.setName(EMPTY); - } - - final List configDocItems = new ArrayList<>(); - String property = allConfigurationGroups.get(configGroup); - List groupConfigItems; - if (property != null) { - groupConfigItems = OBJECT_MAPPER.readValue(property, LIST_OF_CONFIG_ITEMS_TYPE_REF); - } else { - TypeElement configGroupTypeElement = configGroupQualifiedNameToTypeElementMap.get(configGroup); - groupConfigItems = recursivelyFindConfigItems(configGroupTypeElement, EMPTY, EMPTY, configPhase, - false, 1, generateSeparateConfigGroupDocs, configMapping); - allConfigurationGroups.put(configGroup, OBJECT_MAPPER.writeValueAsString(groupConfigItems)); - } - - groupConfigItems = decorateGroupItems(groupConfigItems, configPhase, topLevelRootName, parentName, additionalNames, - withinAMap, generateSeparateConfigGroupDocs); - - // make sure that the config section is added if it is to be shown or when scanning parent configuration group - // priory to scanning configuration roots. This is useful as we get indication of whether the config items are part - // of a configuration section (i.e. configuration group) we are current scanning. - if (configSection.isShowSection() || !generateSeparateConfigGroupDocs) { - final ConfigDocItem configDocItem = new ConfigDocItem(); - configDocItem.setConfigDocSection(configSection); - configDocItems.add(configDocItem); - configSection.addConfigDocItems(groupConfigItems); - } else { - configDocItems.addAll(groupConfigItems); - } - - if (generateSeparateConfigGroupDocs) { - addConfigGroupItemToHolder(configDocItems, configGroup); - } - - return configDocItems; - } - - /** - * Add some information which are missing from configuration items scanned from configuration groups. - * The missing information come from configuration roots and these are config phase, top level root name and parent name (as - * we are traversing down the tree) - */ - private List decorateGroupItems( - List groupConfigItems, - ConfigPhase configPhase, - String topLevelRootName, - String parentName, - List additionalNames, - boolean withinAMap, - boolean generateSeparateConfigGroupDocs) { - - List decoratedItems = new ArrayList<>(); - for (ConfigDocItem configDocItem : groupConfigItems) { - if (configDocItem.isConfigKey()) { - ConfigDocKey configDocKey = configDocItem.getConfigDocKey(); - configDocKey.setConfigPhase(configPhase); - configDocKey.setWithinAMap(configDocKey.isWithinAMap() || withinAMap); - configDocKey.setWithinAConfigGroup(true); - configDocKey.setTopLevelGrouping(topLevelRootName); - List additionalKeys = new ArrayList<>(); - for (String key : configDocKey.getAdditionalKeys()) { - additionalKeys.add(parentName + key); - for (String name : additionalNames) { - additionalKeys.add(name + key); - } - } - additionalKeys.addAll(additionalNames.stream().map(k -> k + configDocKey.getKey()).collect(toList())); - configDocKey.setAdditionalKeys(additionalKeys); - configDocKey.setKey(parentName + configDocKey.getKey()); - configDocKey.setEnvironmentVariable( - DocGeneratorUtil.toEnvVarName(parentName) + configDocKey.getEnvironmentVariable()); - decoratedItems.add(configDocItem); - } else { - ConfigDocSection section = configDocItem.getConfigDocSection(); - section.setConfigPhase(configPhase); - section.setTopLevelGrouping(topLevelRootName); - section.setWithinAMap(section.isWithinAMap() || withinAMap); - section.setName(parentName + section.getName()); - List configDocItems = decorateGroupItems( - section.getConfigDocItems(), - configPhase, - topLevelRootName, - parentName, - additionalNames, - section.isWithinAMap(), - generateSeparateConfigGroupDocs); - String configGroupType = section.getConfigGroupType(); - if (generateSeparateConfigGroupDocs) { - addConfigGroupItemToHolder(configDocItems, configGroupType); - } - - if (section.isShowSection()) { - decoratedItems.add(configDocItem); - } else { - decoratedItems.addAll(configDocItems); - } - } - } - - return decoratedItems; - } - - private void addConfigGroupItemToHolder(List configDocItems, String configGroupType) { - List previousConfigGroupConfigItems = holder.getConfigGroupConfigItems() - .get(configGroupType); - if (previousConfigGroupConfigItems == null) { - holder.addConfigGroupItems(configGroupType, configDocItems); - } else { - previousConfigGroupConfigItems.addAll(configDocItems); - } - } -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItemScanner.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItemScanner.java deleted file mode 100644 index 43d212c9393b4c..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocItemScanner.java +++ /dev/null @@ -1,289 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.computeConfigGroupDocFileName; -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.computeConfigRootDocFileName; -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.getName; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Properties; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.stream.Collectors; - -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.TypeElement; - -final public class ConfigDocItemScanner { - private static final String IO_QUARKUS_TEST_EXTENSION_PACKAGE = "io.quarkus.extest."; - - private final Set configRoots = new HashSet<>(); - private final Map configGroupsToTypeElement = new HashMap<>(); - - private final FsMap allExtensionGeneratedDocs; - private final FsMap allConfigGroupGeneratedDocs; - private final FsMultiMap configurationRootsParExtensionFileName; - - public ConfigDocItemScanner() { - this.allExtensionGeneratedDocs = new FsMap(Constants.GENERATED_DOCS_PATH - .resolve("all-configuration-roots-generated-doc")); - this.allConfigGroupGeneratedDocs = new FsMap(Constants.GENERATED_DOCS_PATH - .resolve("all-configuration-groups-generated-doc")); - this.configurationRootsParExtensionFileName = new FsMultiMap(Constants.GENERATED_DOCS_PATH - .resolve("extensions-configuration-roots-list")); - - } - - /** - * Record configuration group. It will later be visited to find configuration items. - */ - public void addConfigGroups(TypeElement configGroup) { - String configGroupName = configGroup.getQualifiedName().toString(); - if (configGroupName.startsWith(IO_QUARKUS_TEST_EXTENSION_PACKAGE)) { - return; - } - - configGroupsToTypeElement.put(configGroupName, configGroup); - } - - /** - * Record a configuration root class. It will later be visited to find configuration items. - */ - public void addConfigRoot(final PackageElement pkg, TypeElement clazz) { - if (pkg.toString().startsWith(IO_QUARKUS_TEST_EXTENSION_PACKAGE)) { - return; - } - - String prefix = Constants.QUARKUS; - ConfigPhase configPhase = ConfigPhase.BUILD_TIME; - - for (AnnotationMirror annotationMirror : clazz.getAnnotationMirrors()) { - String annotationName = annotationMirror.getAnnotationType().toString(); - if (annotationName.equals(Constants.ANNOTATION_CONFIG_ROOT)) { - final Map elementValues = annotationMirror - .getElementValues(); - String name = Constants.HYPHENATED_ELEMENT_NAME; - for (Map.Entry entry : elementValues.entrySet()) { - final String key = entry.getKey().toString(); - final String value = entry.getValue().getValue().toString(); - if ("name()".equals(key)) { - name = value; - } else if ("phase()".equals(key)) { - configPhase = ConfigPhase.valueOf(value); - } else if ("prefix()".equals(key)) { - prefix = value; - } - } - - for (AnnotationMirror mirror : clazz.getAnnotationMirrors()) { - if (mirror.getAnnotationType().toString().equals(Constants.ANNOTATION_CONFIG_MAPPING)) { - name = Constants.EMPTY; - for (Entry entry : mirror.getElementValues() - .entrySet()) { - if ("prefix()".equals(entry.getKey().toString())) { - prefix = entry.getValue().getValue().toString(); - } - } - } - } - - String docFileName = null; - for (AnnotationMirror mirror : clazz.getAnnotationMirrors()) { - if (mirror.getAnnotationType().toString().equals(Constants.ANNOTATION_CONFIG_DOC_FILE_NAME)) { - for (Entry entry : mirror.getElementValues() - .entrySet()) { - if ("value()".equals(entry.getKey().toString())) { - docFileName = entry.getValue().getValue().toString(); - break; - } - } - break; - } - } - - name = getName(prefix, name, clazz.getSimpleName().toString(), configPhase); - if (name.endsWith(Constants.DOT + Constants.PARENT)) { - // take into account the root case which would contain characters that can't be used to create the final file - name = name.replace(Constants.DOT + Constants.PARENT, ""); - } - - if (docFileName == null || docFileName.isEmpty()) { - final Matcher pkgMatcher = Constants.PKG_PATTERN.matcher(pkg.toString()); - if (pkgMatcher.find()) { - docFileName = DocGeneratorUtil.computeExtensionDocFileName(clazz.toString()); - } else { - docFileName = name.replace(Constants.DOT, Constants.DASH.charAt(0)) - + Constants.ADOC_EXTENSION; - } - } - ConfigRootInfo configRootInfo = new ConfigRootInfo(name, clazz, configPhase, docFileName); - configRoots.add(configRootInfo); - break; - } - } - } - - public Set scanExtensionsConfigurationItems(Properties javaDocProperties, boolean configMapping) - throws IOException { - - Set configDocGeneratedOutputs = new HashSet<>(); - final ConfigDocItemFinder configDocItemFinder = new ConfigDocItemFinder(configRoots, configGroupsToTypeElement, - javaDocProperties, allConfigGroupGeneratedDocs, allExtensionGeneratedDocs, configMapping); - final ScannedConfigDocsItemHolder inMemoryScannedItemsHolder = configDocItemFinder.findInMemoryConfigurationItems(); - - if (!inMemoryScannedItemsHolder.isEmpty()) { - updateScannedExtensionArtifactFiles(inMemoryScannedItemsHolder); - } - - Set allConfigItemsPerExtension = generateAllConfigItemsOutputs(inMemoryScannedItemsHolder); - Set configGroupConfigItems = generateAllConfigGroupOutputs(inMemoryScannedItemsHolder); - Set configRootConfigItems = generateAllConfigRootOutputs(inMemoryScannedItemsHolder); - - configDocGeneratedOutputs.addAll(configGroupConfigItems); - configDocGeneratedOutputs.addAll(allConfigItemsPerExtension); - configDocGeneratedOutputs.addAll(configRootConfigItems); - - return configDocGeneratedOutputs; - } - - /** - * Loads the list of configuration items per configuration root - * - */ - private Properties loadAllExtensionConfigItemsParConfigRoot() { - return allExtensionGeneratedDocs.asProperties(); - } - - /** - * Update extensions config roots. We need to gather the complete list of configuration roots of an extension - * when generating the documentation. - * - */ - private void updateConfigurationRootsList(Map.Entry> entry) { - String extensionFileName = entry.getKey().getFileName(); - String clazz = entry.getKey().getClazz().getQualifiedName().toString(); - configurationRootsParExtensionFileName.put(extensionFileName, clazz); - } - - private void updateScannedExtensionArtifactFiles(ScannedConfigDocsItemHolder inMemoryScannedItemsHolder) - throws IOException { - - for (Map.Entry> entry : inMemoryScannedItemsHolder.getConfigRootConfigItems() - .entrySet()) { - String serializableConfigRootDoc = Constants.OBJECT_MAPPER.writeValueAsString(entry.getValue()); - String clazz = entry.getKey().getClazz().getQualifiedName().toString(); - allExtensionGeneratedDocs.put(clazz, serializableConfigRootDoc); - updateConfigurationRootsList(entry); - } - - } - - private Set generateAllConfigItemsOutputs(ScannedConfigDocsItemHolder inMemoryScannedItemsHolder) - throws IOException { - Set outputs = new HashSet<>(); - - Set extensionFileNamesToGenerate = inMemoryScannedItemsHolder - .getConfigRootConfigItems() - .keySet() - .stream() - .map(ConfigRootInfo::getFileName) - .collect(Collectors.toSet()); - - for (String extensionFileName : extensionFileNamesToGenerate) { - List extensionConfigItems = new ArrayList<>(); - - for (String configRoot : configurationRootsParExtensionFileName.get(extensionFileName)) { - - List configDocItems = inMemoryScannedItemsHolder.getConfigItemsByRootClassName(configRoot); - if (configDocItems == null) { - String serializedContent = allExtensionGeneratedDocs.get(configRoot); - configDocItems = Constants.OBJECT_MAPPER.readValue(serializedContent, - Constants.LIST_OF_CONFIG_ITEMS_TYPE_REF); - } - - DocGeneratorUtil.appendConfigItemsIntoExistingOnes(extensionConfigItems, configDocItems); - } - - outputs.add(new ConfigDocGeneratedOutput(extensionFileName, true, extensionConfigItems, true)); - - List generalConfigItems = extensionConfigItems - .stream() - .filter(ConfigDocItem::isWithinAConfigGroup) - .collect(Collectors.toList()); - - if (!generalConfigItems.isEmpty()) { - String fileName = extensionFileName.replaceAll("\\.adoc$", "-general-config-items.adoc"); - outputs.add(new ConfigDocGeneratedOutput(fileName, false, generalConfigItems, true)); - } - - } - - return outputs; - } - - private Set generateAllConfigGroupOutputs( - ScannedConfigDocsItemHolder inMemoryScannedItemsHolder) { - - return inMemoryScannedItemsHolder - .getConfigGroupConfigItems() - .entrySet() - .stream() - .map(entry -> new ConfigDocGeneratedOutput(computeConfigGroupDocFileName(entry.getKey()), false, - entry.getValue(), true)) - .collect(Collectors.toSet()); - } - - private Set generateAllConfigRootOutputs(ScannedConfigDocsItemHolder inMemoryScannedItemsHolder) { - Set outputs = new HashSet<>(); - for (ConfigRootInfo configRootInfo : configRoots) { - String clazz = configRootInfo.getClazz().getQualifiedName().toString(); - List configDocItems = inMemoryScannedItemsHolder.getConfigItemsByRootClassName(clazz); - String fileName = computeConfigRootDocFileName(clazz, configRootInfo.getName()); - outputs.add(new ConfigDocGeneratedOutput(fileName, false, configDocItems, true)); - } - - return outputs; - } - - /** - * Return a Map structure which contains extension name as key and generated doc value. - */ - public Map> loadAllExtensionsConfigurationItems() - throws IOException { - - final Properties allExtensionGeneratedDocs = loadAllExtensionConfigItemsParConfigRoot(); - - final Map> foundExtensionConfigurationItems = new HashMap<>(); - - for (Entry entry : allExtensionGeneratedDocs.entrySet()) { - - final String serializedContent = (String) entry.getValue(); - if (serializedContent == null) { - continue; - } - - List configDocItems = Constants.OBJECT_MAPPER.readValue(serializedContent, - Constants.LIST_OF_CONFIG_ITEMS_TYPE_REF); - - foundExtensionConfigurationItems.put((String) entry.getKey(), configDocItems); - } - - return foundExtensionConfigurationItems; - } - - @Override - public String toString() { - return "ConfigDocItemScanner{" + - "configRoots=" + configRoots + - ", configGroups=" + configGroupsToTypeElement + - '}'; - } -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocKey.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocKey.java deleted file mode 100644 index f6733e7a301874..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocKey.java +++ /dev/null @@ -1,259 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import java.io.IOException; -import java.io.Writer; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.regex.Matcher; - -final public class ConfigDocKey implements ConfigDocElement, Comparable { - private String type; - private String key; - private List additionalKeys = new ArrayList<>(); - private String configDoc; - private boolean withinAMap; - private String defaultValue; - private String javaDocSiteLink; - private String docMapKey; - private ConfigPhase configPhase; - private List acceptedValues; - private boolean optional; - private boolean list; - private boolean withinAConfigGroup; - // if a key is "quarkus.kubernetes.part-of", then the value of this would be "kubernetes" - private String topLevelGrouping; - private boolean isEnum; - private String since; - private String environmentVariable; - - public ConfigDocKey() { - } - - public boolean hasType() { - return type != null && !type.isEmpty(); - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public boolean hasAcceptedValues() { - return acceptedValues != null && !acceptedValues.isEmpty(); - } - - public List getAcceptedValues() { - return acceptedValues; - } - - public void setAcceptedValues(List acceptedValues) { - this.acceptedValues = acceptedValues; - } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - public List getAdditionalKeys() { - return additionalKeys; - } - - public void setAdditionalKeys(final List additionalKeys) { - this.additionalKeys = additionalKeys; - } - - public void setTopLevelGrouping(String topLevelGrouping) { - this.topLevelGrouping = topLevelGrouping; - } - - public String getConfigDoc() { - return configDoc; - } - - public void setConfigDoc(String configDoc) { - this.configDoc = configDoc; - } - - public String getJavaDocSiteLink() { - if (javaDocSiteLink == null) { - return Constants.EMPTY; - } - - return javaDocSiteLink; - } - - public void setJavaDocSiteLink(String javaDocSiteLink) { - this.javaDocSiteLink = javaDocSiteLink; - } - - public String getDefaultValue() { - if (!defaultValue.isEmpty()) { - return defaultValue; - } - - final String defaultValue = DocGeneratorUtil.getPrimitiveDefaultValue(type); - - if (defaultValue == null) { - return Constants.EMPTY; - } - - return defaultValue; - } - - public void setDefaultValue(String defaultValue) { - this.defaultValue = defaultValue; - } - - public ConfigPhase getConfigPhase() { - return configPhase; - } - - public void setConfigPhase(ConfigPhase configPhase) { - this.configPhase = configPhase; - } - - public void setWithinAMap(boolean withinAMap) { - this.withinAMap = withinAMap; - } - - @SuppressWarnings("unused") - public boolean isWithinAMap() { - return withinAMap; - } - - public String computeTypeSimpleName() { - String unwrappedType = DocGeneratorUtil.unbox(type); - - Matcher matcher = Constants.CLASS_NAME_PATTERN.matcher(unwrappedType); - if (matcher.find()) { - return matcher.group(1); - } - - return unwrappedType; - } - - public void setOptional(boolean optional) { - this.optional = optional; - } - - public boolean isOptional() { - return optional; - } - - public void setList(boolean list) { - this.list = list; - } - - public boolean isList() { - return list; - } - - public String getDocMapKey() { - return docMapKey; - } - - public void setDocMapKey(String docMapKey) { - this.docMapKey = docMapKey; - } - - public boolean isWithinAConfigGroup() { - return withinAConfigGroup; - } - - public void setWithinAConfigGroup(boolean withinAConfigGroup) { - this.withinAConfigGroup = withinAConfigGroup; - } - - public String getTopLevelGrouping() { - return topLevelGrouping; - } - - public boolean isEnum() { - return isEnum; - } - - public void setEnum(boolean anEnum) { - isEnum = anEnum; - } - - public String getSince() { - return since; - } - - public void setSince(String since) { - this.since = since; - } - - public String getEnvironmentVariable() { - return environmentVariable; - } - - public void setEnvironmentVariable(String environmentVariable) { - this.environmentVariable = environmentVariable; - } - - @Override - public void accept(Writer writer, DocFormatter docFormatter) throws IOException { - docFormatter.format(writer, this); - } - - @Override - public int compareTo(ConfigDocElement o) { - return compare(o); - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - ConfigDocKey that = (ConfigDocKey) o; - return withinAMap == that.withinAMap && - optional == that.optional && - list == that.list && - withinAConfigGroup == that.withinAConfigGroup && - Objects.equals(type, that.type) && - Objects.equals(key, that.key) && - Objects.equals(configDoc, that.configDoc) && - Objects.equals(defaultValue, that.defaultValue) && - Objects.equals(javaDocSiteLink, that.javaDocSiteLink) && - Objects.equals(docMapKey, that.docMapKey) && - configPhase == that.configPhase && - Objects.equals(acceptedValues, that.acceptedValues) && - Objects.equals(topLevelGrouping, that.topLevelGrouping); - } - - @Override - public int hashCode() { - return Objects.hash(type, key, configDoc, withinAMap, defaultValue, javaDocSiteLink, docMapKey, configPhase, - acceptedValues, optional, list, withinAConfigGroup, topLevelGrouping); - } - - @Override - public String toString() { - return "ConfigDocKey{" + - "type='" + type + '\'' + - ", key='" + key + '\'' + - ", configDoc='" + configDoc + '\'' + - ", withinAMap=" + withinAMap + - ", defaultValue='" + defaultValue + '\'' + - ", javaDocSiteLink='" + javaDocSiteLink + '\'' + - ", docMapKey='" + docMapKey + '\'' + - ", configPhase=" + configPhase + - ", acceptedValues=" + acceptedValues + - ", optional=" + optional + - ", list=" + list + - ", withinAConfigGroup=" + withinAConfigGroup + - ", topLevelGrouping='" + topLevelGrouping + '\'' + - '}'; - } -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocSection.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocSection.java deleted file mode 100644 index ff04da68138314..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocSection.java +++ /dev/null @@ -1,173 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import java.io.IOException; -import java.io.Writer; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -final public class ConfigDocSection implements ConfigDocElement, Comparable { - private String name; - private boolean optional; - private boolean withinAMap; - private String sectionDetails; - private String sectionDetailsTitle; - private ConfigPhase configPhase; - private String topLevelGrouping; - private String configGroupType; - private boolean showSection; - - private List configDocItems = new ArrayList<>(); - private String anchorPrefix; - - public ConfigDocSection() { - } - - public String getConfigGroupType() { - return configGroupType; - } - - public void setConfigGroupType(String configGroupType) { - this.configGroupType = configGroupType; - } - - public boolean isShowSection() { - return showSection; - } - - public void setShowSection(boolean showSection) { - this.showSection = showSection; - } - - public boolean isWithinAMap() { - return withinAMap; - } - - public void setWithinAMap(boolean withinAMap) { - this.withinAMap = withinAMap; - } - - public ConfigPhase getConfigPhase() { - return configPhase; - } - - public void setConfigPhase(ConfigPhase configPhase) { - this.configPhase = configPhase; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getSectionDetails() { - return sectionDetails; - } - - public void setSectionDetails(String sectionDetails) { - this.sectionDetails = sectionDetails; - } - - public String getSectionDetailsTitle() { - return sectionDetailsTitle; - } - - public void setSectionDetailsTitle(String sectionDetailsTitle) { - this.sectionDetailsTitle = sectionDetailsTitle; - } - - public List getConfigDocItems() { - return configDocItems; - } - - public void setConfigDocItems(List configDocItems) { - this.configDocItems = configDocItems; - } - - public void addConfigDocItems(List configDocItems) { - this.configDocItems.addAll(configDocItems); - } - - @Override - public void accept(Writer writer, DocFormatter docFormatter) throws IOException { - docFormatter.format(writer, this); - } - - @Override - public int compareTo(ConfigDocElement o) { - return compare(o); - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - ConfigDocSection that = (ConfigDocSection) o; - return sectionDetailsTitle.equals(that.sectionDetailsTitle); - } - - @Override - public int hashCode() { - return Objects.hash(sectionDetailsTitle); - } - - @Override - public String toString() { - return "ConfigDocSection{" + - "name='" + name + '\'' + - ", optional=" + optional + - ", withinAMap=" + withinAMap + - ", sectionDetails='" + sectionDetails + '\'' + - ", sectionDetailsTitle='" + sectionDetailsTitle + '\'' + - ", configPhase=" + configPhase + - ", topLevelGrouping='" + topLevelGrouping + '\'' + - ", configDocItems=" + configDocItems + - ", anchorPrefix='" + anchorPrefix + '\'' + - '}'; - } - - public boolean hasDurationInformationNote() { - for (ConfigDocItem item : configDocItems) { - if (item.hasDurationInformationNote()) - return true; - } - return false; - } - - public boolean hasMemoryInformationNote() { - for (ConfigDocItem item : configDocItems) { - if (item.hasMemoryInformationNote()) - return true; - } - return false; - } - - public void setAnchorPrefix(String anchorPrefix) { - this.anchorPrefix = anchorPrefix; - } - - public String getAnchorPrefix() { - return anchorPrefix; - } - - public boolean isOptional() { - return optional; - } - - public void setOptional(boolean optional) { - this.optional = optional; - } - - public String getTopLevelGrouping() { - return topLevelGrouping; - } - - public void setTopLevelGrouping(String topLevelGrouping) { - this.topLevelGrouping = topLevelGrouping; - } -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocWriter.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocWriter.java deleted file mode 100644 index 773cab80eae2be..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigDocWriter.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import java.io.IOException; -import java.io.Writer; -import java.nio.file.Files; -import java.nio.file.Path; - -final public class ConfigDocWriter { - - /** - * Write all extension configuration in AsciiDoc format in `{root}/target/asciidoc/generated/config/` directory - */ - public void writeAllExtensionConfigDocumentation(ConfigDocGeneratedOutput output) - throws IOException { - - if (output.getConfigDocItems().isEmpty()) { - return; - } - - // Create single summary table - final var configDocBuilder = new ConfigDocBuilder().addSummaryTable(output.getAnchorPrefix(), output.isSearchable(), - output.getConfigDocItems(), output.getFileName(), true); - - generateDocumentation(output.getFileName(), configDocBuilder); - } - - 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()); - } - - 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); - } - } - } - -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigPhase.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigPhase.java deleted file mode 100644 index 95d47e7b6cf6b8..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigPhase.java +++ /dev/null @@ -1,78 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import java.util.Comparator; - -public enum ConfigPhase implements Comparable { - RUN_TIME("The configuration is overridable at runtime", "", "RunTime"), - BUILD_TIME("The configuration is not overridable at runtime", Constants.CONFIG_PHASE_BUILD_TIME_ILLUSTRATION, "BuildTime"), - BUILD_AND_RUN_TIME_FIXED("The configuration is not overridable at runtime", Constants.CONFIG_PHASE_BUILD_TIME_ILLUSTRATION, - "BuildTime"); - - static final Comparator COMPARATOR = new Comparator() { - /** - * Order built time phase first - * Then build time run time fixed phase - * Then runtime one - */ - @Override - public int compare(ConfigPhase firstPhase, ConfigPhase secondPhase) { - switch (firstPhase) { - case BUILD_TIME: { - switch (secondPhase) { - case BUILD_TIME: - return 0; - default: - return -1; - } - } - case BUILD_AND_RUN_TIME_FIXED: { - switch (secondPhase) { - case BUILD_TIME: - return 1; - case BUILD_AND_RUN_TIME_FIXED: - return 0; - default: - return -1; - } - } - case RUN_TIME: { - switch (secondPhase) { - case RUN_TIME: - return 0; - default: - return 1; - } - } - default: - return 0; - } - } - }; - - private String description; - private String illustration; - private String configSuffix; - - ConfigPhase(String description, String illustration, String configSuffix) { - this.description = description; - this.illustration = illustration; - this.configSuffix = configSuffix; - } - - @Override - public String toString() { - return "ConfigPhase{" + - "description='" + description + '\'' + - ", illustration='" + illustration + '\'' + - ", configSuffix='" + configSuffix + '\'' + - '}'; - } - - public String getIllustration() { - return illustration; - } - - public String getConfigSuffix() { - return configSuffix; - } -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigRootInfo.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigRootInfo.java deleted file mode 100644 index 786c07fc871863..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ConfigRootInfo.java +++ /dev/null @@ -1,69 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import java.util.Objects; - -import javax.lang.model.element.TypeElement; - -final public class ConfigRootInfo { - private final String name; - private final TypeElement clazz; - private final ConfigPhase configPhase; - private final String fileName; - - public ConfigRootInfo( - final String name, - final TypeElement clazz, - final ConfigPhase configPhase, - final String fileName) { - this.name = name; - this.clazz = clazz; - this.configPhase = configPhase; - this.fileName = fileName; - } - - public String getFileName() { - return fileName; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - final ConfigRootInfo that = (ConfigRootInfo) o; - return name.equals(that.name) && - clazz.equals(that.clazz) && - configPhase == that.configPhase && - fileName.equals(that.fileName); - } - - @Override - public int hashCode() { - return Objects.hash(name, clazz, configPhase, fileName); - } - - @Override - public String toString() { - return "ConfigRootInfo{" + - "name='" + name + '\'' + - ", clazz=" + clazz + - ", configPhase=" + configPhase + - ", fileName='" + fileName + '\'' + - '}'; - } - - public String getName() { - return name; - } - - public TypeElement getClazz() { - return clazz; - } - - public ConfigPhase getConfigPhase() { - return configPhase; - } -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/Constants.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/Constants.java deleted file mode 100644 index 75ce923e755dd7..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/Constants.java +++ /dev/null @@ -1,139 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.Duration; -import java.util.List; -import java.util.Map; -import java.util.OptionalDouble; -import java.util.OptionalInt; -import java.util.OptionalLong; -import java.util.Properties; -import java.util.Set; -import java.util.regex.Pattern; - -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; - -final public class Constants { - public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - public static TypeReference> LIST_OF_CONFIG_ITEMS_TYPE_REF = new TypeReference<>() { - }; - - public static final char DOT = '.'; - public static final String CODE_DELIMITER = "`"; - public static final String EMPTY = ""; - 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 = "<>"; - public static final String NO_DEFAULT = "<>"; - public static final String HYPHENATED_ELEMENT_NAME = "<>"; - - public static final String COMMON = "common"; - public static final String RUNTIME = "runtime"; - public static final String DEPLOYMENT = "deployment"; - public static final String CONFIG = "config"; - - public static final Pattern CLASS_NAME_PATTERN = Pattern.compile("^.+[\\.$](\\w+)$"); - public static final Pattern PKG_PATTERN = Pattern - .compile("^io\\.quarkus\\.(\\w+)\\.?(\\w+)?\\.?(\\w+)?\\.?(\\w+)?\\.?(\\w+)?"); - - public static final String INSTANCE_SYM = "__instance"; - public static final String QUARKUS = "quarkus"; - - public static final String ANNOTATION_RECORDER = "io.quarkus.runtime.annotations.Recorder"; - public static final String ANNOTATION_RECORD = "io.quarkus.deployment.annotations.Record"; - - public static final String MEMORY_SIZE_TYPE = "io.quarkus.runtime.configuration.MemorySize"; - public static final String ANNOTATION_CONFIG_ITEM = "io.quarkus.runtime.annotations.ConfigItem"; - public static final String ANNOTATION_BUILD_STEP = "io.quarkus.deployment.annotations.BuildStep"; - public static final String ANNOTATION_CONFIG_ROOT = "io.quarkus.runtime.annotations.ConfigRoot"; - public static final String ANNOTATION_CONFIG_MAPPING = "io.smallrye.config.ConfigMapping"; - public static final String ANNOTATION_DEFAULT_CONVERTER = "io.quarkus.runtime.annotations.DefaultConverter"; - public static final String ANNOTATION_CONVERT_WITH = "io.quarkus.runtime.annotations.ConvertWith"; - public static final String ANNOTATION_CONFIG_GROUP = "io.quarkus.runtime.annotations.ConfigGroup"; - public static final String ANNOTATION_CONFIG_DOC_IGNORE = "io.quarkus.runtime.annotations.ConfigDocIgnore"; - public static final String ANNOTATION_CONFIG_DOC_MAP_KEY = "io.quarkus.runtime.annotations.ConfigDocMapKey"; - public static final String ANNOTATION_CONFIG_DOC_SECTION = "io.quarkus.runtime.annotations.ConfigDocSection"; - public static final String ANNOTATION_CONFIG_DOC_ENUM_VALUE = "io.quarkus.runtime.annotations.ConfigDocEnumValue"; - public static final String ANNOTATION_CONFIG_DOC_DEFAULT = "io.quarkus.runtime.annotations.ConfigDocDefault"; - public static final String ANNOTATION_CONFIG_DOC_FILE_NAME = "io.quarkus.runtime.annotations.ConfigDocFilename"; - - public static final String ANNOTATION_CONFIG_WITH_NAME = "io.smallrye.config.WithName"; - public static final String ANNOTATION_CONFIG_WITH_PARENT_NAME = "io.smallrye.config.WithParentName"; - public static final String ANNOTATION_CONFIG_WITH_DEFAULT = "io.smallrye.config.WithDefault"; - public static final String ANNOTATION_CONFIG_WITH_UNNAMED_KEY = "io.smallrye.config.WithUnnamedKey"; - - public static final Set SUPPORTED_ANNOTATIONS_TYPES = Set.of(ANNOTATION_BUILD_STEP, ANNOTATION_CONFIG_GROUP, - ANNOTATION_CONFIG_ROOT, ANNOTATION_RECORDER, ANNOTATION_CONFIG_MAPPING); - - public static final Map ALIASED_TYPES = Map.of( - OptionalLong.class.getName(), Long.class.getName(), - OptionalInt.class.getName(), Integer.class.getName(), - OptionalDouble.class.getName(), Double.class.getName(), - "java.lang.Class", "class name", - "java.net.InetSocketAddress", "host:port", - Path.class.getName(), "path", - String.class.getName(), "string"); - - private static final Properties SYSTEM_PROPERTIES = System.getProperties(); - - private static final String DOCS_SRC_MAIN_ASCIIDOC_GENERATED = "/target/asciidoc/generated/config/"; - private static final String DOCS_OUT_DIR = System.getProperty("quarkus.docsOutputDir", - SYSTEM_PROPERTIES.getProperty("maven.multiModuleProjectDirectory", ".")); - public static final Path GENERATED_DOCS_PATH = Paths.get(DOCS_OUT_DIR + DOCS_SRC_MAIN_ASCIIDOC_GENERATED).toAbsolutePath(); - public static final String SUMMARY_TABLE_ID_VARIABLE = "summaryTableId"; - public static final String DURATION_NOTE_ANCHOR = String.format("duration-note-anchor-{%s}", - SUMMARY_TABLE_ID_VARIABLE); - public static final String MEMORY_SIZE_NOTE_ANCHOR = "memory-size-note-anchor"; - public static final String MORE_INFO_ABOUT_TYPE_FORMAT = " link:#%s[icon:question-circle[title=More information about the %s format]]"; - public static final String DURATION_INFORMATION = String.format(Constants.MORE_INFO_ABOUT_TYPE_FORMAT, - Constants.DURATION_NOTE_ANCHOR, Duration.class.getSimpleName()); - public static final String MEMORY_SIZE_INFORMATION = String.format(Constants.MORE_INFO_ABOUT_TYPE_FORMAT, - Constants.MEMORY_SIZE_NOTE_ANCHOR, "MemorySize"); - - public static final String CONFIG_PHASE_BUILD_TIME_ILLUSTRATION = "icon:lock[title=Fixed at build time]"; - public static final String CONFIG_PHASE_LEGEND = String.format( - "%n%s Configuration property fixed at build time - All other configuration properties are overridable at runtime", - CONFIG_PHASE_BUILD_TIME_ILLUSTRATION); - - public static final String DURATION_FORMAT_NOTE = "\nifndef::no-duration-note[]\n[NOTE]" + - "\n[id='" + DURATION_NOTE_ANCHOR + "']\n" + - ".About the Duration format\n" + - "====\n" + - "To write duration values, use the standard `java.time.Duration` format.\n" + - "See the link:https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html#parse(java.lang.CharSequence)[Duration#parse() Java API documentation] for more information.\n" - + - "\n" + - "You can also use a simplified format, starting with a number:\n" + - "\n" + - "* If the value is only a number, it represents time in seconds.\n" + - "* If the value is a number followed by `ms`, it represents time in milliseconds.\n" + - "\n" + - "In other cases, the simplified format is translated to the `java.time.Duration` format for parsing:\n" + - "\n" + - "* If the value is a number followed by `h`, `m`, or `s`, it is prefixed with `PT`.\n" + - "* If the value is a number followed by `d`, it is prefixed with `P`" + - ".\n" + - "====\n" + - "endif::no-duration-note[]\n"; - - public static final String MEMORY_SIZE_FORMAT_NOTE = "\n[NOTE]" + - "\n[[" + MEMORY_SIZE_NOTE_ANCHOR + "]]\n" + - ".About the MemorySize format\n" + - "====\n" + - "A size configuration option recognises string in this format (shown as a regular expression): `[0-9]+[KkMmGgTtPpEeZzYy]?`.\n" - + - "If no suffix is given, assume bytes.\n" + - "====\n"; - - /** - * Tooltip is custom AsciiDoc inline macro that transforms inputs to a CSS Tooltip. - */ - public static final String TOOLTIP = "tooltip:%s[%s]"; - -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/DocFormatter.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/DocFormatter.java deleted file mode 100644 index e153f1aa0afc63..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/DocFormatter.java +++ /dev/null @@ -1,70 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import java.io.IOException; -import java.io.Writer; -import java.text.Normalizer; -import java.util.List; - -interface DocFormatter { - default String getAnchor(String string) { - // remove accents - string = Normalizer.normalize(string, Normalizer.Form.NFKC) - .replaceAll("[àáâãäåāąă]", "a") - .replaceAll("[çćčĉċ]", "c") - .replaceAll("[ďđð]", "d") - .replaceAll("[èéêëēęěĕė]", "e") - .replaceAll("[ƒſ]", "f") - .replaceAll("[ĝğġģ]", "g") - .replaceAll("[ĥħ]", "h") - .replaceAll("[ìíîïīĩĭįı]", "i") - .replaceAll("[ijĵ]", "j") - .replaceAll("[ķĸ]", "k") - .replaceAll("[łľĺļŀ]", "l") - .replaceAll("[ñńňņʼnŋ]", "n") - .replaceAll("[òóôõöøōőŏœ]", "o") - .replaceAll("[Þþ]", "p") - .replaceAll("[ŕřŗ]", "r") - .replaceAll("[śšşŝș]", "s") - .replaceAll("[ťţŧț]", "t") - .replaceAll("[ùúûüūůűŭũų]", "u") - .replaceAll("[ŵ]", "w") - .replaceAll("[ýÿŷ]", "y") - .replaceAll("[žżź]", "z") - .replaceAll("[æ]", "ae") - .replaceAll("[ÀÁÂÃÄÅĀĄĂ]", "A") - .replaceAll("[ÇĆČĈĊ]", "C") - .replaceAll("[ĎĐÐ]", "D") - .replaceAll("[ÈÉÊËĒĘĚĔĖ]", "E") - .replaceAll("[ĜĞĠĢ]", "G") - .replaceAll("[ĤĦ]", "H") - .replaceAll("[ÌÍÎÏĪĨĬĮİ]", "I") - .replaceAll("[Ĵ]", "J") - .replaceAll("[Ķ]", "K") - .replaceAll("[ŁĽĹĻĿ]", "L") - .replaceAll("[ÑŃŇŅŊ]", "N") - .replaceAll("[ÒÓÔÕÖØŌŐŎ]", "O") - .replaceAll("[ŔŘŖ]", "R") - .replaceAll("[ŚŠŞŜȘ]", "S") - .replaceAll("[ÙÚÛÜŪŮŰŬŨŲ]", "U") - .replaceAll("[Ŵ]", "W") - .replaceAll("[ÝŶŸ]", "Y") - .replaceAll("[ŹŽŻ]", "Z") - .replaceAll("[ß]", "ss"); - - // Apostrophes. - string = string.replaceAll("([a-z])'s([^a-z])", "$1s$2"); - // Allow only letters, -, _ - string = string.replaceAll("[^\\w-_]", "-").replaceAll("-{2,}", "-"); - // Get rid of any - at the start and end. - string = string.replaceAll("-+$", "").replaceAll("^-+", ""); - - return string.toLowerCase(); - } - - void format(Writer writer, String initialAnchorPrefix, boolean activateSearch, List configDocItems, - boolean includeConfigPhaseLegend) throws IOException; - - void format(Writer writer, ConfigDocKey configDocKey) throws IOException; - - void format(Writer writer, ConfigDocSection configDocSection) throws IOException; -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/DocGeneratorUtil.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/DocGeneratorUtil.java deleted file mode 100644 index ae33d07e253d79..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/DocGeneratorUtil.java +++ /dev/null @@ -1,532 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import java.time.Duration; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.logging.Level; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeMirror; - -public class DocGeneratorUtil { - private static final String NEW_LINE = "\n"; - private static final String CORE = "core"; - private static final String CONFIG = "Config"; - private static final String CONFIGURATION = "Configuration"; - public static final String LEVEL_HACK_URL = "https://docs.jboss.org/jbossas/javadoc/7.1.2.Final/org/jboss/logmanager/Level.html"; - private static String CONFIG_GROUP_DOC_PREFIX = "config-group-"; - static final String VERTX_JAVA_DOC_SITE = "https://vertx.io/docs/apidocs/"; - static final String OFFICIAL_JAVA_DOC_BASE_LINK = "https://docs.oracle.com/javase/8/docs/api/"; - static final String AGROAL_API_JAVA_DOC_SITE = "https://jar-download.com/javaDoc/io.agroal/agroal-api/1.5/index.html?"; - - private static final Map JAVA_PRIMITIVE_WRAPPERS = new HashMap<>(); - private static final Map PRIMITIVE_DEFAULT_VALUES = new HashMap<>(); - private static final Map EXTENSION_JAVA_DOC_LINK = new HashMap<>(); - private static Pattern PACKAGE_PATTERN = Pattern.compile("^(\\w+)\\.(\\w+)\\..*$"); - private static final String HYPHEN = "-"; - private static final Pattern PATTERN = Pattern.compile("([-_]+)"); - - static { - PRIMITIVE_DEFAULT_VALUES.put("int", "0"); - PRIMITIVE_DEFAULT_VALUES.put("byte", "0"); - PRIMITIVE_DEFAULT_VALUES.put("char", ""); - PRIMITIVE_DEFAULT_VALUES.put("short", "0"); - PRIMITIVE_DEFAULT_VALUES.put("long", "0l"); - PRIMITIVE_DEFAULT_VALUES.put("float", "0f"); - PRIMITIVE_DEFAULT_VALUES.put("double", "0d"); - PRIMITIVE_DEFAULT_VALUES.put("boolean", "false"); - - JAVA_PRIMITIVE_WRAPPERS.put("java.lang.Character", "char"); - JAVA_PRIMITIVE_WRAPPERS.put("java.lang.Boolean", "boolean"); - JAVA_PRIMITIVE_WRAPPERS.put("java.lang.Byte", "byte"); - JAVA_PRIMITIVE_WRAPPERS.put("java.lang.Short", "short"); - JAVA_PRIMITIVE_WRAPPERS.put("java.lang.Integer", "int"); - JAVA_PRIMITIVE_WRAPPERS.put("java.lang.Long", "long"); - JAVA_PRIMITIVE_WRAPPERS.put("java.lang.Float", "float"); - JAVA_PRIMITIVE_WRAPPERS.put("java.lang.Double", "double"); - - EXTENSION_JAVA_DOC_LINK.put("io.vertx.", VERTX_JAVA_DOC_SITE); - EXTENSION_JAVA_DOC_LINK.put("io.agroal.", AGROAL_API_JAVA_DOC_SITE); - } - - /** - * Retrieve a default value of a primitive type. - * If type is not a primitive, returns false - * - */ - static String getPrimitiveDefaultValue(String primitiveType) { - return PRIMITIVE_DEFAULT_VALUES.get(primitiveType); - } - - /** - * Replaces Java primitive wrapper types with primitive types - */ - static String unbox(String type) { - String mapping = JAVA_PRIMITIVE_WRAPPERS.get(type); - return mapping == null ? type : mapping; - } - - /** - * Get javadoc link of a given type value - */ - static String getJavaDocSiteLink(String type) { - if (type.equals(Level.class.getName())) { - //hack, we don't want to link to the JUL version, but the jboss logging version - //this seems like a one off use case so for now it is just hacked in here - //if there are other use cases we should do something more generic - return LEVEL_HACK_URL; - } - Matcher packageMatcher = PACKAGE_PATTERN.matcher(type); - - if (!packageMatcher.find()) { - return Constants.EMPTY; - } - - if (JAVA_PRIMITIVE_WRAPPERS.containsKey(type)) { - return Constants.EMPTY; - } - - if ("java".equals(packageMatcher.group(1))) { - return OFFICIAL_JAVA_DOC_BASE_LINK + getJavaDocLinkForType(type); - } - - String basePkgName = packageMatcher.group(1) + "." + packageMatcher.group(2) + "."; - String javaDocBaseUrl = EXTENSION_JAVA_DOC_LINK.get(basePkgName); - - if (javaDocBaseUrl != null) { - return javaDocBaseUrl + getJavaDocLinkForType(type); - } - - return Constants.EMPTY; - } - - private static String getJavaDocLinkForType(String type) { - int beginOfWrappedTypeIndex = type.indexOf("<"); - if (beginOfWrappedTypeIndex != -1) { - type = type.substring(0, beginOfWrappedTypeIndex); - } - - int indexOfFirstUpperCase = 0; - for (int index = 0; index < type.length(); index++) { - char charAt = type.charAt(index); - if (charAt >= 'A' && charAt <= 'Z') { - indexOfFirstUpperCase = index; - break; - } - } - - final String base = type.substring(0, indexOfFirstUpperCase).replace('.', '/'); - final String html = type.substring(indexOfFirstUpperCase).replace('$', '.') + ".html"; - - return base + html; - } - - /** - * Retrieve enclosed type from known optional types - */ - static String getKnownGenericType(DeclaredType declaredType) { - return Constants.ALIASED_TYPES.get(declaredType.toString()); - } - - static Iterator camelHumpsIterator(String str) { - return new Iterator() { - int idx; - - @Override - public boolean hasNext() { - return idx < str.length(); - } - - @Override - public String next() { - if (idx == str.length()) - throw new NoSuchElementException(); - // known mixed-case rule-breakers - if (str.startsWith("JBoss", idx)) { - idx += 5; - return "JBoss"; - } - final int start = idx; - int c = str.codePointAt(idx); - if (Character.isUpperCase(c)) { - // an uppercase-starting word - idx = str.offsetByCodePoints(idx, 1); - if (idx < str.length()) { - c = str.codePointAt(idx); - if (Character.isUpperCase(c)) { - // all-caps word; need one look-ahead - int nextIdx = str.offsetByCodePoints(idx, 1); - while (nextIdx < str.length()) { - c = str.codePointAt(nextIdx); - if (Character.isLowerCase(c)) { - // ended at idx - return str.substring(start, idx); - } - idx = nextIdx; - nextIdx = str.offsetByCodePoints(idx, 1); - } - // consumed the whole remainder, update idx to length - idx = str.length(); - return str.substring(start); - } else { - // initial caps, trailing lowercase - idx = str.offsetByCodePoints(idx, 1); - while (idx < str.length()) { - c = str.codePointAt(idx); - if (Character.isUpperCase(c)) { - // end - return str.substring(start, idx); - } - idx = str.offsetByCodePoints(idx, 1); - } - // consumed the whole remainder - return str.substring(start); - } - } else { - // one-letter word - return str.substring(start); - } - } else { - // a lowercase-starting word - idx = str.offsetByCodePoints(idx, 1); - while (idx < str.length()) { - c = str.codePointAt(idx); - if (Character.isUpperCase(c)) { - // end - return str.substring(start, idx); - } - idx = str.offsetByCodePoints(idx, 1); - } - // consumed the whole remainder - return str.substring(start); - } - } - }; - } - - static Iterator lowerCase(Iterator orig) { - return new Iterator() { - @Override - public boolean hasNext() { - return orig.hasNext(); - } - - @Override - public String next() { - return orig.next().toLowerCase(Locale.ROOT); - } - }; - } - - static String join(Iterator it) { - final StringBuilder b = new StringBuilder(); - if (it.hasNext()) { - b.append(it.next()); - while (it.hasNext()) { - b.append("-"); - b.append(it.next()); - } - } - return b.toString(); - } - - static String hyphenate(String orig) { - return join(lowerCase(camelHumpsIterator(orig))); - } - - /** - * This needs to be consistent with io.quarkus.runtime.configuration.HyphenateEnumConverter. - */ - static String hyphenateEnumValue(String orig) { - StringBuffer target = new StringBuffer(); - String hyphenate = hyphenate(orig); - Matcher matcher = PATTERN.matcher(hyphenate); - while (matcher.find()) { - matcher.appendReplacement(target, HYPHEN); - } - matcher.appendTail(target); - return target.toString(); - } - - static String normalizeDurationValue(String value) { - if (!value.isEmpty() && Character.isDigit(value.charAt(value.length() - 1))) { - try { - value = Integer.parseInt(value) + "S"; - } catch (NumberFormatException ignore) { - } - } - value = value.toUpperCase(Locale.ROOT); - return value; - } - - static String joinAcceptedValues(List acceptedValues) { - if (acceptedValues == null || acceptedValues.isEmpty()) { - return ""; - } - - return acceptedValues.stream().collect(Collectors.joining("`, `", Constants.CODE_DELIMITER, Constants.CODE_DELIMITER)); - } - - static String joinEnumValues(List enumValues) { - if (enumValues == null || enumValues.isEmpty()) { - return Constants.EMPTY; - } - - // nested macros are only detected when cell starts with a new line, e.g. a|\n myMacro::[] - return NEW_LINE + String.join(", ", enumValues); - } - - static String getTypeFormatInformationNote(ConfigDocKey configDocKey) { - if (configDocKey.getType().equals(Duration.class.getName())) { - return Constants.DURATION_INFORMATION; - } else if (configDocKey.getType().equals(Constants.MEMORY_SIZE_TYPE)) { - return Constants.MEMORY_SIZE_INFORMATION; - } - - return Constants.EMPTY; - } - - static boolean hasDurationInformationNote(ConfigDocKey configDocKey) { - return configDocKey.hasType() && configDocKey.getType().equals(Duration.class.getName()); - } - - static boolean hasMemoryInformationNote(ConfigDocKey configDocKey) { - return configDocKey.hasType() && configDocKey.getType().equals(Constants.MEMORY_SIZE_TYPE); - } - - /** - * Guess extension name from given configuration root class name - */ - public static String computeExtensionDocFileName(String configRoot) { - StringBuilder extensionNameBuilder = new StringBuilder(); - final Matcher matcher = Constants.PKG_PATTERN.matcher(configRoot); - if (!matcher.find()) { - extensionNameBuilder.append(configRoot); - } else { - String extensionName = matcher.group(1); - extensionNameBuilder.append(Constants.QUARKUS); - extensionNameBuilder.append(Constants.DASH); - - if (Constants.DEPLOYMENT.equals(extensionName) || Constants.RUNTIME.equals(extensionName)) { - extensionNameBuilder.append(CORE); - } else { - extensionNameBuilder.append(extensionName); - for (int i = 2; i <= matcher.groupCount(); i++) { - String subgroup = matcher.group(i); - if (Constants.DEPLOYMENT.equals(subgroup) - || Constants.RUNTIME.equals(subgroup) - || Constants.COMMON.equals(subgroup) - || !subgroup.matches(Constants.DIGIT_OR_LOWERCASE)) { - break; - } - if (i > 3 && Constants.CONFIG.equals(subgroup)) { - // this is a bit dark magic, but we have config packages as valid extension names - // and config packages where the configuration is stored - break; - } - extensionNameBuilder.append(Constants.DASH); - extensionNameBuilder.append(matcher.group(i)); - } - } - } - - extensionNameBuilder.append(Constants.ADOC_EXTENSION); - return extensionNameBuilder.toString(); - } - - /** - * Guess config group file name from given configuration group class name - */ - public static String computeConfigGroupDocFileName(String configGroupClassName) { - final String sanitizedClassName; - final Matcher matcher = Constants.PKG_PATTERN.matcher(configGroupClassName); - - if (!matcher.find()) { - sanitizedClassName = CONFIG_GROUP_DOC_PREFIX + Constants.DASH + hyphenate(configGroupClassName); - } else { - String replacement = Constants.DASH + CONFIG_GROUP_DOC_PREFIX + Constants.DASH; - sanitizedClassName = configGroupClassName - .replaceFirst("io.", "") - .replaceFirst("\\.runtime\\.", replacement) - .replaceFirst("\\.deployment\\.", replacement); - } - - return hyphenate(sanitizedClassName) - .replaceAll("[\\.-]+", Constants.DASH) - + Constants.ADOC_EXTENSION; - } - - /** - * Guess config root file name from given configuration root class name. - */ - public static String computeConfigRootDocFileName(String configRootClassName, String rootName) { - String sanitizedClassName; - final Matcher matcher = Constants.PKG_PATTERN.matcher(configRootClassName); - - if (!matcher.find()) { - sanitizedClassName = rootName + Constants.DASH + hyphenate(configRootClassName); - } else { - String deployment = Constants.DOT + Constants.DEPLOYMENT + Constants.DOT; - String runtime = Constants.DOT + Constants.RUNTIME + Constants.DOT; - - if (configRootClassName.contains(deployment)) { - sanitizedClassName = configRootClassName - .substring(configRootClassName.indexOf(deployment) + deployment.length()); - } else if (configRootClassName.contains(runtime)) { - sanitizedClassName = configRootClassName.substring(configRootClassName.indexOf(runtime) + runtime.length()); - } else { - sanitizedClassName = configRootClassName.replaceFirst("io.quarkus.", ""); - } - - sanitizedClassName = rootName + Constants.DASH + sanitizedClassName; - } - - return hyphenate(sanitizedClassName) - .replaceAll("[\\.-]+", Constants.DASH) - + Constants.ADOC_EXTENSION; - } - - public static void appendConfigItemsIntoExistingOnes(List existingConfigItems, - List configDocItems) { - for (ConfigDocItem configDocItem : configDocItems) { - if (configDocItem.isConfigKey()) { - existingConfigItems.add(configDocItem); - } else { - ConfigDocSection configDocSection = configDocItem.getConfigDocSection(); - boolean configSectionMerged = mergeSectionIntoPreviousExistingConfigItems(configDocSection, - existingConfigItems); - if (!configSectionMerged) { - existingConfigItems.add(configDocItem); - } - } - } - } - - /** - * returns true if section is merged into one of the existing config items, false otherwise - */ - private static boolean mergeSectionIntoPreviousExistingConfigItems(ConfigDocSection section, - List configDocItems) { - for (ConfigDocItem configDocItem : configDocItems) { - if (configDocItem.isConfigKey()) { - continue; - } - - ConfigDocSection configDocSection = configDocItem.getConfigDocSection(); - if (configDocSection.equals(section)) { - appendConfigItemsIntoExistingOnes(configDocSection.getConfigDocItems(), section.getConfigDocItems()); - return true; - } else { - boolean configSectionMerged = mergeSectionIntoPreviousExistingConfigItems(section, - configDocSection.getConfigDocItems()); - if (configSectionMerged) { - return true; - } - } - } - - return false; - } - - static String stringifyType(TypeMirror typeMirror) { - List typeArguments = ((DeclaredType) typeMirror).getTypeArguments(); - String simpleName = typeSimpleName(typeMirror); - if (typeArguments.isEmpty()) { - return simpleName; - } else if (typeArguments.size() == 1) { - return String.format("%s<%s>", simpleName, stringifyType(typeArguments.get(0))); - } else if (typeArguments.size() == 2) { - return String.format("%s<%s,%s>", simpleName, stringifyType(typeArguments.get(0)), - stringifyType(typeArguments.get(1))); - } - - return "unknown"; // we should not reach here - } - - private static String typeSimpleName(TypeMirror typeMirror) { - String type = ((DeclaredType) typeMirror).asElement().toString(); - return type.substring(1 + type.lastIndexOf(Constants.DOT)); - } - - static String getName(String prefix, String name, String simpleClassName, ConfigPhase configPhase) { - if (name.equals(Constants.HYPHENATED_ELEMENT_NAME)) { - return deriveConfigRootName(simpleClassName, prefix, configPhase); - } - - if (!prefix.isEmpty()) { - if (!name.isEmpty()) { - return prefix + Constants.DOT + name; - } else { - return prefix; - } - } else { - return name; - } - } - - /** - * Replace each character that is neither alphanumeric nor _ with _ then convert the name to upper case, e.g. - * quarkus.datasource.jdbc.initial-size -> QUARKUS_DATASOURCE_JDBC_INITIAL_SIZE - * See also: io.smallrye.config.common.utils.StringUtil#replaceNonAlphanumericByUnderscores(java.lang.String) - */ - static String toEnvVarName(final String name) { - int length = name.length(); - StringBuilder sb = new StringBuilder(length); - for (int i = 0; i < length; i++) { - char c = name.charAt(i); - if ('a' <= c && c <= 'z' || - 'A' <= c && c <= 'Z' || - '0' <= c && c <= '9') { - sb.append(c); - } else { - sb.append('_'); - } - } - return sb.toString().toUpperCase(); - } - - static String deriveConfigRootName(String simpleClassName, String prefix, ConfigPhase configPhase) { - String simpleNameInLowerCase = simpleClassName.toLowerCase(); - int length = simpleNameInLowerCase.length(); - - if (simpleNameInLowerCase.endsWith(CONFIG.toLowerCase())) { - String sanitized = simpleClassName.substring(0, length - CONFIG.length()); - return deriveConfigRootName(sanitized, prefix, configPhase); - } else if (simpleNameInLowerCase.endsWith(CONFIGURATION.toLowerCase())) { - String sanitized = simpleClassName.substring(0, length - CONFIGURATION.length()); - return deriveConfigRootName(sanitized, prefix, configPhase); - } else if (simpleNameInLowerCase.endsWith(configPhase.getConfigSuffix().toLowerCase())) { - String sanitized = simpleClassName.substring(0, length - configPhase.getConfigSuffix().length()); - return deriveConfigRootName(sanitized, prefix, configPhase); - } - - return !prefix.isEmpty() ? prefix + Constants.DOT + hyphenate(simpleClassName) - : Constants.QUARKUS + Constants.DOT + hyphenate(simpleClassName); - } - - /** - * Sort docs keys. The sorted list will contain the properties in the following order - * - 1. Map config items as last elements of the generated docs. - * - 2. Build time properties will come first. - * - 3. Otherwise, respect source code declaration order. - * - 4. Elements within a configuration section will appear at the end of the generated doc while preserving described in - * 1-4. - */ - public static void sort(List configDocItems) { - Collections.sort(configDocItems); - for (ConfigDocItem configDocItem : configDocItems) { - if (configDocItem.isConfigSection()) { - sort(configDocItem.getConfigDocSection().getConfigDocItems()); - } - } - } - -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/FsMap.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/FsMap.java deleted file mode 100644 index 2cb0492bd84301..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/FsMap.java +++ /dev/null @@ -1,95 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Properties; -import java.util.stream.Stream; - -/** - * A file system backed map. - */ -public class FsMap { - - private final Path dir; - - public FsMap(Path dir) { - this.dir = safeCreateDirectories(dir); - } - - public String get(String key) { - final Path file = dir.resolve(key); - if (Files.exists(file)) { - try { - return Files.readString(file); - } catch (IOException e) { - throw new RuntimeException("Could not read " + file, e); - } - } else { - return null; - } - } - - public void put(String key, String value) { - final Path file = dir.resolve(key); - try { - Files.write(file, value.getBytes(StandardCharsets.UTF_8)); - } catch (IOException e) { - throw new RuntimeException("Could not write " + file, e); - } - } - - public boolean hasKey(String key) { - final Path file = dir.resolve(key); - return Files.exists(file); - } - - /** - * Attempts to call {@link Files#createDirectories(Path, java.nio.file.attribute.FileAttribute...)} with the given - * {@code dir} at most {@code dir.getNameCount()} times as long as it does not exist, assuming that other treads - * may try to create the same directory concurrently. - * - * @param dir the directory to create - * @throws RuntimeException A wrapped {@link IOException} thrown by the last call to - * {@link Files#createDirectories(Path, java.nio.file.attribute.FileAttribute...)} - */ - static Path safeCreateDirectories(Path dir) { - IOException lastException; - int retries = dir.getNameCount(); - do { - if (Files.exists(dir)) { - return dir; - } - try { - Files.createDirectories(dir); - return dir; - } catch (IOException e) { - lastException = e; - } - } while (retries-- > 0); - throw new RuntimeException("Could not create directories " + dir, lastException); - } - - public Properties asProperties() { - final Properties result = new Properties(); - if (Files.exists(dir)) { - try (Stream files = Files.list(dir)) { - files - .filter(Files::isRegularFile) - .forEach(f -> { - try { - result.setProperty(f.getFileName().toString(), - Files.readString(f)); - } catch (IOException e) { - throw new IllegalStateException("Could not read from " + f, e); - } - }); - } catch (IOException e) { - throw new RuntimeException("Could not list " + dir, e); - } - } - return result; - } - -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/FsMultiMap.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/FsMultiMap.java deleted file mode 100644 index b7842182161a11..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/FsMultiMap.java +++ /dev/null @@ -1,60 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * A file system backed map associating each key with a collection of values - */ -public class FsMultiMap { - - private final Path dir; - - public FsMultiMap(Path dir) { - this.dir = FsMap.safeCreateDirectories(dir); - } - - /** - * @param key - * @return the collection associated with the given {@code key}; never {@code null} - */ - public List get(String key) { - final Path entryDir = dir.resolve(key); - if (Files.exists(entryDir)) { - try (Stream files = Files.list(entryDir)) { - return files - .filter(Files::isRegularFile) - .map(f -> f.getFileName().toString()) - .collect(Collectors.toList()); - - } catch (IOException e) { - throw new RuntimeException("Could not list " + entryDir, e); - } - } - return Collections.emptyList(); - } - - /** - * Add the given {@code value} to the collection associated with the given {@code key}. - * - * @param key - * @param value - */ - public void put(String key, String value) { - final Path entryDir = dir.resolve(key); - FsMap.safeCreateDirectories(entryDir); - final Path itemPath = entryDir.resolve(value); - try { - Files.write(itemPath, value.getBytes(StandardCharsets.UTF_8)); - } catch (IOException e) { - throw new RuntimeException("Could not write to " + itemPath, e); - } - } - -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/JavaDocParser.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/JavaDocParser.java deleted file mode 100644 index 4d8955c3ae503a..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/JavaDocParser.java +++ /dev/null @@ -1,544 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.hyphenate; - -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Consumer; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import org.jsoup.Jsoup; -import org.jsoup.nodes.Node; -import org.jsoup.nodes.TextNode; - -import com.github.javaparser.StaticJavaParser; -import com.github.javaparser.javadoc.Javadoc; -import com.github.javaparser.javadoc.JavadocBlockTag; -import com.github.javaparser.javadoc.JavadocBlockTag.Type; -import com.github.javaparser.javadoc.description.JavadocDescription; -import com.github.javaparser.javadoc.description.JavadocDescriptionElement; -import com.github.javaparser.javadoc.description.JavadocInlineTag; - -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 = "#"; - private static final String STAR = "*"; - private static final String S_NODE = "s"; - private static final String UNDERSCORE = "_"; - private static final String NEW_LINE = "\n"; - private static final String LINK_NODE = "a"; - private static final String BOLD_NODE = "b"; - private static final String STRONG_NODE = "strong"; - private static final String BIG_NODE = "big"; - private static final String CODE_NODE = "code"; - private static final String DEL_NODE = "del"; - private static final String ITALICS_NODE = "i"; - private static final String EMPHASIS_NODE = "em"; - private static final String TEXT_NODE = "#text"; - private static final String UNDERLINE_NODE = "u"; - private static final String NEW_LINE_NODE = "br"; - private static final String PARAGRAPH_NODE = "p"; - private static final String SMALL_NODE = "small"; - private static final String LIST_ITEM_NODE = "li"; - private static final String HREF_ATTRIBUTE = "href"; - private static final String STRIKE_NODE = "strike"; - private static final String SUB_SCRIPT_NODE = "sub"; - private static final String ORDERED_LIST_NODE = "ol"; - private static final String SUPER_SCRIPT_NODE = "sup"; - private static final String UN_ORDERED_LIST_NODE = "ul"; - private static final String PREFORMATED_NODE = "pre"; - private static final String BLOCKQUOTE_NODE = "blockquote"; - - private static final String BIG_ASCIDOC_STYLE = "[.big]"; - private static final String LINK_ATTRIBUTE_FORMAT = "[%s]"; - private static final String SUB_SCRIPT_ASCIDOC_STYLE = "~"; - private static final String SUPER_SCRIPT_ASCIDOC_STYLE = "^"; - private static final String SMALL_ASCIDOC_STYLE = "[.small]"; - private static final String ORDERED_LIST_ITEM_ASCIDOC_STYLE = " . "; - private static final String UNORDERED_LIST_ITEM_ASCIDOC_STYLE = " - "; - private static final String UNDERLINE_ASCIDOC_STYLE = "[.underline]"; - private static final String LINE_THROUGH_ASCIDOC_STYLE = "[.line-through]"; - private static final String HARD_LINE_BREAK_ASCIDOC_STYLE = " +\n"; - private static final String CODE_BLOCK_ASCIDOC_STYLE = "```"; - private static final String BLOCKQUOTE_BLOCK_ASCIDOC_STYLE = "[quote]\n____"; - private static final String BLOCKQUOTE_BLOCK_ASCIDOC_STYLE_END = "____"; - - private final boolean inlineMacroMode; - - public JavaDocParser(boolean inlineMacroMode) { - this.inlineMacroMode = inlineMacroMode; - } - - public JavaDocParser() { - this(false); - } - - public String parseConfigDescription(String javadocComment) { - final AtomicReference ref = new AtomicReference<>(); - parseConfigDescription(javadocComment, ref::set, s -> { - }); - return ref.get(); - } - - public void parseConfigDescription( - String javadocComment, - Consumer javadocTextConsumer, - Consumer sinceConsumer) { - - if (javadocComment == null || javadocComment.trim().isEmpty()) { - javadocTextConsumer.accept(Constants.EMPTY); - return; - } - - // the parser expects all the lines to start with "* " - // we add it as it has been previously removed - javadocComment = START_OF_LINE.matcher(javadocComment).replaceAll("* "); - Javadoc javadoc = StaticJavaParser.parseJavadoc(javadocComment); - - if (isAsciidoc(javadoc)) { - javadocTextConsumer.accept(handleEolInAsciidoc(javadoc)); - } else { - javadocTextConsumer.accept(htmlJavadocToAsciidoc(javadoc.getDescription())); - } - javadoc.getBlockTags().stream() - .filter(t -> t.getType() == Type.SINCE) - .map(JavadocBlockTag::getContent) - .map(JavadocDescription::toText) - .findFirst() - .ifPresent(sinceConsumer::accept); - } - - public SectionHolder parseConfigSection(String javadocComment, int sectionLevel) { - if (javadocComment == null || javadocComment.trim().isEmpty()) { - return new SectionHolder(Constants.EMPTY, Constants.EMPTY); - } - - // the parser expects all the lines to start with "* " - // we add it as it has been previously removed - javadocComment = START_OF_LINE.matcher(javadocComment).replaceAll("* "); - Javadoc javadoc = StaticJavaParser.parseJavadoc(javadocComment); - - if (isAsciidoc(javadoc)) { - final String details = handleEolInAsciidoc(javadoc); - final int endOfTitleIndex = details.indexOf(Constants.DOT); - final String title = details.substring(0, endOfTitleIndex).replaceAll("^([^\\w])+", Constants.EMPTY).trim(); - return new SectionHolder(title, details); - } - - return generateConfigSection(javadoc, sectionLevel); - } - - private SectionHolder generateConfigSection(Javadoc javadoc, int sectionLevel) { - final String generatedAsciiDoc = htmlJavadocToAsciidoc(javadoc.getDescription()); - if (generatedAsciiDoc.isEmpty()) { - return new SectionHolder(Constants.EMPTY, Constants.EMPTY); - } - - final String beginSectionDetails = IntStream - .rangeClosed(0, Math.max(0, sectionLevel)) - .mapToObj(x -> "=").collect(Collectors.joining()) - + " "; - - final int endOfTitleIndex = generatedAsciiDoc.indexOf(Constants.DOT); - if (endOfTitleIndex == -1) { - return new SectionHolder(generatedAsciiDoc.trim(), beginSectionDetails + generatedAsciiDoc); - } else { - final String title = generatedAsciiDoc.substring(0, endOfTitleIndex).trim(); - final String introduction = generatedAsciiDoc.substring(endOfTitleIndex + 1).trim(); - final String details = beginSectionDetails + title + "\n\n" + introduction; - - return new SectionHolder(title, details.trim()); - } - } - - private String handleEolInAsciidoc(Javadoc javadoc) { - // it's Asciidoc, so we just pass through - // it also uses platform specific EOL, so we need to convert them back to \n - String asciidoc = javadoc.getDescription().toText(); - asciidoc = REPLACE_WINDOWS_EOL.matcher(asciidoc).replaceAll("\n"); - asciidoc = REPLACE_MACOS_EOL.matcher(asciidoc).replaceAll("\n"); - return asciidoc; - } - - private boolean isAsciidoc(Javadoc javadoc) { - for (JavadocBlockTag blockTag : javadoc.getBlockTags()) { - if ("asciidoclet".equals(blockTag.getTagName())) { - return true; - } - } - return false; - } - - private String htmlJavadocToAsciidoc(JavadocDescription javadocDescription) { - StringBuilder sb = new StringBuilder(); - - for (JavadocDescriptionElement javadocDescriptionElement : javadocDescription.getElements()) { - if (javadocDescriptionElement instanceof JavadocInlineTag) { - JavadocInlineTag inlineTag = (JavadocInlineTag) javadocDescriptionElement; - String content = inlineTag.getContent().trim(); - switch (inlineTag.getType()) { - case CODE: - case VALUE: - case LITERAL: - case SYSTEM_PROPERTY: - sb.append('`'); - appendEscapedAsciiDoc(sb, content); - sb.append('`'); - break; - case LINK: - case LINKPLAIN: - if (content.startsWith(HASH)) { - content = hyphenate(content.substring(1)); - } - sb.append('`'); - appendEscapedAsciiDoc(sb, content); - sb.append('`'); - break; - default: - sb.append(content); - break; - } - } else { - appendHtml(sb, Jsoup.parseBodyFragment(javadocDescriptionElement.toText())); - } - } - - return trim(sb); - } - - private void appendHtml(StringBuilder sb, Node node) { - for (Node childNode : node.childNodes()) { - switch (childNode.nodeName()) { - case PARAGRAPH_NODE: - newLine(sb); - newLine(sb); - appendHtml(sb, childNode); - break; - case PREFORMATED_NODE: - newLine(sb); - newLine(sb); - sb.append(CODE_BLOCK_ASCIDOC_STYLE); - newLine(sb); - for (Node grandChildNode : childNode.childNodes()) { - unescapeHtmlEntities(sb, grandChildNode.toString()); - } - newLineIfNeeded(sb); - sb.append(CODE_BLOCK_ASCIDOC_STYLE); - newLine(sb); - newLine(sb); - break; - case BLOCKQUOTE_NODE: - newLine(sb); - newLine(sb); - sb.append(BLOCKQUOTE_BLOCK_ASCIDOC_STYLE); - newLine(sb); - appendHtml(sb, childNode); - newLineIfNeeded(sb); - sb.append(BLOCKQUOTE_BLOCK_ASCIDOC_STYLE_END); - newLine(sb); - newLine(sb); - break; - case ORDERED_LIST_NODE: - case UN_ORDERED_LIST_NODE: - newLine(sb); - appendHtml(sb, childNode); - break; - case LIST_ITEM_NODE: - final String marker = childNode.parent().nodeName().equals(ORDERED_LIST_NODE) - ? ORDERED_LIST_ITEM_ASCIDOC_STYLE - : UNORDERED_LIST_ITEM_ASCIDOC_STYLE; - newLine(sb); - sb.append(marker); - appendHtml(sb, childNode); - break; - case LINK_NODE: - final String link = childNode.attr(HREF_ATTRIBUTE); - sb.append("link:"); - sb.append(link); - final StringBuilder caption = new StringBuilder(); - appendHtml(caption, childNode); - sb.append(String.format(LINK_ATTRIBUTE_FORMAT, trim(caption))); - break; - case CODE_NODE: - sb.append(BACKTICK); - appendHtml(sb, childNode); - sb.append(BACKTICK); - break; - case BOLD_NODE: - case STRONG_NODE: - sb.append(STAR); - appendHtml(sb, childNode); - sb.append(STAR); - break; - case EMPHASIS_NODE: - case ITALICS_NODE: - sb.append(UNDERSCORE); - appendHtml(sb, childNode); - sb.append(UNDERSCORE); - break; - case UNDERLINE_NODE: - sb.append(UNDERLINE_ASCIDOC_STYLE); - sb.append(HASH); - appendHtml(sb, childNode); - sb.append(HASH); - break; - case SMALL_NODE: - sb.append(SMALL_ASCIDOC_STYLE); - sb.append(HASH); - appendHtml(sb, childNode); - sb.append(HASH); - break; - case BIG_NODE: - sb.append(BIG_ASCIDOC_STYLE); - sb.append(HASH); - appendHtml(sb, childNode); - sb.append(HASH); - break; - case SUB_SCRIPT_NODE: - sb.append(SUB_SCRIPT_ASCIDOC_STYLE); - appendHtml(sb, childNode); - sb.append(SUB_SCRIPT_ASCIDOC_STYLE); - break; - case SUPER_SCRIPT_NODE: - sb.append(SUPER_SCRIPT_ASCIDOC_STYLE); - appendHtml(sb, childNode); - sb.append(SUPER_SCRIPT_ASCIDOC_STYLE); - break; - case DEL_NODE: - case S_NODE: - case STRIKE_NODE: - sb.append(LINE_THROUGH_ASCIDOC_STYLE); - sb.append(HASH); - appendHtml(sb, childNode); - sb.append(HASH); - break; - case NEW_LINE_NODE: - sb.append(HARD_LINE_BREAK_ASCIDOC_STYLE); - break; - case TEXT_NODE: - 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
- 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); - break; - } - } - } - - /** - * Trim the content of the given {@link StringBuilder} holding also AsciiDoc had line break {@code " +\n"} - * for whitespace in addition to characters <= {@code ' '}. - * - * @param sb the {@link StringBuilder} to trim - * @return the trimmed content of the given {@link StringBuilder} - */ - static String trim(StringBuilder sb) { - int length = sb.length(); - int offset = 0; - while (offset < length) { - final char ch = sb.charAt(offset); - if (ch == ' ' - && offset + 2 < length - && sb.charAt(offset + 1) == '+' - && sb.charAt(offset + 2) == '\n') { - /* Space followed by + and newline is AsciiDoc hard break that we consider whitespace */ - offset += 3; - continue; - } else if (ch > ' ') { - /* Non-whitespace as defined by String.trim() */ - break; - } - offset++; - } - if (offset > 0) { - sb.delete(0, offset); - } - if (sb.length() > 0) { - offset = sb.length() - 1; - while (offset >= 0) { - final char ch = sb.charAt(offset); - if (ch == '\n' - && offset - 2 >= 0 - && sb.charAt(offset - 1) == '+' - && sb.charAt(offset - 2) == ' ') { - /* Space followed by + is AsciiDoc hard break that we consider whitespace */ - offset -= 3; - continue; - } else if (ch > ' ') { - /* Non-whitespace as defined by String.trim() */ - break; - } - offset--; - } - if (offset < sb.length() - 1) { - sb.setLength(offset + 1); - } - } - return sb.toString(); - } - - private static StringBuilder newLineIfNeeded(StringBuilder sb) { - trimText(sb, " \t\r\n"); - return sb.append(NEW_LINE); - } - - private static StringBuilder newLine(StringBuilder sb) { - /* Trim trailing spaces and tabs at the end of line */ - trimText(sb, " \t"); - return sb.append(NEW_LINE); - } - - private static StringBuilder trimText(StringBuilder sb, String charsToTrim) { - while (sb.length() > 0 && charsToTrim.indexOf(sb.charAt(sb.length() - 1)) >= 0) { - sb.setLength(sb.length() - 1); - } - return sb; - } - - private StringBuilder unescapeHtmlEntities(StringBuilder sb, String text) { - int i = 0; - /* trim leading whitespace */ - LOOP: while (i < text.length()) { - switch (text.charAt(i++)) { - case ' ': - case '\t': - case '\r': - case '\n': - break; - default: - i--; - break LOOP; - } - } - for (; i < text.length(); i++) { - final char ch = text.charAt(i); - switch (ch) { - case '&': - int start = ++i; - while (i < text.length() && text.charAt(i) != ';') { - i++; - } - if (i > start) { - final String abbrev = text.substring(start, i); - switch (abbrev) { - case "lt": - sb.append('<'); - break; - case "gt": - sb.append('>'); - break; - case "nbsp": - sb.append("{nbsp}"); - break; - case "amp": - sb.append('&'); - break; - default: - try { - int code = Integer.parseInt(abbrev); - sb.append((char) code); - } catch (NumberFormatException e) { - throw new RuntimeException( - "Could not parse HTML entity &" + abbrev + "; in\n\n" + text + "\n\n"); - } - break; - } - } - break; - case '\r': - if (i + 1 < text.length() && text.charAt(i + 1) == '\n') { - /* Ignore \r followed by \n */ - } else { - /* A Mac single \r: replace by \n */ - sb.append('\n'); - } - break; - default: - sb.append(ch); - - } - } - return sb; - } - - private StringBuilder appendEscapedAsciiDoc(StringBuilder sb, String text) { - boolean escaping = false; - for (int i = 0; i < text.length(); i++) { - final char ch = text.charAt(i); - switch (ch) { - case ']': - // don't escape closing square bracket in the attribute list of an inline element with passThrough - // https://docs.asciidoctor.org/asciidoc/latest/attributes/positional-and-named-attributes/#substitutions - if (inlineMacroMode) { - if (escaping) { - sb.append("++"); - escaping = false; - } - sb.append("]"); - break; - } - case '#': - case '*': - case '\\': - case '{': - case '}': - case '[': - case '|': - if (!escaping) { - sb.append("++"); - escaping = true; - } - sb.append(ch); - break; - case '+': - if (escaping) { - sb.append("++"); - escaping = false; - } - sb.append("{plus}"); - break; - default: - if (escaping) { - sb.append("++"); - escaping = false; - } - sb.append(ch); - } - } - if (escaping) { - sb.append("++"); - } - return sb; - } - - static class SectionHolder { - final String title; - final String details; - - public SectionHolder(String title, String details) { - this.title = title; - this.details = details; - } - } -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/LegacyConfigDocExtensionProcessor.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/LegacyConfigDocExtensionProcessor.java deleted file mode 100644 index 6c5e77aa1be45e..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/LegacyConfigDocExtensionProcessor.java +++ /dev/null @@ -1,210 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import static io.quarkus.annotation.processor.generate_doc.Constants.ANNOTATION_CONFIG_GROUP; -import static io.quarkus.annotation.processor.generate_doc.Constants.ANNOTATION_CONFIG_MAPPING; -import static javax.lang.model.util.ElementFilter.typesIn; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Properties; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import javax.annotation.processing.RoundEnvironment; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.ElementFilter; -import javax.tools.Diagnostic; - -import io.quarkus.annotation.processor.ExtensionProcessor; -import io.quarkus.annotation.processor.Outputs; -import io.quarkus.annotation.processor.documentation.config.util.Types; -import io.quarkus.annotation.processor.util.Config; -import io.quarkus.annotation.processor.util.Utils; - -public class LegacyConfigDocExtensionProcessor implements ExtensionProcessor { - - private Utils utils; - private final ConfigDocItemScanner configDocItemScanner; - private final ConfigDocWriter configDocWriter; - - private final Map annotationUsageTracker = new ConcurrentHashMap<>(); - private boolean configMappingUsed; - - public LegacyConfigDocExtensionProcessor() { - this.configDocItemScanner = new ConfigDocItemScanner(); - this.configDocWriter = new ConfigDocWriter(); - } - - @Override - public void init(Config config, Utils utils) { - this.utils = utils; - } - - @Override - public void process(Set annotations, RoundEnvironment roundEnv) { - configMappingUsed = annotations.stream() - .anyMatch(a -> a.getQualifiedName().toString().equals(Types.ANNOTATION_CONFIG_MAPPING)); - - for (TypeElement annotation : annotations) { - switch (annotation.getQualifiedName().toString()) { - case Types.ANNOTATION_CONFIG_ROOT: - trackAnnotationUsed(Types.ANNOTATION_CONFIG_ROOT); - processConfigRoot(roundEnv, annotation); - break; - case Types.ANNOTATION_CONFIG_GROUP: - trackAnnotationUsed(Types.ANNOTATION_CONFIG_GROUP); - processConfigGroup(roundEnv, annotation); - break; - case Types.ANNOTATION_CONFIG_MAPPING: - configMappingUsed = true; - break; - } - } - } - - private void processConfigRoot(RoundEnvironment roundEnv, TypeElement annotation) { - for (TypeElement clazz : typesIn(roundEnv.getElementsAnnotatedWith(annotation))) { - final PackageElement pkg = utils.element().getPackageOf(clazz); - if (pkg == null) { - utils.processingEnv().getMessager().printMessage(Diagnostic.Kind.ERROR, - "Element " + clazz + " has no enclosing package"); - continue; - } - - configDocItemScanner.addConfigRoot(pkg, clazz); - } - } - - private void processConfigGroup(RoundEnvironment roundEnv, TypeElement annotation) { - final Set groupClassNames = new HashSet<>(); - for (TypeElement i : ElementFilter.typesIn(roundEnv.getElementsAnnotatedWith(annotation))) { - if (groupClassNames.add(i.getQualifiedName().toString())) { - configDocItemScanner.addConfigGroups(i); - } - } - } - - private void recordMappingJavadoc(TypeElement clazz) { - String className = clazz.getQualifiedName().toString(); - if (!utils.element().isAnnotationPresent(clazz, ANNOTATION_CONFIG_MAPPING)) { - configDocItemScanner.addConfigGroups(clazz); - } - Properties javadocProps = new Properties(); - - for (Element e : clazz.getEnclosedElements()) { - switch (e.getKind()) { - case INTERFACE: { - recordMappingJavadoc(((TypeElement) e)); - break; - } - - case METHOD: { - if (!isConfigMappingMethodIgnored(e)) { - processMethodConfigMapping((ExecutableElement) e, javadocProps, className); - } - break; - } - default: - } - } - } - - private void processMethodConfigMapping(ExecutableElement method, Properties javadocProps, String className) { - if (method.getModifiers().contains(Modifier.ABSTRACT)) { - TypeMirror returnType = method.getReturnType(); - if (TypeKind.DECLARED.equals(returnType.getKind())) { - DeclaredType declaredType = (DeclaredType) returnType; - if (!utils.element().isAnnotationPresent(declaredType.asElement(), ANNOTATION_CONFIG_GROUP)) { - TypeElement type = unwrapConfigGroup(returnType); - if (type != null && ElementKind.INTERFACE.equals(type.getKind())) { - recordMappingJavadoc(type); - configDocItemScanner.addConfigGroups(type); - } - } - } - } - } - - private TypeElement unwrapConfigGroup(TypeMirror typeMirror) { - if (typeMirror == null) { - return null; - } - - DeclaredType declaredType = (DeclaredType) typeMirror; - String name = declaredType.asElement() - .toString(); - List typeArguments = declaredType.getTypeArguments(); - if (typeArguments.isEmpty()) { - if (!name.startsWith("java.")) { - return (TypeElement) declaredType.asElement(); - } - } else if (typeArguments.size() == 1) { - if (name.equals(Optional.class.getName()) || - name.equals(List.class.getName()) || - name.equals(Set.class.getName())) { - return unwrapConfigGroup(typeArguments.get(0)); - } - } else if (typeArguments.size() == 2) { - if (name.equals(Map.class.getName())) { - return unwrapConfigGroup(typeArguments.get(1)); - } - } - return null; - } - - private static boolean isConfigMappingMethodIgnored(Element element) { - for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) { - String annotationName = ((TypeElement) annotationMirror.getAnnotationType().asElement()) - .getQualifiedName().toString(); - if (Constants.ANNOTATION_CONFIG_DOC_IGNORE.equals(annotationName)) { - return true; - } - } - return false; - } - - private void trackAnnotationUsed(String annotation) { - annotationUsageTracker.put(annotation, true); - } - - @Override - public void finalizeProcessing() { - try { - // not ideal but let's load the javadoc properties (we can't use the filer API here as we can't open the same file twice)... - Properties javadocProperties = new Properties(); - Path javadocPropertiesPath = utils.filer().getTargetPath().resolve("classes") - .resolve(Outputs.META_INF_QUARKUS_JAVADOC); - if (Files.isReadable(javadocPropertiesPath)) { - try (InputStream is = Files.newInputStream(javadocPropertiesPath)) { - javadocProperties.load(is); - } - } - - final Set outputs = configDocItemScanner - .scanExtensionsConfigurationItems(javadocProperties, configMappingUsed); - for (ConfigDocGeneratedOutput output : outputs) { - DocGeneratorUtil.sort(output.getConfigDocItems()); // sort before writing - configDocWriter.writeAllExtensionConfigDocumentation(output); - } - } catch (IOException e) { - utils.processingEnv().getMessager().printMessage(Diagnostic.Kind.ERROR, "Failed to generate extension doc: " + e); - return; - } - } - -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/MavenConfigDocBuilder.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/MavenConfigDocBuilder.java deleted file mode 100644 index 0e538bb2169aaa..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/MavenConfigDocBuilder.java +++ /dev/null @@ -1,93 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import static io.quarkus.annotation.processor.generate_doc.Constants.NEW_LINE; -import static io.quarkus.annotation.processor.generate_doc.Constants.SECTION_TITLE_L1; - -import java.util.ArrayList; -import java.util.List; - -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 configDocItems = new ArrayList<>(); - - /** - * Section name that is displayed in a table header - */ - abstract protected String getSectionName(); - - public List 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.setAdditionalKeys(List.of(name)); - configDocKey.setConfigPhase(ConfigPhase.RUN_TIME); - configDocKey.setDefaultValue(defaultValue == null ? Constants.EMPTY : defaultValue); - javaDocParser.parseConfigDescription(description, configDocKey::setConfigDoc, configDocKey::setSince); - configDocKey.setEnvironmentVariable(DocGeneratorUtil.toEnvVarName(name)); - configDocKey.setOptional(!required); - final ConfigDocItem configDocItem = new ConfigDocItem(); - configDocItem.setConfigDocKey(configDocKey); - configDocItems.add(configDocItem); - } - - @Override - protected String getSectionName() { - return "Parameter"; - } - } - -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ScannedConfigDocsItemHolder.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ScannedConfigDocsItemHolder.java deleted file mode 100644 index cba9d2bed6cabf..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/ScannedConfigDocsItemHolder.java +++ /dev/null @@ -1,59 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -final class ScannedConfigDocsItemHolder { - private final Map> configGroupConfigItems; - private final Map> configRootConfigItems; - private final Map configRootClassToConfigRootInfo = new HashMap<>(); - - public ScannedConfigDocsItemHolder() { - this(new HashMap<>(), new HashMap<>()); - } - - public ScannedConfigDocsItemHolder(Map> configRootConfigItems, - Map> configGroupConfigItems) { - this.configRootConfigItems = configRootConfigItems; - this.configGroupConfigItems = configGroupConfigItems; - } - - public Map> getConfigGroupConfigItems() { - return configGroupConfigItems; - } - - public Map> getConfigRootConfigItems() { - return configRootConfigItems; - } - - public void addConfigGroupItems(String configGroupName, List configDocItems) { - configGroupConfigItems.put(configGroupName, configDocItems); - } - - public void addConfigRootItems(ConfigRootInfo configRoot, List configDocItems) { - configRootConfigItems.put(configRoot, configDocItems); - configRootClassToConfigRootInfo.put(configRoot.getClazz().getQualifiedName().toString(), configRoot); - } - - public List getConfigItemsByRootClassName(String configRootClassName) { - ConfigRootInfo configRootInfo = configRootClassToConfigRootInfo.get(configRootClassName); - if (configRootInfo == null) { - return null; - } - - return configRootConfigItems.get(configRootInfo); - } - - public boolean isEmpty() { - return configRootConfigItems.isEmpty(); - } - - @Override - public String toString() { - return "ScannedConfigDocsItemHolder{" + - ", configRootConfigItems=" + configRootConfigItems + - ", configGroupConfigItems=" + configGroupConfigItems + - '}'; - } -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/SummaryTableDocFormatter.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/SummaryTableDocFormatter.java deleted file mode 100644 index 1fe3040fe6dca3..00000000000000 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/SummaryTableDocFormatter.java +++ /dev/null @@ -1,154 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import static io.quarkus.annotation.processor.generate_doc.Constants.CONFIG_PHASE_LEGEND; -import static io.quarkus.annotation.processor.generate_doc.Constants.NEW_LINE; -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.toEnvVarName; - -import java.io.IOException; -import java.io.Writer; -import java.util.List; - -final class SummaryTableDocFormatter implements DocFormatter { - private static final String TWO_NEW_LINES = "\n\n"; - private static final String TABLE_CLOSING_TAG = "\n|==="; - public static final String SEARCHABLE_TABLE_CLASS = ".searchable"; // a css class indicating if a table is searchable - public static final String CONFIGURATION_TABLE_CLASS = ".configuration-reference"; - private static final String TABLE_ROW_FORMAT = "\n\na|%s [[%s]]`link:#%s[%s]`\n\n[.description]\n--\n%s\n--%s|%s %s\n|%s\n"; - private static final String SECTION_TITLE = "[[%s]]link:#%s[%s]"; - private static final String TABLE_HEADER_FORMAT = "[%s, cols=\"80,.^10,.^10\"]\n|==="; - private static final String TABLE_SECTION_ROW_FORMAT = "\n\nh|%s\n%s\nh|Type\nh|Default"; - private final boolean showEnvVars; - - private String anchorPrefix = ""; - - public SummaryTableDocFormatter(boolean showEnvVars) { - this.showEnvVars = showEnvVars; - } - - public SummaryTableDocFormatter() { - this(true); - } - - /** - * Generate configuration keys in table format with search engine activated or not. - * Useful when we want to optionally activate or deactivate search engine - */ - @Override - public void format(Writer writer, String initialAnchorPrefix, boolean activateSearch, - List configDocItems, boolean includeConfigPhaseLegend) - throws IOException { - if (includeConfigPhaseLegend) { - writer.append("[.configuration-legend]").append(CONFIG_PHASE_LEGEND).append(NEW_LINE); - } - String searchableClass = activateSearch ? SEARCHABLE_TABLE_CLASS : Constants.EMPTY; - String tableClasses = CONFIGURATION_TABLE_CLASS + searchableClass; - writer.append(String.format(TABLE_HEADER_FORMAT, tableClasses)); - anchorPrefix = initialAnchorPrefix; - - // make sure that section-less configs get a legend - if (configDocItems.isEmpty() || configDocItems.get(0).isConfigKey()) { - String anchor = anchorPrefix + getAnchor("configuration"); - writer.append(String.format(TABLE_SECTION_ROW_FORMAT, - String.format(SECTION_TITLE, anchor, anchor, "Configuration property"), - Constants.EMPTY)); - } - - for (ConfigDocItem configDocItem : configDocItems) { - if (configDocItem.isConfigSection() && configDocItem.getConfigDocSection().isShowSection() - && configDocItem.getConfigDocSection().getAnchorPrefix() != null) { - anchorPrefix = configDocItem.getConfigDocSection().getAnchorPrefix() + "_"; - } - configDocItem.accept(writer, this); - } - - writer.append(TABLE_CLOSING_TAG); // close table - } - - @Override - public void format(Writer writer, ConfigDocKey configDocKey) throws IOException { - String typeContent = ""; - if (configDocKey.hasAcceptedValues()) { - if (configDocKey.isEnum()) { - typeContent = DocGeneratorUtil.joinEnumValues(configDocKey.getAcceptedValues()); - } else { - typeContent = DocGeneratorUtil.joinAcceptedValues(configDocKey.getAcceptedValues()); - } - } else if (configDocKey.hasType()) { - typeContent = configDocKey.computeTypeSimpleName(); - final String javaDocLink = configDocKey.getJavaDocSiteLink(); - if (!javaDocLink.isEmpty()) { - typeContent = String.format("link:%s[%s]\n", javaDocLink, typeContent); - } - } - if (configDocKey.isList()) { - typeContent = "list of " + typeContent; - } - - String doc = configDocKey.getConfigDoc(); - - if (showEnvVars) { - // Convert a property name to an environment variable name and show it in the config description - final String envVarExample = String.format("ifdef::add-copy-button-to-env-var[]\n" + - "Environment variable: env_var_with_copy_button:+++%1$s+++[]\n" + - "endif::add-copy-button-to-env-var[]\n" + - "ifndef::add-copy-button-to-env-var[]\n" + - "Environment variable: `+++%1$s+++`\n" + - "endif::add-copy-button-to-env-var[]", toEnvVarName(configDocKey.getKey())); - if (configDocKey.getConfigDoc().isEmpty()) { - doc = envVarExample; - } else { - // Add 2 new lines in order to show the environment variable on next line - doc += TWO_NEW_LINES + envVarExample; - } - } - - final String typeDetail = DocGeneratorUtil.getTypeFormatInformationNote(configDocKey); - final String defaultValue = configDocKey.getDefaultValue(); - // this is not strictly true, because we can have a required value with a default value, but - // for documentation it will do - String required = configDocKey.isOptional() || !defaultValue.isEmpty() ? "" - : "required icon:exclamation-circle[title=Configuration property is required]"; - String key = configDocKey.getKey(); - String configKeyAnchor = getAnchor(key); - String anchor = anchorPrefix + configKeyAnchor; - - StringBuilder keys = new StringBuilder(); - keys.append( - String.format("%s [[%s]]`link:#%s[%s]`\n\n", configDocKey.getConfigPhase().getIllustration(), anchor, anchor, - key)); - for (String additionalKey : configDocKey.getAdditionalKeys()) { - if (!additionalKey.equals(key)) { - keys.append(String.format("`link:#%s[%s]`\n\n", anchor, additionalKey)); - } - } - - writer.append(String.format("\n\na|%s\n[.description]\n--\n%s\n--%s|%s %s\n|%s\n", - keys, - // make sure nobody inserts a table cell separator here - doc.replace("|", "\\|"), - // if ConfigDocKey is enum, cell style operator must support block elements - configDocKey.isEnum() ? " a" : Constants.EMPTY, - typeContent, typeDetail, - defaultValue.isEmpty() ? required - : String.format("`%s`", defaultValue.replace("|", "\\|") - .replace("`", "\\`")))); - } - - @Override - public void format(Writer writer, ConfigDocSection configDocSection) throws IOException { - if (configDocSection.isShowSection()) { - String anchor = anchorPrefix - + getAnchor(configDocSection.getName() + Constants.DASH + configDocSection.getSectionDetailsTitle()); - String sectionTitle = String.format(SECTION_TITLE, anchor, anchor, configDocSection.getSectionDetailsTitle()); - final String sectionRow = String.format(TABLE_SECTION_ROW_FORMAT, sectionTitle, - configDocSection.isOptional() ? "This configuration section is optional" : Constants.EMPTY); - - writer.append(sectionRow); - } - - for (ConfigDocItem configDocItem : configDocSection.getConfigDocItems()) { - configDocItem.accept(writer, this); - } - } - -} diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/util/AccessorGenerator.java b/core/processor/src/main/java/io/quarkus/annotation/processor/util/AccessorGenerator.java index 130d969d2762c7..2eb1efd69e24e4 100644 --- a/core/processor/src/main/java/io/quarkus/annotation/processor/util/AccessorGenerator.java +++ b/core/processor/src/main/java/io/quarkus/annotation/processor/util/AccessorGenerator.java @@ -34,11 +34,10 @@ import org.jboss.jdeparser.JType; import org.jboss.jdeparser.JTypes; -import io.quarkus.annotation.processor.generate_doc.Constants; - public final class AccessorGenerator { private static final String QUARKUS_GENERATED = "io.quarkus.Generated"; + private static final String INSTANCE_SYM = "__instance"; private final ProcessingEnvironment processingEnv; private final ElementUtil elementUtil; @@ -75,7 +74,7 @@ public void generateAccessor(final TypeElement clazz) { classDef.constructor(JMod.PRIVATE); // no construction classDef.annotate(QUARKUS_GENERATED) .value("Quarkus annotation processor"); - final JAssignableExpr instanceName = JExprs.name(Constants.INSTANCE_SYM); + final JAssignableExpr instanceName = JExprs.name(INSTANCE_SYM); boolean isEnclosingClassPublic = clazz.getModifiers() .contains(Modifier.PUBLIC); // iterate fields @@ -114,14 +113,14 @@ public void generateAccessor(final TypeElement clazz) { final JMethodDef getter = classDef.method(JMod.PUBLIC | JMod.STATIC, publicType, "get_" + fieldName); getter.annotate(SuppressWarnings.class) .value("unchecked"); - getter.param(JType.OBJECT, Constants.INSTANCE_SYM); + getter.param(JType.OBJECT, INSTANCE_SYM); getter.body() ._return(instanceName.cast(clazzType) .field(fieldName)); final JMethodDef setter = classDef.method(JMod.PUBLIC | JMod.STATIC, JType.VOID, "set_" + fieldName); setter.annotate(SuppressWarnings.class) .value("unchecked"); - setter.param(JType.OBJECT, Constants.INSTANCE_SYM); + setter.param(JType.OBJECT, INSTANCE_SYM); setter.param(publicType, fieldName); final JAssignableExpr fieldExpr = JExprs.name(fieldName); setter.body() diff --git a/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/JavaDocConfigDescriptionParserTest.java b/core/processor/src/test/java/io/quarkus/annotation/processor/documentation/config/formatter/JavadocToAsciidocTransformerConfigItemTest.java similarity index 51% rename from core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/JavaDocConfigDescriptionParserTest.java rename to core/processor/src/test/java/io/quarkus/annotation/processor/documentation/config/formatter/JavadocToAsciidocTransformerConfigItemTest.java index 60d4200fe52a36..3bab12d00c2155 100644 --- a/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/JavaDocConfigDescriptionParserTest.java +++ b/core/processor/src/test/java/io/quarkus/annotation/processor/documentation/config/formatter/JavadocToAsciidocTransformerConfigItemTest.java @@ -1,66 +1,61 @@ -package io.quarkus.annotation.processor.generate_doc; +package io.quarkus.annotation.processor.documentation.config.formatter; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import java.util.Collections; -import java.util.concurrent.atomic.AtomicReference; import org.asciidoctor.Asciidoctor.Factory; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -public class JavaDocConfigDescriptionParserTest { +import io.quarkus.annotation.processor.documentation.config.discovery.ParsedJavadoc; - private JavaDocParser parser; - - @BeforeEach - public void setup() { - parser = new JavaDocParser(); - } +public class JavadocToAsciidocTransformerConfigItemTest { @Test public void parseNullJavaDoc() { - String parsed = parser.parseConfigDescription(null); - assertEquals("", parsed); + ParsedJavadoc parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(null); + assertNull(parsed.description()); } @Test public void removeParagraphIndentation() { - String parsed = parser.parseConfigDescription("First paragraph

Second Paragraph"); - assertEquals("First paragraph +\n +\nSecond Paragraph", parsed); + ParsedJavadoc parsed = JavadocToAsciidocTransformer.INSTANCE + .parseConfigItemJavadoc("First paragraph

Second Paragraph"); + assertEquals("First paragraph +\n +\nSecond Paragraph", parsed.description()); } @Test public void parseUntrimmedJavaDoc() { - String parsed = parser.parseConfigDescription(" "); - assertEquals("", parsed); - parsed = parser.parseConfigDescription("

"); - assertEquals("", parsed); + ParsedJavadoc parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(" "); + assertNull(parsed.description()); + parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc("

"); + assertNull(parsed.description()); } @Test public void parseSimpleJavaDoc() { String javaDoc = "hello world"; - String parsed = parser.parseConfigDescription(javaDoc); + ParsedJavadoc parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); - assertEquals(javaDoc, parsed); + assertEquals(javaDoc, parsed.description()); } @Test public void parseJavaDocWithParagraph() { String javaDoc = "hello

world

"; String expectedOutput = "hello\n\nworld"; - String parsed = parser.parseConfigDescription(javaDoc); + ParsedJavadoc parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); - assertEquals(expectedOutput, parsed); + assertEquals(expectedOutput, parsed.description()); javaDoc = "hello world

bonjour

le monde

"; expectedOutput = "hello world\n\nbonjour\n\nle monde"; - parsed = parser.parseConfigDescription(javaDoc); + parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); - assertEquals(expectedOutput, parsed); + assertEquals(expectedOutput, parsed.description()); } @Test @@ -68,55 +63,55 @@ public void parseJavaDocWithStyles() { // Bold String javaDoc = "hello world"; String expectedOutput = "hello *world*"; - String parsed = parser.parseConfigDescription(javaDoc); - assertEquals(expectedOutput, parsed); + ParsedJavadoc parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); + assertEquals(expectedOutput, parsed.description()); javaDoc = "hello world"; expectedOutput = "hello *world*"; - parsed = parser.parseConfigDescription(javaDoc); - assertEquals(expectedOutput, parsed); + parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); + assertEquals(expectedOutput, parsed.description()); // Emphasized javaDoc = "hello world"; expectedOutput = "_hello world_"; - parsed = parser.parseConfigDescription(javaDoc); - assertEquals(expectedOutput, parsed); + parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); + assertEquals(expectedOutput, parsed.description()); // Italics javaDoc = "hello world"; expectedOutput = "_hello world_"; - parsed = parser.parseConfigDescription(javaDoc); - assertEquals(expectedOutput, parsed); + parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); + assertEquals(expectedOutput, parsed.description()); // Underline javaDoc = "hello world"; expectedOutput = "[.underline]#hello world#"; - parsed = parser.parseConfigDescription(javaDoc); - assertEquals(expectedOutput, parsed); + parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); + assertEquals(expectedOutput, parsed.description()); // small javaDoc = "quarkus subatomic"; expectedOutput = "[.small]#quarkus subatomic#"; - parsed = parser.parseConfigDescription(javaDoc); - assertEquals(expectedOutput, parsed); + parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); + assertEquals(expectedOutput, parsed.description()); // big javaDoc = "hello world"; expectedOutput = "[.big]#hello world#"; - parsed = parser.parseConfigDescription(javaDoc); - assertEquals(expectedOutput, parsed); + parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); + assertEquals(expectedOutput, parsed.description()); // line through javaDoc = "hello monolith world"; expectedOutput = "[.line-through]#hello #[.line-through]#monolith #[.line-through]#world#"; - parsed = parser.parseConfigDescription(javaDoc); - assertEquals(expectedOutput, parsed); + parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); + assertEquals(expectedOutput, parsed.description()); // superscript and subscript javaDoc = "cloud in-premise"; expectedOutput = "^cloud ^~in-premise~"; - parsed = parser.parseConfigDescription(javaDoc); - assertEquals(expectedOutput, parsed); + parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); + assertEquals(expectedOutput, parsed.description()); } @Test @@ -128,9 +123,9 @@ public void parseJavaDocWithLiTagsInsideUlTag() { "" + ""; String expectedOutput = "List:\n\n - 1\n - 2"; - String parsed = parser.parseConfigDescription(javaDoc); + ParsedJavadoc parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); - assertEquals(expectedOutput, parsed); + assertEquals(expectedOutput, parsed.description()); } @Test @@ -142,72 +137,72 @@ public void parseJavaDocWithLiTagsInsideOlTag() { "" + ""; String expectedOutput = "List:\n\n . 1\n . 2"; - String parsed = parser.parseConfigDescription(javaDoc); + ParsedJavadoc parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); - assertEquals(expectedOutput, parsed); + assertEquals(expectedOutput, parsed.description()); } @Test public void parseJavaDocWithLinkInlineSnippet() { String javaDoc = "{@link firstlink} {@link #secondlink} \n {@linkplain #third.link}"; String expectedOutput = "`firstlink` `secondlink` `third.link`"; - String parsed = parser.parseConfigDescription(javaDoc); + ParsedJavadoc parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); - assertEquals(expectedOutput, parsed); + assertEquals(expectedOutput, parsed.description()); } @Test public void parseJavaDocWithLinkTag() { String javaDoc = "this is a hello link"; String expectedOutput = "this is a link:http://link.com[hello] link"; - String parsed = parser.parseConfigDescription(javaDoc); + ParsedJavadoc parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); - assertEquals(expectedOutput, parsed); + assertEquals(expectedOutput, parsed.description()); } @Test public void parseJavaDocWithCodeInlineSnippet() { String javaDoc = "{@code true} {@code false}"; String expectedOutput = "`true` `false`"; - String parsed = parser.parseConfigDescription(javaDoc); + ParsedJavadoc parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); - assertEquals(expectedOutput, parsed); + assertEquals(expectedOutput, parsed.description()); } @Test public void parseJavaDocWithLiteralInlineSnippet() { String javaDoc = "{@literal java.util.Boolean}"; String expectedOutput = "`java.util.Boolean`"; - String parsed = parser.parseConfigDescription(javaDoc); + ParsedJavadoc parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); - assertEquals(expectedOutput, parsed); + assertEquals(expectedOutput, parsed.description()); } @Test public void parseJavaDocWithValueInlineSnippet() { String javaDoc = "{@value 10s}"; String expectedOutput = "`10s`"; - String parsed = parser.parseConfigDescription(javaDoc); + ParsedJavadoc parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); - assertEquals(expectedOutput, parsed); + assertEquals(expectedOutput, parsed.description()); } @Test public void parseJavaDocWithUnknownInlineSnippet() { String javaDoc = "{@see java.util.Boolean}"; String expectedOutput = "java.util.Boolean"; - String parsed = parser.parseConfigDescription(javaDoc); + ParsedJavadoc parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); - assertEquals(expectedOutput, parsed); + assertEquals(expectedOutput, parsed.description()); } @Test public void parseJavaDocWithUnknownNode() { String javaDoc = "hello"; String expectedOutput = "hello"; - String parsed = parser.parseConfigDescription(javaDoc); + ParsedJavadoc parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc); - assertEquals(expectedOutput, parsed); + assertEquals(expectedOutput, parsed.description()); } @Test @@ -220,46 +215,49 @@ public void parseJavaDocWithBlockquoteBlock() { + "____\n" + "\n" + "That was interesting, wasn't it?", - parser.parseConfigDescription("See Section 4.5.5 of the JSR 380 specification, specifically\n" - + "\n" - + "
\n" - + "In sub types (be it sub classes/interfaces or interface implementations), no parameter constraints may\n" - + "be declared on overridden or implemented methods, nor may parameters be marked for cascaded validation.\n" - + "This would pose a strengthening of preconditions to be fulfilled by the caller.\n" - + "
\nThat was interesting, wasn't it?")); + JavadocToAsciidocTransformer.INSTANCE + .parseConfigItemJavadoc("See Section 4.5.5 of the JSR 380 specification, specifically\n" + + "\n" + + "
\n" + + "In sub types (be it sub classes/interfaces or interface implementations), no parameter constraints may\n" + + "be declared on overridden or implemented methods, nor may parameters be marked for cascaded validation.\n" + + "This would pose a strengthening of preconditions to be fulfilled by the caller.\n" + + "
\nThat was interesting, wasn't it?") + .description()); assertEquals( "Some HTML entities & special characters:\n\n```\n|[/variant]|/[/variant]\n```\n\nbaz", - parser.parseConfigDescription( - "Some HTML entities & special characters:\n\n
<os>|<arch>[/variant]|<os>/<arch>[/variant]\n
\n\nbaz")); + JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc( + "Some HTML entities & special characters:\n\n
<os>|<arch>[/variant]|<os>/<arch>[/variant]\n
\n\nbaz") + .description()); // TODO // assertEquals("Example:\n\n```\nfoo\nbar\n```", - // parser.parseConfigDescription("Example:\n\n
{@code\nfoo\nbar\n}
")); + // JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc("Example:\n\n
{@code\nfoo\nbar\n}
")); } @Test public void parseJavaDocWithCodeBlock() { assertEquals("Example:\n\n```\nfoo\nbar\n```\n\nbaz", - parser.parseConfigDescription("Example:\n\n
\nfoo\nbar\n
\n\nbaz")); + JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc("Example:\n\n
\nfoo\nbar\n
\n\nbaz") + .description()); assertEquals( "Some HTML entities & special characters:\n\n```\n|[/variant]|/[/variant]\n```\n\nbaz", - parser.parseConfigDescription( - "Some HTML entities & special characters:\n\n
<os>|<arch>[/variant]|<os>/<arch>[/variant]\n
\n\nbaz")); + JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc( + "Some HTML entities & special characters:\n\n
<os>|<arch>[/variant]|<os>/<arch>[/variant]\n
\n\nbaz") + .description()); // TODO // assertEquals("Example:\n\n```\nfoo\nbar\n```", - // parser.parseConfigDescription("Example:\n\n
{@code\nfoo\nbar\n}
")); + // JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc("Example:\n\n
{@code\nfoo\nbar\n}
")); } @Test public void since() { - AtomicReference javadoc = new AtomicReference<>(); - AtomicReference since = new AtomicReference<>(); - parser.parseConfigDescription("Javadoc text\n\n@since 1.2.3", javadoc::set, since::set); - assertEquals("Javadoc text", javadoc.get()); - assertEquals("1.2.3", since.get()); + ParsedJavadoc parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc("Javadoc text\n\n@since 1.2.3"); + assertEquals("Javadoc text", parsed.description()); + assertEquals("1.2.3", parsed.since()); } @Test @@ -278,7 +276,8 @@ public void asciidoc() { "And some code\n" + "----"; - assertEquals(asciidoc, parser.parseConfigDescription(asciidoc + "\n" + "@asciidoclet")); + assertEquals(asciidoc, + JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(asciidoc + "\n" + "@asciidoclet").description()); } @Test @@ -290,7 +289,8 @@ public void asciidocLists() { " * 1.2\n" + "* 2"; - assertEquals(asciidoc, parser.parseConfigDescription(asciidoc + "\n" + "@asciidoclet")); + assertEquals(asciidoc, + JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(asciidoc + "\n" + "@asciidoclet").description()); } @ParameterizedTest @@ -299,7 +299,7 @@ public void escape(String ch) { final String javaDoc = "Inline " + ch + " " + ch + ch + ", HTML tag glob " + ch + " " + ch + ch + ", {@code JavaDoc tag " + ch + " " + ch + ch + "}"; - final String asciiDoc = parser.parseConfigDescription(javaDoc); + final String asciiDoc = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc).description(); final String actual = Factory.create().convert(asciiDoc, Collections.emptyMap()); final String expected = "
\n

Inline " + ch + " " + ch + ch + ", HTML tag glob " + ch + " " + ch + ch + ", JavaDoc tag " + ch + " " + ch + ch + "

\n
"; @@ -312,7 +312,8 @@ public void escapeInsideInlineElement(String ch) { final String javaDoc = "Inline " + ch + " " + ch + ch + ", HTML tag glob " + ch + " " + ch + ch + ", {@code JavaDoc tag " + ch + " " + ch + ch + "}"; - final String asciiDoc = new JavaDocParser(true).parseConfigDescription(javaDoc); + final String asciiDoc = JavadocToAsciidocTransformer.INLINE_MACRO_INSTANCE.parseConfigItemJavadoc(javaDoc) + .description(); final String actual = Factory.create().convert(asciiDoc, Collections.emptyMap()); if (ch.equals("]")) { @@ -328,7 +329,7 @@ public void escapePlus() { final String javaDoc = "Inline + ++, HTML tag glob + ++, {@code JavaDoc tag + ++}"; final String expected = "
\n

Inline + ++, HTML tag glob + ++, JavaDoc tag + ++

\n
"; - final String asciiDoc = parser.parseConfigDescription(javaDoc); + final String asciiDoc = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc).description(); final String actual = Factory.create().convert(asciiDoc, Collections.emptyMap()); assertEquals(expected, actual); } @@ -341,30 +342,30 @@ public void escapeBrackets(String ch) { final String expected = "
\n

Inline " + ch + " " + ch + ch + ", HTML tag glob " + ch + " " + ch + ch + "

\n
"; - final String asciiDoc = parser.parseConfigDescription(javaDoc); + final String asciiDoc = JavadocToAsciidocTransformer.INSTANCE.parseConfigItemJavadoc(javaDoc).description(); final String actual = Factory.create().convert(asciiDoc, Collections.emptyMap()); assertEquals(expected, actual); } @Test void trim() { - assertEquals("+ \nfoo", JavaDocParser.trim(new StringBuilder("+ \nfoo"))); - assertEquals("+", JavaDocParser.trim(new StringBuilder(" +"))); - assertEquals("foo", JavaDocParser.trim(new StringBuilder(" +\nfoo"))); - assertEquals("foo +", JavaDocParser.trim(new StringBuilder("foo +"))); - assertEquals("foo", JavaDocParser.trim(new StringBuilder("foo"))); - assertEquals("+", JavaDocParser.trim(new StringBuilder("+ \n"))); - assertEquals("+", JavaDocParser.trim(new StringBuilder(" +\n+ \n"))); - assertEquals("", JavaDocParser.trim(new StringBuilder(" +\n"))); - assertEquals("foo", JavaDocParser.trim(new StringBuilder(" \n\tfoo"))); - assertEquals("foo", JavaDocParser.trim(new StringBuilder("foo \n\t"))); - assertEquals("foo", JavaDocParser.trim(new StringBuilder(" \n\tfoo \n\t"))); - assertEquals("", JavaDocParser.trim(new StringBuilder(""))); - assertEquals("", JavaDocParser.trim(new StringBuilder(" \n\t"))); - assertEquals("+", JavaDocParser.trim(new StringBuilder(" +"))); - assertEquals("", JavaDocParser.trim(new StringBuilder(" +\n"))); - assertEquals("", JavaDocParser.trim(new StringBuilder(" +\n +\n"))); - assertEquals("foo +\nbar", JavaDocParser.trim(new StringBuilder(" foo +\nbar +\n"))); + assertEquals("+ \nfoo", JavadocToAsciidocTransformer.trim(new StringBuilder("+ \nfoo"))); + assertEquals("+", JavadocToAsciidocTransformer.trim(new StringBuilder(" +"))); + assertEquals("foo", JavadocToAsciidocTransformer.trim(new StringBuilder(" +\nfoo"))); + assertEquals("foo +", JavadocToAsciidocTransformer.trim(new StringBuilder("foo +"))); + assertEquals("foo", JavadocToAsciidocTransformer.trim(new StringBuilder("foo"))); + assertEquals("+", JavadocToAsciidocTransformer.trim(new StringBuilder("+ \n"))); + assertEquals("+", JavadocToAsciidocTransformer.trim(new StringBuilder(" +\n+ \n"))); + assertEquals("", JavadocToAsciidocTransformer.trim(new StringBuilder(" +\n"))); + assertEquals("foo", JavadocToAsciidocTransformer.trim(new StringBuilder(" \n\tfoo"))); + assertEquals("foo", JavadocToAsciidocTransformer.trim(new StringBuilder("foo \n\t"))); + assertEquals("foo", JavadocToAsciidocTransformer.trim(new StringBuilder(" \n\tfoo \n\t"))); + assertEquals("", JavadocToAsciidocTransformer.trim(new StringBuilder(""))); + assertEquals("", JavadocToAsciidocTransformer.trim(new StringBuilder(" \n\t"))); + assertEquals("+", JavadocToAsciidocTransformer.trim(new StringBuilder(" +"))); + assertEquals("", JavadocToAsciidocTransformer.trim(new StringBuilder(" +\n"))); + assertEquals("", JavadocToAsciidocTransformer.trim(new StringBuilder(" +\n +\n"))); + assertEquals("foo +\nbar", JavadocToAsciidocTransformer.trim(new StringBuilder(" foo +\nbar +\n"))); } } diff --git a/core/processor/src/test/java/io/quarkus/annotation/processor/documentation/config/formatter/JavadocToAsciidocTransformerConfigSectionTest.java b/core/processor/src/test/java/io/quarkus/annotation/processor/documentation/config/formatter/JavadocToAsciidocTransformerConfigSectionTest.java new file mode 100644 index 00000000000000..190b32c9bba844 --- /dev/null +++ b/core/processor/src/test/java/io/quarkus/annotation/processor/documentation/config/formatter/JavadocToAsciidocTransformerConfigSectionTest.java @@ -0,0 +1,127 @@ +package io.quarkus.annotation.processor.documentation.config.formatter; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +import io.quarkus.annotation.processor.documentation.config.discovery.ParsedJavadocSection; + +public class JavadocToAsciidocTransformerConfigSectionTest { + + @Test + public void parseNullSection() { + ParsedJavadocSection parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigSectionJavadoc(null); + assertEquals(null, parsed.details()); + assertEquals(null, parsed.title()); + } + + @Test + public void parseUntrimmedJavaDoc() { + ParsedJavadocSection parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigSectionJavadoc(" "); + assertEquals(null, parsed.title()); + assertEquals(null, parsed.details()); + + parsed = JavadocToAsciidocTransformer.INSTANCE.parseConfigSectionJavadoc("

"); + assertEquals(null, parsed.title()); + assertEquals(null, parsed.details()); + } + + @Test + public void passThroughAConfigSectionInAsciiDoc() { + String title = "My Asciidoc"; + String details = "Let's have a https://quarkus.io[link to our website].\n" + + "\n" + + "[TIP]\n" + + "====\n" + + "A nice tip\n" + + "====\n" + + "\n" + + "[source,java]\n" + + "----\n" + + "And some code\n" + + "----"; + + String asciidoc = "=== " + title + "\n\n" + details; + + ParsedJavadocSection sectionHolder = JavadocToAsciidocTransformer.INSTANCE + .parseConfigSectionJavadoc(asciidoc + "\n" + "@asciidoclet"); + assertEquals(title, sectionHolder.title()); + assertEquals(details, sectionHolder.details()); + + asciidoc = "Asciidoc title. \n" + + "\n" + + "Let's have a https://quarkus.io[link to our website].\n" + + "\n" + + "[TIP]\n" + + "====\n" + + "A nice tip\n" + + "====\n" + + "\n" + + "[source,java]\n" + + "----\n" + + "And some code\n" + + "----"; + + sectionHolder = JavadocToAsciidocTransformer.INSTANCE.parseConfigSectionJavadoc(asciidoc + "\n" + "@asciidoclet"); + assertEquals("Asciidoc title", sectionHolder.title()); + } + + @Test + public void parseSectionWithoutIntroduction() { + /** + * Simple javadoc + */ + String javaDoc = "Config Section"; + String expectedTitle = "Config Section"; + String expectedDetails = null; + ParsedJavadocSection sectionHolder = JavadocToAsciidocTransformer.INSTANCE.parseConfigSectionJavadoc(javaDoc); + assertEquals(expectedDetails, sectionHolder.details()); + assertEquals(expectedTitle, sectionHolder.title()); + + javaDoc = "Config Section."; + expectedTitle = "Config Section"; + expectedDetails = null; + sectionHolder = JavadocToAsciidocTransformer.INSTANCE.parseConfigSectionJavadoc(javaDoc); + assertEquals(expectedDetails, sectionHolder.details()); + assertEquals(expectedTitle, sectionHolder.title()); + + /** + * html javadoc + */ + javaDoc = "

Config Section

"; + expectedTitle = "Config Section"; + expectedDetails = null; + sectionHolder = JavadocToAsciidocTransformer.INSTANCE.parseConfigSectionJavadoc(javaDoc); + assertEquals(expectedDetails, sectionHolder.details()); + assertEquals(expectedTitle, sectionHolder.title()); + } + + @Test + public void parseSectionWithIntroduction() { + /** + * Simple javadoc + */ + String javaDoc = "Config Section .Introduction"; + String expectedDetails = "Introduction"; + String expectedTitle = "Config Section"; + assertEquals(expectedTitle, JavadocToAsciidocTransformer.INSTANCE.parseConfigSectionJavadoc(javaDoc).title()); + assertEquals(expectedDetails, JavadocToAsciidocTransformer.INSTANCE.parseConfigSectionJavadoc(javaDoc).details()); + + /** + * html javadoc + */ + javaDoc = "

Config Section

. Introduction"; + expectedDetails = "Introduction"; + assertEquals(expectedDetails, JavadocToAsciidocTransformer.INSTANCE.parseConfigSectionJavadoc(javaDoc).details()); + assertEquals(expectedTitle, JavadocToAsciidocTransformer.INSTANCE.parseConfigSectionJavadoc(javaDoc).title()); + } + + @Test + public void properlyParseConfigSectionWrittenInHtml() { + String javaDoc = "

Config Section.

This is section introduction"; + String expectedDetails = "This is section introduction"; + String title = "Config Section"; + assertEquals(expectedDetails, JavadocToAsciidocTransformer.INSTANCE.parseConfigSectionJavadoc(javaDoc).details()); + assertEquals(title, JavadocToAsciidocTransformer.INSTANCE.parseConfigSectionJavadoc(javaDoc).title()); + } +} diff --git a/core/processor/src/test/java/io/quarkus/annotation/processor/documentation/config/util/ConfigNamingUtilTest.java b/core/processor/src/test/java/io/quarkus/annotation/processor/documentation/config/util/ConfigNamingUtilTest.java new file mode 100644 index 00000000000000..ae98968392ea65 --- /dev/null +++ b/core/processor/src/test/java/io/quarkus/annotation/processor/documentation/config/util/ConfigNamingUtilTest.java @@ -0,0 +1,106 @@ +package io.quarkus.annotation.processor.documentation.config.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +import io.quarkus.annotation.processor.documentation.config.model.ConfigPhase; + +public class ConfigNamingUtilTest { + + @Test + public void replaceNonAlphanumericByUnderscoresThenConvertToUpperCase() { + assertEquals("QUARKUS_DATASOURCE__DATASOURCE_NAME__JDBC_BACKGROUND_VALIDATION_INTERVAL", + ConfigNamingUtil.toEnvVarName("quarkus.datasource.\"datasource-name\".jdbc.background-validation-interval")); + assertEquals( + "QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__NAMED_PRINCIPAL_QUERIES__BCRYPT_PASSWORD_MAPPER_ITERATION_COUNT_INDEX", + ConfigNamingUtil.toEnvVarName( + "quarkus.security.jdbc.principal-query.\"named-principal-queries\".bcrypt-password-mapper.iteration-count-index")); + } + + @Test + void getRootPrefixTest() { + String prefix = "quarkus"; + String name = Markers.HYPHENATED_ELEMENT_NAME; + String simpleClassName = "MyConfig"; + String actual = ConfigNamingUtil.getRootPrefix(prefix, name, simpleClassName, ConfigPhase.RUN_TIME); + assertEquals("quarkus.my", actual); + + prefix = "my.prefix"; + name = ""; + simpleClassName = "MyPrefix"; + actual = ConfigNamingUtil.getRootPrefix(prefix, name, simpleClassName, ConfigPhase.RUN_TIME); + assertEquals("my.prefix", actual); + + prefix = ""; + name = "my.prefix"; + simpleClassName = "MyPrefix"; + actual = ConfigNamingUtil.getRootPrefix(prefix, name, simpleClassName, ConfigPhase.RUN_TIME); + assertEquals("my.prefix", actual); + + prefix = "my"; + name = "prefix"; + simpleClassName = "MyPrefix"; + actual = ConfigNamingUtil.getRootPrefix(prefix, name, simpleClassName, ConfigPhase.RUN_TIME); + assertEquals("my.prefix", actual); + + prefix = "quarkus"; + name = "prefix"; + simpleClassName = "SomethingElse"; + actual = ConfigNamingUtil.getRootPrefix(prefix, name, simpleClassName, ConfigPhase.RUN_TIME); + assertEquals("quarkus.prefix", actual); + + prefix = ""; + name = Markers.HYPHENATED_ELEMENT_NAME; + simpleClassName = "SomethingElse"; + actual = ConfigNamingUtil.getRootPrefix(prefix, name, simpleClassName, ConfigPhase.RUN_TIME); + assertEquals("quarkus.something-else", actual); + } + + @Test + public void derivingConfigRootNameTestCase() { + // should hyphenate class name + String simpleClassName = "RootName"; + String actual = ConfigNamingUtil.deriveConfigRootName(simpleClassName, "", ConfigPhase.RUN_TIME); + assertEquals("quarkus.root-name", actual); + + // should hyphenate class name after removing Config(uration) suffix + simpleClassName = "RootNameConfig"; + actual = ConfigNamingUtil.deriveConfigRootName(simpleClassName, "", ConfigPhase.BUILD_TIME); + assertEquals("quarkus.root-name", actual); + + simpleClassName = "RootNameConfiguration"; + actual = ConfigNamingUtil.deriveConfigRootName(simpleClassName, "", ConfigPhase.BUILD_AND_RUN_TIME_FIXED); + assertEquals("quarkus.root-name", actual); + + // should hyphenate class name after removing RunTimeConfig(uration) suffix + simpleClassName = "RootNameRunTimeConfig"; + actual = ConfigNamingUtil.deriveConfigRootName(simpleClassName, "", ConfigPhase.RUN_TIME); + assertEquals("quarkus.root-name", actual); + + simpleClassName = "RootNameRuntimeConfig"; + actual = ConfigNamingUtil.deriveConfigRootName(simpleClassName, "", ConfigPhase.RUN_TIME); + assertEquals("quarkus.root-name", actual); + + simpleClassName = "RootNameRunTimeConfiguration"; + actual = ConfigNamingUtil.deriveConfigRootName(simpleClassName, "", ConfigPhase.RUN_TIME); + assertEquals("quarkus.root-name", actual); + + // should hyphenate class name after removing BuildTimeConfig(uration) suffix + simpleClassName = "RootNameBuildTimeConfig"; + actual = ConfigNamingUtil.deriveConfigRootName(simpleClassName, "", ConfigPhase.BUILD_AND_RUN_TIME_FIXED); + assertEquals("quarkus.root-name", actual); + + simpleClassName = "RootNameBuildTimeConfiguration"; + actual = ConfigNamingUtil.deriveConfigRootName(simpleClassName, "", ConfigPhase.BUILD_TIME); + assertEquals("quarkus.root-name", actual); + + simpleClassName = "RootName"; + actual = ConfigNamingUtil.deriveConfigRootName(simpleClassName, "prefix", ConfigPhase.RUN_TIME); + assertEquals("prefix.root-name", actual); + + simpleClassName = "RootName"; + actual = ConfigNamingUtil.deriveConfigRootName(simpleClassName, "my.prefix", ConfigPhase.RUN_TIME); + assertEquals("my.prefix.root-name", actual); + } +} diff --git a/core/processor/src/test/java/io/quarkus/annotation/processor/documentation/config/util/JavadocUtilTest.java b/core/processor/src/test/java/io/quarkus/annotation/processor/documentation/config/util/JavadocUtilTest.java new file mode 100644 index 00000000000000..9fab0e55e0e528 --- /dev/null +++ b/core/processor/src/test/java/io/quarkus/annotation/processor/documentation/config/util/JavadocUtilTest.java @@ -0,0 +1,121 @@ +package io.quarkus.annotation.processor.documentation.config.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.math.BigInteger; +import java.net.InetAddress; +import java.time.Duration; +import java.util.List; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +public class JavadocUtilTest { + + @Test + public void shouldReturnEmptyListForPrimitiveValue() { + String value = JavadocUtil.getJavadocSiteLink("int"); + assertNull(value); + + value = JavadocUtil.getJavadocSiteLink("long"); + assertNull(value); + + value = JavadocUtil.getJavadocSiteLink("float"); + assertNull(value); + + value = JavadocUtil.getJavadocSiteLink("boolean"); + assertNull(value); + + value = JavadocUtil.getJavadocSiteLink("double"); + assertNull(value); + + value = JavadocUtil.getJavadocSiteLink("char"); + assertNull(value); + + value = JavadocUtil.getJavadocSiteLink("short"); + assertNull(value); + + value = JavadocUtil.getJavadocSiteLink("byte"); + assertNull(value); + + value = JavadocUtil.getJavadocSiteLink(Boolean.class.getName()); + assertNull(value); + + value = JavadocUtil.getJavadocSiteLink(Byte.class.getName()); + assertNull(value); + + value = JavadocUtil.getJavadocSiteLink(Short.class.getName()); + assertNull(value); + + value = JavadocUtil.getJavadocSiteLink(Integer.class.getName()); + assertNull(value); + + value = JavadocUtil.getJavadocSiteLink(Long.class.getName()); + assertNull(value); + + value = JavadocUtil.getJavadocSiteLink(Float.class.getName()); + assertNull(value); + + value = JavadocUtil.getJavadocSiteLink(Double.class.getName()); + assertNull(value); + + value = JavadocUtil.getJavadocSiteLink(Character.class.getName()); + assertNull(value); + } + + @Test + public void shouldReturnALinkToOfficialJavaDocIfIsJavaOfficialType() { + String value = JavadocUtil.getJavadocSiteLink(String.class.getName()); + // for String, we don't return a Javadoc link as it's a very basic type + assertNull(value); + + value = JavadocUtil.getJavadocSiteLink(InetAddress.class.getName()); + assertEquals(JavadocUtil.OFFICIAL_JAVA_DOC_BASE_LINK + "java/net/InetAddress.html", value); + + value = JavadocUtil.getJavadocSiteLink(BigInteger.class.getName()); + assertEquals(JavadocUtil.OFFICIAL_JAVA_DOC_BASE_LINK + "java/math/BigInteger.html", value); + + value = JavadocUtil.getJavadocSiteLink(Duration.class.getName()); + assertEquals(JavadocUtil.OFFICIAL_JAVA_DOC_BASE_LINK + "java/time/Duration.html", value); + + value = JavadocUtil.getJavadocSiteLink((Map.Entry.class.getName().replace('$', '.'))); + assertEquals(JavadocUtil.OFFICIAL_JAVA_DOC_BASE_LINK + "java/util/Map.Entry.html", value); + + value = JavadocUtil.getJavadocSiteLink(Map.Entry.class.getName()); + assertEquals(JavadocUtil.OFFICIAL_JAVA_DOC_BASE_LINK + "java/util/Map.Entry.html", value); + + value = JavadocUtil.getJavadocSiteLink(List.class.getName()); + assertEquals(JavadocUtil.OFFICIAL_JAVA_DOC_BASE_LINK + "java/util/List.html", value); + + value = JavadocUtil.getJavadocSiteLink("java.util.List"); + assertEquals(JavadocUtil.OFFICIAL_JAVA_DOC_BASE_LINK + "java/util/List.html", value); + } + + @Test + public void shouldReturnALinkToAgroalJavaDocIfTypeIsDeclaredInAgroalPackage() { + String value = JavadocUtil.getJavadocSiteLink( + "io.agroal.api.configuration.AgroalConnectionFactoryConfiguration.TransactionIsolation"); + assertEquals(JavadocUtil.AGROAL_API_JAVA_DOC_SITE + + "io/agroal/api/configuration/AgroalConnectionFactoryConfiguration.TransactionIsolation.html", value); + + value = JavadocUtil.getJavadocSiteLink("io.agroal.api.AgroalDataSource.FlushMode"); + assertEquals(JavadocUtil.AGROAL_API_JAVA_DOC_SITE + "io/agroal/api/AgroalDataSource.FlushMode.html", value); + } + + @Test + public void shouldReturnALinkToVertxJavaDocIfTypeIsDeclaredInVertxPackage() { + String value = JavadocUtil.getJavadocSiteLink( + "io.vertx.core.Context"); + assertEquals(JavadocUtil.VERTX_JAVA_DOC_SITE + "io/vertx/core/Context.html", value); + + value = JavadocUtil.getJavadocSiteLink("io.vertx.amqp.AmqpMessage"); + assertEquals(JavadocUtil.VERTX_JAVA_DOC_SITE + "io/vertx/amqp/AmqpMessage.html", value); + } + + @Test + public void shouldReturnEmptyLinkIfUnknownJavaDocType() { + String value = JavadocUtil.getJavadocSiteLink("io.quarkus.ConfigDocKey"); + assertNull(value); + } +} diff --git a/core/processor/src/test/java/io/quarkus/annotation/processor/documentation/config/util/TypeUtilTest.java b/core/processor/src/test/java/io/quarkus/annotation/processor/documentation/config/util/TypeUtilTest.java new file mode 100644 index 00000000000000..e25c5d652087f9 --- /dev/null +++ b/core/processor/src/test/java/io/quarkus/annotation/processor/documentation/config/util/TypeUtilTest.java @@ -0,0 +1,20 @@ +package io.quarkus.annotation.processor.documentation.config.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class TypeUtilTest { + + @Test + public void normalizeDurationValueTest() { + assertEquals("", TypeUtil.normalizeDurationValue("")); + assertEquals("1S", TypeUtil.normalizeDurationValue("1")); + assertEquals("1S", TypeUtil.normalizeDurationValue("1S")); + assertEquals("1S", TypeUtil.normalizeDurationValue("1s")); + + // values are not validated here + assertEquals("1_000", TypeUtil.normalizeDurationValue("1_000")); + assertEquals("FOO", TypeUtil.normalizeDurationValue("foo")); + } +} diff --git a/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/ConfigDocKeyTest.java b/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/ConfigDocKeyTest.java deleted file mode 100644 index 8a5c4b0ba8324a..00000000000000 --- a/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/ConfigDocKeyTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.time.Duration; -import java.util.List; -import java.util.Map; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class ConfigDocKeyTest { - - private ConfigDocKey configDocKey; - - @BeforeEach - public void setup() { - configDocKey = new ConfigDocKey(); - } - - @Test - public void shouldComputePrimitiveSimpleName() { - configDocKey.setType(int.class.getSimpleName()); - String simpleName = configDocKey.computeTypeSimpleName(); - assertEquals(int.class.getSimpleName(), simpleName); - - configDocKey.setType(long.class.getSimpleName()); - simpleName = configDocKey.computeTypeSimpleName(); - assertEquals(long.class.getSimpleName(), simpleName); - - configDocKey.setType(boolean.class.getSimpleName()); - simpleName = configDocKey.computeTypeSimpleName(); - assertEquals(boolean.class.getSimpleName(), simpleName); - } - - @Test - public void shouldComputeClassSimpleName() { - configDocKey.setType(Duration.class.getName()); - String simpleName = configDocKey.computeTypeSimpleName(); - assertEquals(Duration.class.getSimpleName(), simpleName); - - configDocKey.setType(List.class.getName()); - simpleName = configDocKey.computeTypeSimpleName(); - assertEquals(List.class.getSimpleName(), simpleName); - - configDocKey.setType(String.class.getName()); - simpleName = configDocKey.computeTypeSimpleName(); - assertEquals(String.class.getSimpleName(), simpleName); - - configDocKey.setType(Map.Entry.class.getName()); - simpleName = configDocKey.computeTypeSimpleName(); - assertEquals(Map.Entry.class.getSimpleName(), simpleName); - } -} diff --git a/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/DocGeneratorUtilTest.java b/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/DocGeneratorUtilTest.java deleted file mode 100644 index 57fc8df1dee9fd..00000000000000 --- a/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/DocGeneratorUtilTest.java +++ /dev/null @@ -1,427 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.AGROAL_API_JAVA_DOC_SITE; -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.OFFICIAL_JAVA_DOC_BASE_LINK; -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.VERTX_JAVA_DOC_SITE; -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.appendConfigItemsIntoExistingOnes; -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.computeConfigGroupDocFileName; -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.computeConfigRootDocFileName; -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.computeExtensionDocFileName; -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.deriveConfigRootName; -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.getJavaDocSiteLink; -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.getName; -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.normalizeDurationValue; -import static io.quarkus.annotation.processor.generate_doc.DocGeneratorUtil.toEnvVarName; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.math.BigInteger; -import java.net.InetAddress; -import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import org.junit.jupiter.api.Test; - -public class DocGeneratorUtilTest { - @Test - public void shouldReturnEmptyListForPrimitiveValue() { - String value = getJavaDocSiteLink("int"); - assertEquals(Constants.EMPTY, value); - - value = getJavaDocSiteLink("long"); - assertEquals(Constants.EMPTY, value); - - value = getJavaDocSiteLink("float"); - assertEquals(Constants.EMPTY, value); - - value = getJavaDocSiteLink("boolean"); - assertEquals(Constants.EMPTY, value); - - value = getJavaDocSiteLink("double"); - assertEquals(Constants.EMPTY, value); - - value = getJavaDocSiteLink("char"); - assertEquals(Constants.EMPTY, value); - - value = getJavaDocSiteLink("short"); - assertEquals(Constants.EMPTY, value); - - value = getJavaDocSiteLink("byte"); - assertEquals(Constants.EMPTY, value); - - value = getJavaDocSiteLink(Boolean.class.getName()); - assertEquals(Constants.EMPTY, value); - - value = getJavaDocSiteLink(Byte.class.getName()); - assertEquals(Constants.EMPTY, value); - - value = getJavaDocSiteLink(Short.class.getName()); - assertEquals(Constants.EMPTY, value); - - value = getJavaDocSiteLink(Integer.class.getName()); - assertEquals(Constants.EMPTY, value); - - value = getJavaDocSiteLink(Long.class.getName()); - assertEquals(Constants.EMPTY, value); - - value = getJavaDocSiteLink(Float.class.getName()); - assertEquals(Constants.EMPTY, value); - - value = getJavaDocSiteLink(Double.class.getName()); - assertEquals(Constants.EMPTY, value); - - value = getJavaDocSiteLink(Character.class.getName()); - assertEquals(Constants.EMPTY, value); - } - - @Test - public void shouldReturnALinkToOfficialJavaDocIfIsJavaOfficialType() { - String value = getJavaDocSiteLink(String.class.getName()); - assertEquals(OFFICIAL_JAVA_DOC_BASE_LINK + "java/lang/String.html", value); - - value = getJavaDocSiteLink(InetAddress.class.getName()); - assertEquals(OFFICIAL_JAVA_DOC_BASE_LINK + "java/net/InetAddress.html", value); - - value = getJavaDocSiteLink(BigInteger.class.getName()); - assertEquals(OFFICIAL_JAVA_DOC_BASE_LINK + "java/math/BigInteger.html", value); - - value = getJavaDocSiteLink(Duration.class.getName()); - assertEquals(OFFICIAL_JAVA_DOC_BASE_LINK + "java/time/Duration.html", value); - - value = getJavaDocSiteLink((Map.Entry.class.getName().replace('$', '.'))); - assertEquals(OFFICIAL_JAVA_DOC_BASE_LINK + "java/util/Map.Entry.html", value); - - value = getJavaDocSiteLink(Map.Entry.class.getName()); - assertEquals(OFFICIAL_JAVA_DOC_BASE_LINK + "java/util/Map.Entry.html", value); - - value = getJavaDocSiteLink(List.class.getName()); - assertEquals(OFFICIAL_JAVA_DOC_BASE_LINK + "java/util/List.html", value); - - value = getJavaDocSiteLink("java.util.List"); - assertEquals(OFFICIAL_JAVA_DOC_BASE_LINK + "java/util/List.html", value); - } - - @Test - public void replaceNonAlphanumericByUnderscoresThenConvertToUpperCase() { - assertEquals("QUARKUS_DATASOURCE__DATASOURCE_NAME__JDBC_BACKGROUND_VALIDATION_INTERVAL", - toEnvVarName("quarkus.datasource.\"datasource-name\".jdbc.background-validation-interval")); - assertEquals( - "QUARKUS_SECURITY_JDBC_PRINCIPAL_QUERY__NAMED_PRINCIPAL_QUERIES__BCRYPT_PASSWORD_MAPPER_ITERATION_COUNT_INDEX", - toEnvVarName( - "quarkus.security.jdbc.principal-query.\"named-principal-queries\".bcrypt-password-mapper.iteration-count-index")); - } - - @Test - public void shouldReturnALinkToAgroalJavaDocIfTypeIsDeclaredInAgroalPackage() { - String value = getJavaDocSiteLink( - "io.agroal.api.configuration.AgroalConnectionFactoryConfiguration.TransactionIsolation"); - assertEquals(AGROAL_API_JAVA_DOC_SITE - + "io/agroal/api/configuration/AgroalConnectionFactoryConfiguration.TransactionIsolation.html", value); - - value = getJavaDocSiteLink("io.agroal.api.AgroalDataSource.FlushMode"); - assertEquals(AGROAL_API_JAVA_DOC_SITE + "io/agroal/api/AgroalDataSource.FlushMode.html", value); - } - - @Test - public void shouldReturnALinkToVertxJavaDocIfTypeIsDeclaredInVertxPackage() { - String value = getJavaDocSiteLink( - "io.vertx.core.Context"); - assertEquals(VERTX_JAVA_DOC_SITE + "io/vertx/core/Context.html", value); - - value = getJavaDocSiteLink("io.vertx.amqp.AmqpMessage"); - assertEquals(VERTX_JAVA_DOC_SITE + "io/vertx/amqp/AmqpMessage.html", value); - } - - @Test - public void shouldReturnEmptyLinkIfUnknownJavaDocType() { - String value = getJavaDocSiteLink("io.quarkus.ConfigDocKey"); - assertEquals(Constants.EMPTY, value); - } - - @Test - public void shouldReturnConfigRootNameWhenComputingExtensionName() { - String configRoot = "org.acme.ConfigRoot"; - String expected = "org.acme.ConfigRoot.adoc"; - String fileName = computeExtensionDocFileName(configRoot); - assertEquals(expected, fileName); - } - - @Test - public void shouldUseCoreForConfigRootsCoreModuleWhenComputingExtensionName() { - String configRoot = "io.quarkus.runtime.RuntimeConfig"; - String expected = "quarkus-core.adoc"; - String fileName = computeExtensionDocFileName(configRoot); - assertEquals(expected, fileName); - - configRoot = "io.quarkus.deployment.BuildTimeConfig"; - expected = "quarkus-core.adoc"; - fileName = computeExtensionDocFileName(configRoot); - assertEquals(expected, fileName); - - configRoot = "io.quarkus.deployment.path.BuildTimeConfig"; - expected = "quarkus-core.adoc"; - fileName = computeExtensionDocFileName(configRoot); - assertEquals(expected, fileName); - } - - @Test - public void shouldGuessArtifactIdWhenComputingExtensionName() { - String configRoot = "io.quarkus.agroal.Config"; - String expected = "quarkus-agroal.adoc"; - String fileName = computeExtensionDocFileName(configRoot); - assertEquals(expected, fileName); - - configRoot = "io.quarkus.keycloak.Config"; - expected = "quarkus-keycloak.adoc"; - fileName = computeExtensionDocFileName(configRoot); - assertEquals(expected, fileName); - - configRoot = "io.quarkus.extension.name.BuildTimeConfig"; - expected = "quarkus-extension-name.adoc"; - fileName = computeExtensionDocFileName(configRoot); - assertEquals(expected, fileName); - } - - @Test - public void shouldUseHyphenatedClassNameWithoutRuntimeOrDeploymentNamespaceWhenComputingConfigGroupFileName() { - String configRoot = "ClassName"; - String expected = "config-group-class-name.adoc"; - String fileName = computeConfigGroupDocFileName(configRoot); - assertEquals(expected, fileName); - - configRoot = "io.quarkus.agroal.ConfigGroup"; - expected = "quarkus-agroal-config-group.adoc"; - fileName = computeConfigGroupDocFileName(configRoot); - assertEquals(expected, fileName); - - configRoot = "io.quarkus.agroal.runtime.ClassName"; - expected = "quarkus-agroal-config-group-class-name.adoc"; - fileName = computeConfigGroupDocFileName(configRoot); - assertEquals(expected, fileName); - - configRoot = "io.quarkus.keycloak.deployment.RealmConfig"; - expected = "quarkus-keycloak-config-group-realm-config.adoc"; - fileName = computeConfigGroupDocFileName(configRoot); - assertEquals(expected, fileName); - - configRoot = "io.quarkus.extension.deployment.BuildTimeConfig"; - expected = "quarkus-extension-config-group-build-time-config.adoc"; - fileName = computeConfigGroupDocFileName(configRoot); - assertEquals(expected, fileName); - - configRoot = "io.quarkus.extension.deployment.name.BuildTimeConfig"; - expected = "quarkus-extension-config-group-name-build-time-config.adoc"; - fileName = computeConfigGroupDocFileName(configRoot); - assertEquals(expected, fileName); - } - - @Test - public void shouldUseHyphenatedClassNameWithEverythingBeforeRuntimeOrDeploymentNamespaceReplacedByConfigRootNameWhenComputingConfigRootFileName() { - String configRoot = "ClassName"; - String expected = "root-name-class-name.adoc"; - String fileName = computeConfigRootDocFileName(configRoot, "root-name"); - assertEquals(expected, fileName); - - configRoot = "io.quarkus.agroal.runtime.ClassName"; - expected = "quarkus-datasource-class-name.adoc"; - fileName = computeConfigRootDocFileName(configRoot, "quarkus-datasource"); - assertEquals(expected, fileName); - - configRoot = "io.quarkus.keycloak.deployment.RealmConfig"; - expected = "quarkus-keycloak-realm-config.adoc"; - fileName = computeConfigRootDocFileName(configRoot, "quarkus-keycloak"); - assertEquals(expected, fileName); - - configRoot = "io.quarkus.extension.deployment.BuildTimeConfig"; - expected = "quarkus-root-10-build-time-config.adoc"; - fileName = computeConfigRootDocFileName(configRoot, "quarkus-root-10"); - assertEquals(expected, fileName); - - configRoot = "io.quarkus.extension.deployment.name.BuildTimeConfig"; - expected = "quarkus-config-root-name-build-time-config.adoc"; - fileName = computeConfigRootDocFileName(configRoot, "quarkus-config-root"); - assertEquals(expected, fileName); - } - - @Test - public void shouldPreserveExistingConfigItemsWhenAppendAnEmptyConfigItems() { - List existingConfigItems = Arrays.asList(new ConfigDocItem(), new ConfigDocItem()); - appendConfigItemsIntoExistingOnes(existingConfigItems, Collections.emptyList()); - assertEquals(2, existingConfigItems.size()); - } - - @Test - public void shouldAppendNewConfigItemsAtTheEndOfExistingConfigItems() { - List existingConfigItems = new ArrayList<>( - Arrays.asList(new ConfigDocItem(null, new ConfigDocKey()), new ConfigDocItem(null, new ConfigDocKey()))); - ConfigDocItem newItem = new ConfigDocItem(null, new ConfigDocKey()); - ConfigDocSection configDocSection = new ConfigDocSection(); - configDocSection.setSectionDetailsTitle("title"); - ConfigDocItem section = new ConfigDocItem(configDocSection, null); - List newConfigItems = Arrays.asList(newItem, section); - - appendConfigItemsIntoExistingOnes(existingConfigItems, newConfigItems); - - assertEquals(4, existingConfigItems.size()); - List addedList = existingConfigItems.subList(2, 4); - assertEquals(newItem, addedList.get(0)); - assertEquals(section, addedList.get(1)); - } - - @Test - public void shouldAppendConfigSectionConfigItemsIntoExistingConfigItemsOfConfigSectionWithSameTitle() { - ConfigDocSection existingSection = new ConfigDocSection(); - existingSection.setSectionDetailsTitle("title"); - ConfigDocItem configItem = new ConfigDocItem(null, new ConfigDocKey()); - existingSection.addConfigDocItems(Arrays.asList(configItem)); - - ConfigDocItem configDocItem = new ConfigDocItem(existingSection, null); - List existingConfigItems = new ArrayList<>(Arrays.asList(configDocItem)); - - ConfigDocSection configDocSection = new ConfigDocSection(); - configDocSection.setSectionDetailsTitle("title"); - ConfigDocItem newConfigItem = new ConfigDocItem(null, new ConfigDocKey()); - configDocSection.addConfigDocItems(Arrays.asList(newConfigItem)); - ConfigDocItem section = new ConfigDocItem(configDocSection, null); - - appendConfigItemsIntoExistingOnes(existingConfigItems, Arrays.asList(section)); - - assertEquals(1, existingConfigItems.size()); - assertEquals(2, existingSection.getConfigDocItems().size()); - - assertEquals(configItem, existingSection.getConfigDocItems().get(0)); - assertEquals(newConfigItem, existingSection.getConfigDocItems().get(1)); - } - - // TODO - should deep merge be supported? Or we should only merge top level sections? - @Test - public void shouldDeepAppendConfigSectionConfigItemsIntoExistingConfigItemsOfConfigSectionWithSameTitle() { - ConfigDocSection deepSection = new ConfigDocSection(); - deepSection.setSectionDetailsTitle("title"); - ConfigDocItem deepConfigKey = new ConfigDocItem(null, new ConfigDocKey()); - deepSection.addConfigDocItems(Arrays.asList(deepConfigKey)); - ConfigDocItem deepConfigItem = new ConfigDocItem(deepSection, null); - - ConfigDocSection section = new ConfigDocSection(); - section.setSectionDetailsTitle(""); - section.addConfigDocItems(Arrays.asList(deepConfigItem)); - - ConfigDocItem configItemWithDeepSection = new ConfigDocItem(section, null); - List existingConfigItems = new ArrayList<>(Arrays.asList(configItemWithDeepSection)); - - ConfigDocSection configDocSection = new ConfigDocSection(); - configDocSection.setSectionDetailsTitle("title"); - ConfigDocItem configItem = new ConfigDocItem(null, new ConfigDocKey()); - configDocSection.addConfigDocItems(Arrays.asList(configItem)); - ConfigDocItem configDocItem = new ConfigDocItem(configDocSection, null); - - appendConfigItemsIntoExistingOnes(existingConfigItems, Arrays.asList(configDocItem)); - - assertEquals(1, existingConfigItems.size()); - assertEquals(2, deepSection.getConfigDocItems().size()); - - assertEquals(deepConfigKey, deepSection.getConfigDocItems().get(0)); - assertEquals(configItem, deepSection.getConfigDocItems().get(1)); - } - - @Test - void getNameTest() { - String prefix = Constants.QUARKUS; - String name = Constants.HYPHENATED_ELEMENT_NAME; - String simpleClassName = "MyConfig"; - String actual = getName(prefix, name, simpleClassName, ConfigPhase.RUN_TIME); - assertEquals("quarkus.my", actual); - - prefix = "my.prefix"; - name = ""; - simpleClassName = "MyPrefix"; - actual = getName(prefix, name, simpleClassName, ConfigPhase.RUN_TIME); - assertEquals("my.prefix", actual); - - prefix = ""; - name = "my.prefix"; - simpleClassName = "MyPrefix"; - actual = getName(prefix, name, simpleClassName, ConfigPhase.RUN_TIME); - assertEquals("my.prefix", actual); - - prefix = "my"; - name = "prefix"; - simpleClassName = "MyPrefix"; - actual = getName(prefix, name, simpleClassName, ConfigPhase.RUN_TIME); - assertEquals("my.prefix", actual); - - prefix = Constants.QUARKUS; - name = "prefix"; - simpleClassName = "SomethingElse"; - actual = getName(prefix, name, simpleClassName, ConfigPhase.RUN_TIME); - assertEquals("quarkus.prefix", actual); - - prefix = ""; - name = Constants.HYPHENATED_ELEMENT_NAME; - simpleClassName = "SomethingElse"; - actual = getName(prefix, name, simpleClassName, ConfigPhase.RUN_TIME); - assertEquals("quarkus.something-else", actual); - } - - @Test - public void derivingConfigRootNameTestCase() { - // should hyphenate class name - String simpleClassName = "RootName"; - String actual = deriveConfigRootName(simpleClassName, "", ConfigPhase.RUN_TIME); - assertEquals("quarkus.root-name", actual); - - // should hyphenate class name after removing Config(uration) suffix - simpleClassName = "RootNameConfig"; - actual = deriveConfigRootName(simpleClassName, "", ConfigPhase.BUILD_TIME); - assertEquals("quarkus.root-name", actual); - - simpleClassName = "RootNameConfiguration"; - actual = deriveConfigRootName(simpleClassName, "", ConfigPhase.BUILD_AND_RUN_TIME_FIXED); - assertEquals("quarkus.root-name", actual); - - // should hyphenate class name after removing RunTimeConfig(uration) suffix - simpleClassName = "RootNameRunTimeConfig"; - actual = deriveConfigRootName(simpleClassName, "", ConfigPhase.RUN_TIME); - assertEquals("quarkus.root-name", actual); - - simpleClassName = "RootNameRuntimeConfig"; - actual = deriveConfigRootName(simpleClassName, "", ConfigPhase.RUN_TIME); - assertEquals("quarkus.root-name", actual); - - simpleClassName = "RootNameRunTimeConfiguration"; - actual = deriveConfigRootName(simpleClassName, "", ConfigPhase.RUN_TIME); - assertEquals("quarkus.root-name", actual); - - // should hyphenate class name after removing BuildTimeConfig(uration) suffix - simpleClassName = "RootNameBuildTimeConfig"; - actual = deriveConfigRootName(simpleClassName, "", ConfigPhase.BUILD_AND_RUN_TIME_FIXED); - assertEquals("quarkus.root-name", actual); - - simpleClassName = "RootNameBuildTimeConfiguration"; - actual = deriveConfigRootName(simpleClassName, "", ConfigPhase.BUILD_TIME); - assertEquals("quarkus.root-name", actual); - - simpleClassName = "RootName"; - actual = deriveConfigRootName(simpleClassName, "prefix", ConfigPhase.RUN_TIME); - assertEquals("prefix.root-name", actual); - - simpleClassName = "RootName"; - actual = deriveConfigRootName(simpleClassName, "my.prefix", ConfigPhase.RUN_TIME); - assertEquals("my.prefix.root-name", actual); - } - - @Test - public void normalizeDurationValueTest() { - assertEquals("", normalizeDurationValue("")); - assertEquals("1S", normalizeDurationValue("1")); - assertEquals("1S", normalizeDurationValue("1S")); - assertEquals("1S", normalizeDurationValue("1s")); - - // values are not validated here - assertEquals("1_000", normalizeDurationValue("1_000")); - assertEquals("FOO", normalizeDurationValue("foo")); - } -} diff --git a/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/JavaDocConfigSectionParserTest.java b/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/JavaDocConfigSectionParserTest.java deleted file mode 100644 index bae3690f84962a..00000000000000 --- a/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/JavaDocConfigSectionParserTest.java +++ /dev/null @@ -1,150 +0,0 @@ -package io.quarkus.annotation.processor.generate_doc; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -public class JavaDocConfigSectionParserTest { - - private JavaDocParser parser; - - @BeforeEach - public void setup() { - parser = new JavaDocParser(); - } - - @Test - public void parseNullSection() { - JavaDocParser.SectionHolder parsed = parser.parseConfigSection(null, 1); - assertEquals("", parsed.details); - assertEquals("", parsed.title); - } - - @Test - public void parseUntrimmedJavaDoc() { - JavaDocParser.SectionHolder parsed = parser.parseConfigSection(" ", 1); - assertEquals("", parsed.details); - assertEquals("", parsed.title); - - parsed = parser.parseConfigSection("

", 1); - assertEquals("", parsed.details); - assertEquals("", parsed.title); - } - - @Test - public void passThroughAConfigSectionInAsciiDoc() { - String asciidoc = "=== My Asciidoc\n" + - "\n" + - ".Let's have a https://quarkus.io[link to our website].\n" + - "\n" + - "[TIP]\n" + - "====\n" + - "A nice tip\n" + - "====\n" + - "\n" + - "[source,java]\n" + - "----\n" + - "And some code\n" + - "----"; - - JavaDocParser.SectionHolder sectionHolder = parser.parseConfigSection(asciidoc + "\n" + "@asciidoclet", 1); - assertEquals(asciidoc, sectionHolder.details); - assertEquals("My Asciidoc", sectionHolder.title); - - asciidoc = "Asciidoc title. \n" + - "\n" + - "Let's have a https://quarkus.io[link to our website].\n" + - "\n" + - "[TIP]\n" + - "====\n" + - "A nice tip\n" + - "====\n" + - "\n" + - "[source,java]\n" + - "----\n" + - "And some code\n" + - "----"; - - sectionHolder = parser.parseConfigSection(asciidoc + "\n" + "@asciidoclet", 1); - assertEquals("Asciidoc title", sectionHolder.title); - } - - @Test - public void parseSectionWithoutIntroduction() { - /** - * Simple javadoc - */ - String javaDoc = "Config Section"; - String expectedTitle = "Config Section"; - String expectedDetails = "== Config Section"; - JavaDocParser.SectionHolder sectionHolder = parser.parseConfigSection(javaDoc, 1); - assertEquals(expectedDetails, sectionHolder.details); - assertEquals(expectedTitle, sectionHolder.title); - - javaDoc = "Config Section."; - expectedTitle = "Config Section"; - expectedDetails = "== Config Section"; - assertEquals(expectedDetails, parser.parseConfigSection(javaDoc, 1).details); - assertEquals(expectedTitle, sectionHolder.title); - - /** - * html javadoc - */ - javaDoc = "

Config Section

"; - expectedTitle = "Config Section"; - expectedDetails = "== Config Section"; - assertEquals(expectedDetails, parser.parseConfigSection(javaDoc, 1).details); - assertEquals(expectedTitle, sectionHolder.title); - } - - @Test - public void parseSectionWithIntroduction() { - /** - * Simple javadoc - */ - String javaDoc = "Config Section .Introduction"; - String expectedDetails = "== Config Section\n\nIntroduction"; - String expectedTitle = "Config Section"; - assertEquals(expectedTitle, parser.parseConfigSection(javaDoc, 1).title); - assertEquals(expectedDetails, parser.parseConfigSection(javaDoc, 1).details); - - /** - * html javadoc - */ - javaDoc = "

Config Section

. Introduction"; - expectedDetails = "== Config Section\n\nIntroduction"; - assertEquals(expectedDetails, parser.parseConfigSection(javaDoc, 1).details); - assertEquals(expectedTitle, parser.parseConfigSection(javaDoc, 1).title); - } - - @Test - public void properlyParseConfigSectionWrittenInHtml() { - String javaDoc = "

Config Section.

This is section introduction"; - String expectedDetails = "== Config Section\n\nThis is section introduction"; - String title = "Config Section"; - assertEquals(expectedDetails, parser.parseConfigSection(javaDoc, 1).details); - assertEquals(title, parser.parseConfigSection(javaDoc, 1).title); - } - - @Test - public void handleSectionLevelCorrectly() { - String javaDoc = "

Config Section.

This is section introduction"; - - // level 0 should default to 1 - String expectedDetails = "= Config Section\n\nThis is section introduction"; - assertEquals(expectedDetails, parser.parseConfigSection(javaDoc, 0).details); - - // level 1 - expectedDetails = "== Config Section\n\nThis is section introduction"; - assertEquals(expectedDetails, parser.parseConfigSection(javaDoc, 1).details); - - // level 2 - expectedDetails = "=== Config Section\n\nThis is section introduction"; - assertEquals(expectedDetails, parser.parseConfigSection(javaDoc, 2).details); - - // level 3 - expectedDetails = "==== Config Section\n\nThis is section introduction"; - assertEquals(expectedDetails, parser.parseConfigSection(javaDoc, 3).details); - } -}