From 84e93d317f064f5f4398f6ccd80991e8454d376a Mon Sep 17 00:00:00 2001 From: azerr Date: Fri, 24 Jan 2020 20:23:19 +0100 Subject: [PATCH] Value from Java enum are not correct Fixes #198 Signed-off-by: azerr --- .../META-INF/MANIFEST.MF | 3 +- .../metadata/ConfigurationMetadata.java | 11 +- .../commons/metadata/ConverterKind.java | 78 +++++++ .../commons/metadata/ItemHint.java | 50 +++- .../commons/metadata/ItemMetadata.java | 12 + .../jdt/core/AbstractPropertiesProvider.java | 23 +- .../jdt/core/utils/JDTTypeUtils.java | 19 +- .../MicroProfileConfigPropertyProvider.java | 4 +- .../io/quarkus/runtime/util/StringUtil.java | 220 ++++++++++++++++++ .../jdt/internal/quarkus/JDTQuarkusUtils.java | 21 ++ .../QuarkusConfigPropertiesProvider.java | 18 +- .../providers/QuarkusConfigRootProvider.java | 11 +- .../providers/QuarkusKubernetesProvider.java | 4 +- .../GenerateAllPropertiesAndDefinition.java | 4 +- .../metadata/ConfigurationMetadata.java | 11 +- .../commons/metadata/ConverterKind.java | 78 +++++++ .../commons/metadata/ItemHint.java | 50 +++- .../commons/metadata/ItemMetadata.java | 12 + .../services/MicroProfileCodeActions.java | 70 +++--- .../services/MicroProfileCompletions.java | 18 +- .../services/MicroProfileDefinition.java | 20 +- .../services/MicroProfileHover.java | 18 +- .../io/quarkus/runtime/util/StringUtil.java | 37 +++ .../ApplicationPropertiesCodeActionsTest.java | 174 ++++++-------- .../ApplicationPropertiesCompletionTest.java | 31 ++- .../ApplicationPropertiesDefinitionTest.java | 9 + .../ApplicationPropertiesDiagnosticsTest.java | 92 +++++++- .../ApplicationPropertiesHoverTest.java | 10 +- .../services/MicroProfileAssert.java | 111 +++++---- .../services/all-quarkus-properties.json | 126 +++++++++- 30 files changed, 1094 insertions(+), 251 deletions(-) create mode 100644 microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/metadata/ConverterKind.java create mode 100644 microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/io/quarkus/runtime/util/StringUtil.java create mode 100644 microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/metadata/ConverterKind.java rename {microprofile.jdt/com.redhat.microprofile.jdt.quarkus => microprofile.ls/com.redhat.microprofile.ls}/src/main/java/io/quarkus/runtime/util/StringUtil.java (82%) diff --git a/microprofile.jdt/com.redhat.microprofile.jdt.core/META-INF/MANIFEST.MF b/microprofile.jdt/com.redhat.microprofile.jdt.core/META-INF/MANIFEST.MF index f854256d7..4478d7dd5 100644 --- a/microprofile.jdt/com.redhat.microprofile.jdt.core/META-INF/MANIFEST.MF +++ b/microprofile.jdt/com.redhat.microprofile.jdt.core/META-INF/MANIFEST.MF @@ -21,4 +21,5 @@ Bundle-ActivationPolicy: lazy Export-Package: com.redhat.microprofile.commons, com.redhat.microprofile.commons.metadata, com.redhat.microprofile.jdt.core, - com.redhat.microprofile.jdt.core.utils + com.redhat.microprofile.jdt.core.utils, + io.quarkus.runtime.util diff --git a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/metadata/ConfigurationMetadata.java b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/metadata/ConfigurationMetadata.java index 07a20b64a..fae649b40 100644 --- a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/metadata/ConfigurationMetadata.java +++ b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/metadata/ConfigurationMetadata.java @@ -72,12 +72,21 @@ public ItemHint getHint(String... hint) { return null; } + /** + * Returns true if the given value is a valid enumeration for the + * given metadata and false otherwise. + * + * @param metadata the property. + * @param value the value to check. + * @return true if the given value is a valid enumeration for the + * given metadata and false otherwise. + */ public boolean isValidEnum(ItemMetadata metadata, String value) { ItemHint itemHint = getHint(metadata); if (itemHint == null) { return true; } - return itemHint.getValue(value) != null; + return itemHint.getValue(value, metadata.getConverterKinds()) != null; } } diff --git a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/metadata/ConverterKind.java b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/metadata/ConverterKind.java new file mode 100644 index 000000000..75adcb02a --- /dev/null +++ b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/metadata/ConverterKind.java @@ -0,0 +1,78 @@ +/******************************************************************************* +* Copyright (c) 2019 Red Hat Inc. and others. +* All rights reserved. This program and the accompanying materials +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v20.html +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package com.redhat.microprofile.commons.metadata; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import io.quarkus.runtime.util.StringUtil; + +/** + * Converter kind. + * + * @author Angelo ZERR + * + */ +public enum ConverterKind { + + KEBAB_CASE(1), VERBATIM(2); + + private final int value; + + ConverterKind(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public static ConverterKind forValue(int value) { + ConverterKind[] allValues = ConverterKind.values(); + if (value < 1 || value > allValues.length) + throw new IllegalArgumentException("Illegal enum value: " + value); + return allValues[value - 1]; + } + + private static final String HYPHEN = "-"; + private static final Pattern PATTERN = Pattern.compile("([-_]+)"); + + public static String convert(String value, ConverterKind converterKind) { + if (converterKind == null || value == null) { + return value; + } + + switch (converterKind) { + case KEBAB_CASE: + return hyphenate(value); + default: + return value; + } + + } + + /** + * Convert the given value to kebab case. + * + * @param value + * @return + * @see https://github.com/quarkusio/quarkus/blob/1457e12766d46507674f8e8d8391fc5a5e8f0103/core/runtime/src/main/java/io/quarkus/runtime/configuration/HyphenateEnumConverter.java#L54 + */ + private static String hyphenate(String value) { + StringBuffer target = new StringBuffer(); + String hyphenate = StringUtil.hyphenate(value); + Matcher matcher = PATTERN.matcher(hyphenate); + while (matcher.find()) { + matcher.appendReplacement(target, HYPHEN); + } + matcher.appendTail(target); + return target.toString(); + } +} diff --git a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/metadata/ItemHint.java b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/metadata/ItemHint.java index f1c58ff65..3ed2281b4 100644 --- a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/metadata/ItemHint.java +++ b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/metadata/ItemHint.java @@ -41,10 +41,39 @@ public static class ValueHint { private String sourceType; + /** + * Returns the value. + * + * @return the value. + */ public String getValue() { return value; } + /** + * Returns the converted value by using the given converter. + * + * @param converterKind the converter + * @return the converted value by using the given converter. + */ + public String getValue(ConverterKind converterKind) { + return ConverterKind.convert(getValue(), converterKind); + } + + /** + * Returns the preferred value according the given converters. + * + * @param converterKinds supported converters and null otherwise. + * + * @return the preferred value according the given converters. + */ + public String getPreferredValue(List converterKinds) { + ConverterKind preferredConverter = converterKinds != null && !converterKinds.isEmpty() + ? converterKinds.get(0) + : null; + return getValue(preferredConverter); + } + public void setValue(String value) { this.value = value; } @@ -101,17 +130,32 @@ public boolean equals(Object obj) { return false; return true; } - } - public ValueHint getValue(String value) { + /** + * Returns the value hint from the given value and supported + * converters converterKinds and null otherwise. + * + * @param value the value + * @param converterKinds the supported converters. + * @return the value hint from the given value and supported + * converters converterKinds and null otherwise. + */ + public ValueHint getValue(String value, List converterKinds) { if (values == null || value == null) { return null; } for (ValueHint valueHint : values) { - if (value.equals(valueHint.getValue())) { + if (converterKinds != null) { + for (ConverterKind converterKind : converterKinds) { + if (value.equals(valueHint.getValue(converterKind))) { + return valueHint; + } + } + } else if (value.equals(valueHint.getValue())) { return valueHint; } + } return null; } diff --git a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/metadata/ItemMetadata.java b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/metadata/ItemMetadata.java index 9135bca96..60323e87a 100644 --- a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/metadata/ItemMetadata.java +++ b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/commons/metadata/ItemMetadata.java @@ -9,6 +9,8 @@ *******************************************************************************/ package com.redhat.microprofile.commons.metadata; +import java.util.List; + /** * Configuration item metadata. * @@ -47,6 +49,8 @@ public class ItemMetadata extends ItemBase { private boolean required; private int phase; + private List converterKinds; + public String getType() { return type; } @@ -103,6 +107,14 @@ public void setPhase(int phase) { this.phase = phase; } + public List getConverterKinds() { + return converterKinds; + } + + public void setConverterKinds(List converterKinds) { + this.converterKinds = converterKinds; + } + public boolean isAvailableAtRun() { return phase == CONFIG_PHASE_BUILD_AND_RUN_TIME_FIXED || phase == CONFIG_PHASE_RUN_TIME; } diff --git a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/core/AbstractPropertiesProvider.java b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/core/AbstractPropertiesProvider.java index 9b300dd4a..129864b02 100644 --- a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/core/AbstractPropertiesProvider.java +++ b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/core/AbstractPropertiesProvider.java @@ -9,12 +9,10 @@ *******************************************************************************/ package com.redhat.microprofile.jdt.core; -import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.findType; -import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.getOptionalTypeParameter; +import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.getPropertyType; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IJavaElement; -import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.search.IJavaSearchConstants; @@ -147,26 +145,13 @@ protected ItemMetadata addItemMetadata(IPropertiesCollector collector, String na * @return the hint name. * @throws JavaModelException */ - protected String updateHint(IPropertiesCollector collector, IType type, String typeName, IJavaProject javaProject) - throws JavaModelException { - // type name is the string of the JDT type (which could be null if type is not - // retrieved) - String enclosedType = typeName; + protected String updateHint(IPropertiesCollector collector, IType type) throws JavaModelException { if (type == null) { - // JDT type is null, in some case it's because type is optional (ex : - // java.util.Optional) - // try to extract the enclosed type from the optional type (to get 'MyType' ) - enclosedType = getOptionalTypeParameter(typeName); - if (enclosedType != null) { - type = findType(javaProject, enclosedType); - } - if (type == null) { - return null; - } + return null; } if (type.isEnum()) { // Register Enumeration in "hints" section - String hint = enclosedType; + String hint = getPropertyType(type, null); if (!collector.hasItemHint(hint)) { ItemHint itemHint = collector.getItemHint(hint); itemHint.setSourceType(hint); diff --git a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/core/utils/JDTTypeUtils.java b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/core/utils/JDTTypeUtils.java index ab85f7c03..89eff67d2 100644 --- a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/core/utils/JDTTypeUtils.java +++ b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/core/utils/JDTTypeUtils.java @@ -97,7 +97,7 @@ public static String getPropertyType(IType type, String typeName) { } public static String getSourceType(IMember member) { - return member.getDeclaringType().getFullyQualifiedName('.'); + return getPropertyType(member.getDeclaringType(), null); } public static String getSourceField(IField field) { @@ -133,6 +133,23 @@ public static String getOptionalTypeParameter(String typeName) { return typeName.substring(start + 1, end); } + public static IType getEnclosedType(IType type, String typeName, IJavaProject javaProject) + throws JavaModelException { + // type name is the string of the JDT type (which could be null if type is not + // retrieved) + String enclosedType = typeName; + if (type == null) { + // JDT type is null, in some case it's because type is optional (ex : + // java.util.Optional) + // try to extract the enclosed type from the optional type (to get 'MyType' ) + enclosedType = getOptionalTypeParameter(typeName); + if (enclosedType != null) { + type = findType(javaProject, enclosedType); + } + } + return type; + } + public static String[] getRawTypeParameters(String fieldTypeName) { int start = fieldTypeName.indexOf("<") + 1; int end = fieldTypeName.lastIndexOf(">"); diff --git a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/internal/core/providers/MicroProfileConfigPropertyProvider.java b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/internal/core/providers/MicroProfileConfigPropertyProvider.java index 20b98bbda..3e161fdfa 100644 --- a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/internal/core/providers/MicroProfileConfigPropertyProvider.java +++ b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/com/redhat/microprofile/jdt/internal/core/providers/MicroProfileConfigPropertyProvider.java @@ -11,6 +11,7 @@ import static com.redhat.microprofile.jdt.core.utils.AnnotationUtils.getAnnotationMemberValue; import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.findType; +import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.getEnclosedType; import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.getPropertyType; import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.getResolvedTypeName; import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.getSourceField; @@ -66,7 +67,8 @@ protected void processAnnotation(IJavaElement javaElement, IAnnotation configPro String extensionName = null; // Enumerations - super.updateHint(collector, fieldClass, type, field.getJavaProject()); + IType enclosedType = getEnclosedType(fieldClass, type, field.getJavaProject()); + super.updateHint(collector, enclosedType); addItemMetadata(collector, name, type, description, sourceType, sourceField, null, defaultValue, extensionName, field.isBinary()); diff --git a/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/io/quarkus/runtime/util/StringUtil.java b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/io/quarkus/runtime/util/StringUtil.java new file mode 100644 index 000000000..30ec7b9f6 --- /dev/null +++ b/microprofile.jdt/com.redhat.microprofile.jdt.core/src/main/java/io/quarkus/runtime/util/StringUtil.java @@ -0,0 +1,220 @@ +package io.quarkus.runtime.util; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.NoSuchElementException; +import java.util.Objects; + +/** + */ +public final class StringUtil { + private StringUtil() { + } + + public static Iterator camelHumpsIterator(String str) { + return new Iterator() { + int idx; + + public boolean hasNext() { + return idx < str.length(); + } + + 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); + } + } + }; + } + + public static Iterator lowerCase(Iterator orig) { + return new Iterator() { + public boolean hasNext() { + return orig.hasNext(); + } + + public String next() { + return orig.next().toLowerCase(Locale.ROOT); + } + }; + } + + /** + * @deprecated Use {@link String#join} instead. + * @param delim delimiter + * @param it iterator + * @return the joined string + */ + @Deprecated + public static String join(String delim, Iterator it) { + final StringBuilder b = new StringBuilder(); + if (it.hasNext()) { + b.append(it.next()); + while (it.hasNext()) { + b.append(delim); + b.append(it.next()); + } + } + return b.toString(); + } + + public static String join(Iterator it) { + final StringBuilder b = new StringBuilder(); + if (it.hasNext()) { + b.append(it.next()); + while (it.hasNext()) { + b.append(it.next()); + } + } + return b.toString(); + } + + public static Iterator lowerCaseFirst(Iterator orig) { + return new Iterator() { + boolean first = true; + + public boolean hasNext() { + return orig.hasNext(); + } + + public String next() { + final String next = orig.next(); + if (first) { + first = false; + return next.toLowerCase(Locale.ROOT); + } else { + return next; + } + } + }; + } + + public static Iterator withoutSuffix(Iterator orig, String... suffixes) { + return new Iterator() { + String next = null; + + public boolean hasNext() { + if (next == null) { + if (!orig.hasNext()) + return false; + final String next = orig.next(); + if (!orig.hasNext() && arrayContains(next, suffixes)) { + return false; + } + this.next = next; + } + return true; + } + + public String next() { + if (!hasNext()) + throw new NoSuchElementException(); + final String next = this.next; + this.next = null; + return next; + } + }; + } + + @SafeVarargs + public static List withoutSuffix(List list, T... segments) { + if (list.size() < segments.length) { + return list; + } + for (int i = 0; i < segments.length; i++) { + if (!list.get(list.size() - i - 1).equals(segments[segments.length - i - 1])) { + return list; + } + } + return list.subList(0, list.size() - segments.length); + } + + public static List toList(Iterator orig) { + return toList(orig, 0); + } + + private static List toList(Iterator orig, int idx) { + if (orig.hasNext()) { + final String item = orig.next(); + final List list = toList(orig, idx + 1); + list.set(idx, item); + return list; + } else { + return Arrays.asList(new String[idx]); + } + } + + @SafeVarargs + private static boolean arrayContains(final T item, final T... array) { + for (T arrayItem : array) { + if (Objects.equals(arrayItem, item)) + return true; + } + return false; + } + + public static String hyphenate(String orig) { + return join("-", lowerCase(camelHumpsIterator(orig))); + } + +} \ No newline at end of file diff --git a/microprofile.jdt/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/JDTQuarkusUtils.java b/microprofile.jdt/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/JDTQuarkusUtils.java index 5f3d93299..eb3da4db8 100644 --- a/microprofile.jdt/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/JDTQuarkusUtils.java +++ b/microprofile.jdt/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/JDTQuarkusUtils.java @@ -9,6 +9,16 @@ *******************************************************************************/ package com.redhat.microprofile.jdt.internal.quarkus; +import java.util.Arrays; +import java.util.List; + +import org.eclipse.jdt.core.IMember; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaModelException; + +import com.redhat.microprofile.commons.metadata.ConverterKind; +import com.redhat.microprofile.commons.metadata.ItemMetadata; + /** * JDT Quarkus utilities. * @@ -17,6 +27,9 @@ */ public class JDTQuarkusUtils { + private static final List DEFAULT_QUARKUS_CONVERTERS = Arrays.asList(ConverterKind.KEBAB_CASE, + ConverterKind.VERBATIM); + /** * Returns the extension name (ex: quarkus-core) from the given JAR location (ex * : @@ -51,4 +64,12 @@ public static String getExtensionName(String location) { return extensionName; } + public static void updateConverterKinds(ItemMetadata metadata, IMember member, IType enclosedType) + throws JavaModelException { + if (enclosedType == null || !enclosedType.isEnum()) { + return; + } + // By default Quarkus set the enum values as kebab and verbatim + metadata.setConverterKinds(DEFAULT_QUARKUS_CONVERTERS); + } } diff --git a/microprofile.jdt/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/providers/QuarkusConfigPropertiesProvider.java b/microprofile.jdt/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/providers/QuarkusConfigPropertiesProvider.java index 89a563b88..2c05fba67 100644 --- a/microprofile.jdt/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/providers/QuarkusConfigPropertiesProvider.java +++ b/microprofile.jdt/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/providers/QuarkusConfigPropertiesProvider.java @@ -12,6 +12,7 @@ import static com.redhat.microprofile.jdt.core.utils.AnnotationUtils.getAnnotation; import static com.redhat.microprofile.jdt.core.utils.AnnotationUtils.getAnnotationMemberValue; import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.findType; +import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.getEnclosedType; import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.getPropertyType; import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.getResolvedResultTypeName; import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.getResolvedTypeName; @@ -43,6 +44,7 @@ import org.eclipse.jdt.core.ITypeHierarchy; import org.eclipse.jdt.core.JavaModelException; +import com.redhat.microprofile.commons.metadata.ItemMetadata; import com.redhat.microprofile.jdt.core.AbstractAnnotationTypeReferencePropertiesProvider; import com.redhat.microprofile.jdt.core.IPropertiesCollector; import com.redhat.microprofile.jdt.core.MicroProfileConstants; @@ -156,11 +158,13 @@ private void processConfigProperties(IJavaElement javaElement, IAnnotation confi String sourceMethod = getSourceMethod(method); // Enumerations - super.updateHint(collector, returnType, methodResultTypeName, method.getJavaProject()); + IType enclosedType = getEnclosedType(returnType, methodResultTypeName, method.getJavaProject()); + super.updateHint(collector, enclosedType); if (isSimpleFieldType(returnType, methodResultTypeName)) { - super.addItemMetadata(collector, propertyName, type, description, sourceType, null, - sourceMethod, defaultValue, extensionName, method.isBinary()); + ItemMetadata metadata = super.addItemMetadata(collector, propertyName, type, description, + sourceType, null, sourceMethod, defaultValue, extensionName, method.isBinary()); + JDTQuarkusUtils.updateConverterKinds(metadata, method, enclosedType); } else { populateConfigObject(returnType, propertyName, extensionName, new HashSet<>(), collector, monitor); @@ -238,10 +242,12 @@ private void populateConfigObject(IType configPropertiesType, String prefixStr, String sourceField = getSourceField(field); // Enumerations - super.updateHint(collector, fieldClass, type, field.getJavaProject()); + IType enclosedType = getEnclosedType(fieldClass, type, field.getJavaProject()); + super.updateHint(collector, enclosedType); - super.addItemMetadata(collector, propertyName, type, description, sourceType, sourceField, null, - defaultValue, extensionName, field.isBinary()); + ItemMetadata metadata = super.addItemMetadata(collector, propertyName, type, description, + sourceType, sourceField, null, defaultValue, extensionName, field.isBinary()); + JDTQuarkusUtils.updateConverterKinds(metadata, field, enclosedType); } else { populateConfigObject(fieldClass, propertyName, extensionName, typesAlreadyProcessed, collector, monitor); diff --git a/microprofile.jdt/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/providers/QuarkusConfigRootProvider.java b/microprofile.jdt/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/providers/QuarkusConfigRootProvider.java index 69350c425..22e14ce0e 100644 --- a/microprofile.jdt/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/providers/QuarkusConfigRootProvider.java +++ b/microprofile.jdt/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/providers/QuarkusConfigRootProvider.java @@ -12,6 +12,7 @@ import static com.redhat.microprofile.jdt.core.utils.AnnotationUtils.getAnnotation; import static com.redhat.microprofile.jdt.core.utils.AnnotationUtils.getAnnotationMemberValue; import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.findType; +import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.getEnclosedType; import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.getPropertyType; import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.getResolvedTypeName; import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.getSourceField; @@ -428,7 +429,8 @@ private void addItemMetadata(String extensionName, IField field, String fieldTyp String sourceField = getSourceField(field); // Enumerations - super.updateHint(collector, fieldClass, fieldTypeName, field.getJavaProject()); + IType enclosedType = getEnclosedType(fieldClass, type, field.getJavaProject()); + super.updateHint(collector, enclosedType); ItemMetadata item = null; // Default value for primitive type @@ -467,12 +469,7 @@ private void addItemMetadata(String extensionName, IField field, String fieldTyp if (item != null) { item.setPhase(getPhase(configPhase)); } - } - - private static String getOptionalParameter(String fieldTypeName) { - int start = fieldTypeName.indexOf("<") + 1; - int end = fieldTypeName.lastIndexOf(">"); - return fieldTypeName.substring(start, end); + JDTQuarkusUtils.updateConverterKinds(item, field, enclosedType); } private static String[] getRawTypeParameters(String fieldTypeName) { diff --git a/microprofile.jdt/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/providers/QuarkusKubernetesProvider.java b/microprofile.jdt/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/providers/QuarkusKubernetesProvider.java index f7a97de07..30a50295a 100644 --- a/microprofile.jdt/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/providers/QuarkusKubernetesProvider.java +++ b/microprofile.jdt/com.redhat.microprofile.jdt.quarkus/src/main/java/com/redhat/microprofile/jdt/internal/quarkus/providers/QuarkusKubernetesProvider.java @@ -11,6 +11,7 @@ import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.findType; import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.getDefaultValue; +import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.getEnclosedType; import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.getPropertyType; import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.getResolvedResultTypeName; import static com.redhat.microprofile.jdt.core.utils.JDTTypeUtils.getSourceMethod; @@ -135,7 +136,8 @@ private void collectProperties(String prefix, IType configType, IPropertiesColle String extensionName = null; // Enumerations - super.updateHint(collector, resultTypeClass, resultTypeName, method.getJavaProject()); + IType enclosedType = getEnclosedType(resultTypeClass, resultTypeName, method.getJavaProject()); + super.updateHint(collector, enclosedType); super.addItemMetadata(collector, propertyName, type, description, sourceType, null, sourceMethod, defaultValue, extensionName, method.isBinary()); diff --git a/microprofile.jdt/com.redhat.microprofile.jdt.test/src/main/java/com/redhat/microprofile/jdt/core/GenerateAllPropertiesAndDefinition.java b/microprofile.jdt/com.redhat.microprofile.jdt.test/src/main/java/com/redhat/microprofile/jdt/core/GenerateAllPropertiesAndDefinition.java index c5700a23a..3101e41b4 100644 --- a/microprofile.jdt/com.redhat.microprofile.jdt.test/src/main/java/com/redhat/microprofile/jdt/core/GenerateAllPropertiesAndDefinition.java +++ b/microprofile.jdt/com.redhat.microprofile.jdt.test/src/main/java/com/redhat/microprofile/jdt/core/GenerateAllPropertiesAndDefinition.java @@ -27,6 +27,7 @@ import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; import org.eclipse.lsp4j.ClientCapabilities; import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.jsonrpc.json.adapters.EnumTypeAdapter; import org.junit.Ignore; import org.junit.Test; @@ -156,7 +157,8 @@ public void generateAllQuarkusExtensionPropertiesAndDefinitions() private void generateJsonFiles(MavenProjectName mavenProject, IJDTUtils utils, boolean generateDefinition) throws JavaModelException, CoreException, Exception { - Gson gson = new GsonBuilder().setPrettyPrinting().create(); + Gson gson = new GsonBuilder().registerTypeAdapterFactory(new EnumTypeAdapter.Factory()).setPrettyPrinting() + .create(); long start = System.currentTimeMillis(); LOGGER.info("Start generating all-quarkus-properties.json"); diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/metadata/ConfigurationMetadata.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/metadata/ConfigurationMetadata.java index 07a20b64a..fae649b40 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/metadata/ConfigurationMetadata.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/metadata/ConfigurationMetadata.java @@ -72,12 +72,21 @@ public ItemHint getHint(String... hint) { return null; } + /** + * Returns true if the given value is a valid enumeration for the + * given metadata and false otherwise. + * + * @param metadata the property. + * @param value the value to check. + * @return true if the given value is a valid enumeration for the + * given metadata and false otherwise. + */ public boolean isValidEnum(ItemMetadata metadata, String value) { ItemHint itemHint = getHint(metadata); if (itemHint == null) { return true; } - return itemHint.getValue(value) != null; + return itemHint.getValue(value, metadata.getConverterKinds()) != null; } } diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/metadata/ConverterKind.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/metadata/ConverterKind.java new file mode 100644 index 000000000..75adcb02a --- /dev/null +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/metadata/ConverterKind.java @@ -0,0 +1,78 @@ +/******************************************************************************* +* Copyright (c) 2019 Red Hat Inc. and others. +* All rights reserved. This program and the accompanying materials +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v20.html +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package com.redhat.microprofile.commons.metadata; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import io.quarkus.runtime.util.StringUtil; + +/** + * Converter kind. + * + * @author Angelo ZERR + * + */ +public enum ConverterKind { + + KEBAB_CASE(1), VERBATIM(2); + + private final int value; + + ConverterKind(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public static ConverterKind forValue(int value) { + ConverterKind[] allValues = ConverterKind.values(); + if (value < 1 || value > allValues.length) + throw new IllegalArgumentException("Illegal enum value: " + value); + return allValues[value - 1]; + } + + private static final String HYPHEN = "-"; + private static final Pattern PATTERN = Pattern.compile("([-_]+)"); + + public static String convert(String value, ConverterKind converterKind) { + if (converterKind == null || value == null) { + return value; + } + + switch (converterKind) { + case KEBAB_CASE: + return hyphenate(value); + default: + return value; + } + + } + + /** + * Convert the given value to kebab case. + * + * @param value + * @return + * @see https://github.com/quarkusio/quarkus/blob/1457e12766d46507674f8e8d8391fc5a5e8f0103/core/runtime/src/main/java/io/quarkus/runtime/configuration/HyphenateEnumConverter.java#L54 + */ + private static String hyphenate(String value) { + StringBuffer target = new StringBuffer(); + String hyphenate = StringUtil.hyphenate(value); + Matcher matcher = PATTERN.matcher(hyphenate); + while (matcher.find()) { + matcher.appendReplacement(target, HYPHEN); + } + matcher.appendTail(target); + return target.toString(); + } +} diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/metadata/ItemHint.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/metadata/ItemHint.java index f1c58ff65..3ed2281b4 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/metadata/ItemHint.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/metadata/ItemHint.java @@ -41,10 +41,39 @@ public static class ValueHint { private String sourceType; + /** + * Returns the value. + * + * @return the value. + */ public String getValue() { return value; } + /** + * Returns the converted value by using the given converter. + * + * @param converterKind the converter + * @return the converted value by using the given converter. + */ + public String getValue(ConverterKind converterKind) { + return ConverterKind.convert(getValue(), converterKind); + } + + /** + * Returns the preferred value according the given converters. + * + * @param converterKinds supported converters and null otherwise. + * + * @return the preferred value according the given converters. + */ + public String getPreferredValue(List converterKinds) { + ConverterKind preferredConverter = converterKinds != null && !converterKinds.isEmpty() + ? converterKinds.get(0) + : null; + return getValue(preferredConverter); + } + public void setValue(String value) { this.value = value; } @@ -101,17 +130,32 @@ public boolean equals(Object obj) { return false; return true; } - } - public ValueHint getValue(String value) { + /** + * Returns the value hint from the given value and supported + * converters converterKinds and null otherwise. + * + * @param value the value + * @param converterKinds the supported converters. + * @return the value hint from the given value and supported + * converters converterKinds and null otherwise. + */ + public ValueHint getValue(String value, List converterKinds) { if (values == null || value == null) { return null; } for (ValueHint valueHint : values) { - if (value.equals(valueHint.getValue())) { + if (converterKinds != null) { + for (ConverterKind converterKind : converterKinds) { + if (value.equals(valueHint.getValue(converterKind))) { + return valueHint; + } + } + } else if (value.equals(valueHint.getValue())) { return valueHint; } + } return null; } diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/metadata/ItemMetadata.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/metadata/ItemMetadata.java index 9135bca96..60323e87a 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/metadata/ItemMetadata.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/commons/metadata/ItemMetadata.java @@ -9,6 +9,8 @@ *******************************************************************************/ package com.redhat.microprofile.commons.metadata; +import java.util.List; + /** * Configuration item metadata. * @@ -47,6 +49,8 @@ public class ItemMetadata extends ItemBase { private boolean required; private int phase; + private List converterKinds; + public String getType() { return type; } @@ -103,6 +107,14 @@ public void setPhase(int phase) { this.phase = phase; } + public List getConverterKinds() { + return converterKinds; + } + + public void setConverterKinds(List converterKinds) { + this.converterKinds = converterKinds; + } + public boolean isAvailableAtRun() { return phase == CONFIG_PHASE_BUILD_AND_RUN_TIME_FIXED || phase == CONFIG_PHASE_RUN_TIME; } diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileCodeActions.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileCodeActions.java index cee1d2b39..e232d4e77 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileCodeActions.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileCodeActions.java @@ -17,7 +17,16 @@ import java.util.logging.Logger; import java.util.stream.Collectors; +import org.eclipse.lsp4j.CodeAction; +import org.eclipse.lsp4j.CodeActionContext; +import org.eclipse.lsp4j.CodeActionKind; +import org.eclipse.lsp4j.Command; +import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; + import com.redhat.microprofile.commons.MicroProfileProjectInfo; +import com.redhat.microprofile.commons.metadata.ConverterKind; import com.redhat.microprofile.commons.metadata.ItemHint.ValueHint; import com.redhat.microprofile.commons.metadata.ItemMetadata; import com.redhat.microprofile.ls.commons.BadLocationException; @@ -37,14 +46,6 @@ import com.redhat.microprofile.utils.PositionUtils; import com.redhat.microprofile.utils.StringUtils; -import org.eclipse.lsp4j.CodeAction; -import org.eclipse.lsp4j.CodeActionContext; -import org.eclipse.lsp4j.CodeActionKind; -import org.eclipse.lsp4j.Command; -import org.eclipse.lsp4j.Diagnostic; -import org.eclipse.lsp4j.Position; -import org.eclipse.lsp4j.Range; - /** * The Quarkus code actions * @@ -169,10 +170,23 @@ private void doCodeActionsForUnknownEnumValue(Diagnostic diagnostic, PropertiesM return; } - Collection similarEnums = new ArrayList<>(); + List converterKinds = metaProperty.getConverterKinds(); + Collection similarEnums = new ArrayList<>(); for (ValueHint e : enums) { - if (isSimilarPropertyValue(e.getValue(), value)) { - similarEnums.add(e); + if (converterKinds != null && !converterKinds.isEmpty()) { + // The metadata property has converters, loop for each converte and check for + // each converted value if it could be a similar value. + for (ConverterKind converterKind : converterKinds) { + String convertedValue = e.getValue(converterKind); + if (isSimilarPropertyValue(convertedValue, value)) { + similarEnums.add(convertedValue); + } + } + } else { + // No converter, check if the value if the value hint could be a similar value. + if (isSimilarPropertyValue(e.getValue(), value)) { + similarEnums.add(e.getValue()); + } } } @@ -180,16 +194,17 @@ private void doCodeActionsForUnknownEnumValue(Diagnostic diagnostic, PropertiesM if (!similarEnums.isEmpty()) { // add code actions for all similar enums - for (ValueHint e : similarEnums) { - CodeAction replaceAction = CodeActionFactory.replace("Did you mean '" + e.getValue() + "'?", range, - e.getValue(), document.getDocument(), diagnostic); + for (String similarValue : similarEnums) { + CodeAction replaceAction = CodeActionFactory.replace("Did you mean '" + similarValue + "'?", range, + similarValue, document.getDocument(), diagnostic); codeActions.add(replaceAction); } } else { // add code actions for all enums for (ValueHint e : enums) { - CodeAction replaceAction = CodeActionFactory.replace("Replace with '" + e.getValue() + "'?", range, - e.getValue(), document.getDocument(), diagnostic); + String preferredValue = e.getPreferredValue(converterKinds); + CodeAction replaceAction = CodeActionFactory.replace("Replace with '" + preferredValue + "'?", + range, preferredValue, document.getDocument(), diagnostic); codeActions.add(replaceAction); } } @@ -224,17 +239,18 @@ private void doCodeActionForIgnoreUnknownValidation(String propertyName, Diagnos } /** - * Returns a code action for diagnostic that causes item to - * be added to quarkus.tools.validation.unknown.excluded client configuration + * Returns a code action for diagnostic that causes + * item to be added to + * quarkus.tools.validation.unknown.excluded client configuration * * @param item the item to add to the client configuration array * @param diagnostic the diagnostic for the CodeAction * @return a code action that causes item to be added to - * quarkus.tools.validation.unknown.excluded client configuration + * quarkus.tools.validation.unknown.excluded client + * configuration */ private CodeAction createAddToExcludedCodeAction(String item, Diagnostic diagnostic) { - CodeAction insertCodeAction = new CodeAction( - "Exclude '" + item + "' from unknown property validation?"); + CodeAction insertCodeAction = new CodeAction("Exclude '" + item + "' from unknown property validation?"); ConfigurationItemEdit configItemEdit = new ConfigurationItemEdit("quarkus.tools.validation.unknown.excluded", ConfigurationItemEditType.add, item); @@ -299,15 +315,12 @@ private void doCodeActionForAllRequired(List diagnostics, Properties } /** - * Returns true if propertyName has a parent - * key, false otherwise + * Returns true if propertyName has a parent key, false otherwise * - * For example, the parent key for "quarkus.http.cors" is - * "quarkus.http" + * For example, the parent key for "quarkus.http.cors" is "quarkus.http" * * @param propertyName the property name to check - * @return true if propertyName has a parent - * key, false otherwise + * @return true if propertyName has a parent key, false otherwise */ private boolean hasParentKey(String propertyName) { return propertyName.lastIndexOf('.') >= 0; @@ -316,8 +329,7 @@ private boolean hasParentKey(String propertyName) { /** * Returns the parent key for propertyName * - * For example, the parent key for "quarkus.http.cors" is - * "quarkus.http" + * For example, the parent key for "quarkus.http.cors" is "quarkus.http" * * @param propertyName the property name * @return the parent key for propertyName diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileCompletions.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileCompletions.java index b428fe619..976640569 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileCompletions.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileCompletions.java @@ -11,6 +11,7 @@ import java.util.Collection; import java.util.HashSet; +import java.util.List; import java.util.Objects; import java.util.Set; import java.util.function.Predicate; @@ -29,6 +30,7 @@ import org.eclipse.lsp4j.jsonrpc.CancelChecker; import com.redhat.microprofile.commons.MicroProfileProjectInfo; +import com.redhat.microprofile.commons.metadata.ConverterKind; import com.redhat.microprofile.commons.metadata.ItemHint.ValueHint; import com.redhat.microprofile.commons.metadata.ItemMetadata; import com.redhat.microprofile.ls.commons.BadLocationException; @@ -209,7 +211,9 @@ private static void collectPropertyKeySuggestions(int offset, Node node, Propert if (snippetsSupported) { // Because of LSP limitation, we cannot use default value with choice. SnippetsBuilder.choice(formattedProperty.getParameterCount() + 1, - enums.stream().map(ValueHint::getValue).collect(Collectors.toList()), insertText); + enums.stream().map(valueHint -> valueHint.getPreferredValue(property.getConverterKinds())) + .collect(Collectors.toList()), + insertText); } else { // Plaintext: use default value or the first enum if no default value. String defaultEnumValue = defaultValue != null ? defaultValue : enums.iterator().next().getValue(); @@ -317,7 +321,8 @@ private static void collectPropertyValueSuggestions(Node node, PropertiesModel m if (enums != null && !enums.isEmpty()) { boolean markdownSupported = completionSettings.isDocumentationFormatSupported(MarkupKind.MARKDOWN); for (ValueHint e : enums) { - list.getItems().add(getValueCompletionItem(e, node, model, markdownSupported)); + list.getItems() + .add(getValueCompletionItem(e, item.getConverterKinds(), node, model, markdownSupported)); } } } @@ -327,6 +332,8 @@ private static void collectPropertyValueSuggestions(Node node, PropertiesModel m * Returns the CompletionItem which offers completion for value * completion for value at the start offset of node. * + * @param converterKinds + * * @param value the value for completion * @param docs the documentation for completion * @param node the node where its start offset is where value @@ -335,9 +342,9 @@ private static void collectPropertyValueSuggestions(Node node, PropertiesModel m * @param markdownSupported true if markdown is supported and false otherwise. * @return the value completion item */ - private static CompletionItem getValueCompletionItem(ValueHint item, Node node, PropertiesModel model, - boolean markdownSupported) { - String value = item.getValue(); + private static CompletionItem getValueCompletionItem(ValueHint item, List converterKinds, Node node, + PropertiesModel model, boolean markdownSupported) { + String value = item.getPreferredValue(converterKinds); CompletionItem completionItem = new CompletionItem(value); completionItem.setKind(CompletionItemKind.Value); @@ -357,4 +364,5 @@ private static CompletionItem getValueCompletionItem(ValueHint item, Node node, return completionItem; } + } \ No newline at end of file diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileDefinition.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileDefinition.java index a902f06fb..f73cc69cc 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileDefinition.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileDefinition.java @@ -22,6 +22,8 @@ import com.redhat.microprofile.commons.MicroProfileProjectInfo; import com.redhat.microprofile.commons.MicroProfilePropertyDefinitionParams; +import com.redhat.microprofile.commons.metadata.ItemHint; +import com.redhat.microprofile.commons.metadata.ItemHint.ValueHint; import com.redhat.microprofile.commons.metadata.ItemMetadata; import com.redhat.microprofile.ls.api.MicroProfilePropertyDefinitionProvider; import com.redhat.microprofile.ls.commons.BadLocationException; @@ -82,7 +84,8 @@ public CompletableFuture, List, List> ge } private static MicroProfilePropertyDefinitionParams getPropertyDefinitionParams(PropertiesModel document, - ItemMetadata item, Node node) { + ItemMetadata item, MicroProfileProjectInfo projectInfo, Node node) { if (node.getNodeType() != NodeType.PROPERTY_KEY && node.getNodeType() != NodeType.PROPERTY_VALUE) { return null; @@ -132,7 +135,18 @@ private static MicroProfilePropertyDefinitionParams getPropertyDefinitionParams( } case PROPERTY_VALUE: { sourceType = item.getHintType(); - sourceField = ((PropertyValue) node).getValue().toUpperCase(); + sourceField = ((PropertyValue) node).getValue(); + // for the case of property which uses kebab_case, we must get the real value of + // the Java enumeration + // Ex: for quarkus.datasource.transaction-isolation-level = read-uncommitted + // the real value of Java enumeration 'read-uncommitted' is 'READ_UNCOMMITTED' + ItemHint itemHint = projectInfo.getHint(sourceType); + if (itemHint != null) { + ValueHint realValue = itemHint.getValue(sourceField, item.getConverterKinds()); + if (realValue != null) { + sourceField = realValue.getValue(); + } + } break; } default: diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileHover.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileHover.java index 055c068d3..9bcbec1b7 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileHover.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/com/redhat/microprofile/services/MicroProfileHover.java @@ -12,6 +12,12 @@ import java.util.logging.Level; import java.util.logging.Logger; +import org.eclipse.lsp4j.Hover; +import org.eclipse.lsp4j.MarkupContent; +import org.eclipse.lsp4j.MarkupKind; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; + import com.redhat.microprofile.commons.MicroProfileProjectInfo; import com.redhat.microprofile.commons.metadata.ConfigurationMetadata; import com.redhat.microprofile.commons.metadata.ItemHint; @@ -29,12 +35,6 @@ import com.redhat.microprofile.utils.MicroProfilePropertiesUtils; import com.redhat.microprofile.utils.PositionUtils; -import org.eclipse.lsp4j.Hover; -import org.eclipse.lsp4j.MarkupContent; -import org.eclipse.lsp4j.MarkupKind; -import org.eclipse.lsp4j.Position; -import org.eclipse.lsp4j.Range; - /** * Retrieves hover documentation and creating Hover object */ @@ -203,12 +203,12 @@ private static ValueHint getValueHint(String propertyValue, ItemMetadata metadat return null; } ItemHint enumItem = configuration.getHint(metadata); - if (enumItem != null) { - ValueHint valueHint = enumItem .getValue(propertyValue); + if (enumItem != null) { + ValueHint valueHint = enumItem.getValue(propertyValue, metadata.getConverterKinds()); if (valueHint != null) { return valueHint; } - } + } return valuesRulesManager.getValueHint(propertyValue, metadata, model); } } \ No newline at end of file diff --git a/microprofile.jdt/com.redhat.microprofile.jdt.quarkus/src/main/java/io/quarkus/runtime/util/StringUtil.java b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/io/quarkus/runtime/util/StringUtil.java similarity index 82% rename from microprofile.jdt/com.redhat.microprofile.jdt.quarkus/src/main/java/io/quarkus/runtime/util/StringUtil.java rename to microprofile.ls/com.redhat.microprofile.ls/src/main/java/io/quarkus/runtime/util/StringUtil.java index 6fc531a42..947aecee4 100644 --- a/microprofile.jdt/com.redhat.microprofile.jdt.quarkus/src/main/java/io/quarkus/runtime/util/StringUtil.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/main/java/io/quarkus/runtime/util/StringUtil.java @@ -1,6 +1,8 @@ package io.quarkus.runtime.util; +import java.util.Arrays; import java.util.Iterator; +import java.util.List; import java.util.Locale; import java.util.NoSuchElementException; import java.util.Objects; @@ -97,6 +99,13 @@ public String next() { }; } + /** + * @deprecated Use {@link String#join} instead. + * @param delim delimiter + * @param it iterator + * @return the joined string + */ + @Deprecated public static String join(String delim, Iterator it) { final StringBuilder b = new StringBuilder(); if (it.hasNext()) { @@ -167,6 +176,34 @@ public String next() { }; } + @SafeVarargs + public static List withoutSuffix(List list, T... segments) { + if (list.size() < segments.length) { + return list; + } + for (int i = 0; i < segments.length; i++) { + if (!list.get(list.size() - i - 1).equals(segments[segments.length - i - 1])) { + return list; + } + } + return list.subList(0, list.size() - segments.length); + } + + public static List toList(Iterator orig) { + return toList(orig, 0); + } + + private static List toList(Iterator orig, int idx) { + if (orig.hasNext()) { + final String item = orig.next(); + final List list = toList(orig, idx + 1); + list.set(idx, item); + return list; + } else { + return Arrays.asList(new String[idx]); + } + } + @SafeVarargs private static boolean arrayContains(final T item, final T... array) { for (T arrayItem : array) { diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesCodeActionsTest.java b/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesCodeActionsTest.java index 85b3d168a..6538f552d 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesCodeActionsTest.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesCodeActionsTest.java @@ -49,8 +49,7 @@ public void codeActionsForUnknownProperties() throws BadLocationException { testDiagnosticsFor(value, d); testCodeActionsFor(value, d, ca("Did you mean 'quarkus.application.name' ?", te(1, 0, 1, 23, "quarkus.application.name"), d), - caAddToExcluded("quarkus.application.nme", d), - caAddToExcluded("quarkus.application.*", d)); + caAddToExcluded("quarkus.application.nme", d), caAddToExcluded("quarkus.application.*", d)); }; @Test @@ -61,7 +60,6 @@ public void codeActionsForUnknownPropertiesParentKey() throws BadLocationExcepti "abcdefghij.labels[0].value=bar\n" + // "abcdefghij.readiness-probe.initial-delay-seconds=20\n" + // "abcdefghij.readiness-probe.period-seconds=45"; - Diagnostic d1 = d(0, 0, 16, "Unknown property 'abcdefghij.group'", DiagnosticSeverity.Warning, ValidationType.unknown); @@ -71,39 +69,27 @@ public void codeActionsForUnknownPropertiesParentKey() throws BadLocationExcepti ValidationType.unknown); Diagnostic d4 = d(3, 0, 26, "Unknown property 'abcdefghij.labels[0].value'", DiagnosticSeverity.Warning, ValidationType.unknown); - Diagnostic d5 = d(4, 0, 48, "Unknown property 'abcdefghij.readiness-probe.initial-delay-seconds'", DiagnosticSeverity.Warning, - ValidationType.unknown); - Diagnostic d6 = d(5, 0, 41, "Unknown property 'abcdefghij.readiness-probe.period-seconds'", DiagnosticSeverity.Warning, - ValidationType.unknown); + Diagnostic d5 = d(4, 0, 48, "Unknown property 'abcdefghij.readiness-probe.initial-delay-seconds'", + DiagnosticSeverity.Warning, ValidationType.unknown); + Diagnostic d6 = d(5, 0, 41, "Unknown property 'abcdefghij.readiness-probe.period-seconds'", + DiagnosticSeverity.Warning, ValidationType.unknown); testDiagnosticsFor(value, d1, d2, d3, d4, d5, d6); - testCodeActionsFor(value, d1, - caAddToExcluded("abcdefghij.group", d1), - caAddToExcluded("abcdefghij.*", d1)); - - testCodeActionsFor(value, d2, - caAddToExcluded("abcdefghij.registry", d2), - caAddToExcluded("abcdefghij.*", d2)); - - testCodeActionsFor(value, d3, - caAddToExcluded("abcdefghij.labels[0].key", d3), - caAddToExcluded("abcdefghij.labels[0].*", d3), - caAddToExcluded("abcdefghij.*", d3)); - - testCodeActionsFor(value, d4, - caAddToExcluded("abcdefghij.labels[0].value", d4), - caAddToExcluded("abcdefghij.labels[0].*", d4), - caAddToExcluded("abcdefghij.*", d4)); - - testCodeActionsFor(value, d5, - caAddToExcluded("abcdefghij.readiness-probe.initial-delay-seconds", d5), - caAddToExcluded("abcdefghij.readiness-probe.*", d5), - caAddToExcluded("abcdefghij.*", d5)); - - testCodeActionsFor(value, d6, - caAddToExcluded("abcdefghij.readiness-probe.period-seconds", d6), - caAddToExcluded("abcdefghij.readiness-probe.*", d6), - caAddToExcluded("abcdefghij.*", d6)); + testCodeActionsFor(value, d1, caAddToExcluded("abcdefghij.group", d1), caAddToExcluded("abcdefghij.*", d1)); + + testCodeActionsFor(value, d2, caAddToExcluded("abcdefghij.registry", d2), caAddToExcluded("abcdefghij.*", d2)); + + testCodeActionsFor(value, d3, caAddToExcluded("abcdefghij.labels[0].key", d3), + caAddToExcluded("abcdefghij.labels[0].*", d3), caAddToExcluded("abcdefghij.*", d3)); + + testCodeActionsFor(value, d4, caAddToExcluded("abcdefghij.labels[0].value", d4), + caAddToExcluded("abcdefghij.labels[0].*", d4), caAddToExcluded("abcdefghij.*", d4)); + + testCodeActionsFor(value, d5, caAddToExcluded("abcdefghij.readiness-probe.initial-delay-seconds", d5), + caAddToExcluded("abcdefghij.readiness-probe.*", d5), caAddToExcluded("abcdefghij.*", d5)); + + testCodeActionsFor(value, d6, caAddToExcluded("abcdefghij.readiness-probe.period-seconds", d6), + caAddToExcluded("abcdefghij.readiness-probe.*", d6), caAddToExcluded("abcdefghij.*", d6)); }; @Test @@ -112,22 +98,15 @@ public void codeActionsForUnknownPropertiesParentKey2() throws BadLocationExcept String value = "a.b.c.d=123\n" + // "a.c.d=123"; - Diagnostic d1 = d(0, 0, 7, "Unknown property 'a.b.c.d'", DiagnosticSeverity.Warning, - ValidationType.unknown); - Diagnostic d2 = d(1, 0, 5, "Unknown property 'a.c.d'", DiagnosticSeverity.Warning, - ValidationType.unknown); - + Diagnostic d1 = d(0, 0, 7, "Unknown property 'a.b.c.d'", DiagnosticSeverity.Warning, ValidationType.unknown); + Diagnostic d2 = d(1, 0, 5, "Unknown property 'a.c.d'", DiagnosticSeverity.Warning, ValidationType.unknown); + testDiagnosticsFor(value, d1, d2); - testCodeActionsFor(value, d1, - caAddToExcluded("a.b.c.d", d1), - caAddToExcluded("a.b.c.*", d1), - caAddToExcluded("a.b.*", d1), - caAddToExcluded("a.*", d1)); - - testCodeActionsFor(value, d2, - caAddToExcluded("a.c.d", d2), - caAddToExcluded("a.c.*", d2), + testCodeActionsFor(value, d1, caAddToExcluded("a.b.c.d", d1), caAddToExcluded("a.b.c.*", d1), + caAddToExcluded("a.b.*", d1), caAddToExcluded("a.*", d1)); + + testCodeActionsFor(value, d2, caAddToExcluded("a.c.d", d2), caAddToExcluded("a.c.*", d2), caAddToExcluded("a.*", d2)); }; @@ -138,54 +117,46 @@ public void codeActionsForUnknownPropertiesParentKey3() throws BadLocationExcept Diagnostic d = d(0, 0, 15, "Unknown property 'quarkus.a.b.c.d'", DiagnosticSeverity.Warning, ValidationType.unknown); - + testDiagnosticsFor(value, d); - testCodeActionsFor(value, d, - caAddToExcluded("quarkus.a.b.c.d", d), - caAddToExcluded("quarkus.a.b.c.*", d), - caAddToExcluded("quarkus.a.b.*", d), - caAddToExcluded("quarkus.a.*", d)); + testCodeActionsFor(value, d, caAddToExcluded("quarkus.a.b.c.d", d), caAddToExcluded("quarkus.a.b.c.*", d), + caAddToExcluded("quarkus.a.b.*", d), caAddToExcluded("quarkus.a.*", d)); }; - @Test public void codeActionsForUnknownPropertiesParentKey4() throws BadLocationException { String value = "a.b.c.d=123"; - Diagnostic d1 = d(0, 0, 7, "Unknown property 'a.b.c.d'", DiagnosticSeverity.Warning, - ValidationType.unknown); - + Diagnostic d1 = d(0, 0, 7, "Unknown property 'a.b.c.d'", DiagnosticSeverity.Warning, ValidationType.unknown); + testDiagnosticsFor(value, d1); - testCodeActionsFor(value, d1, - caAddToExcluded("a.b.c.d", d1), - caAddToExcluded("a.b.c.*", d1), - caAddToExcluded("a.b.*", d1), - caAddToExcluded("a.*", d1)); + testCodeActionsFor(value, d1, caAddToExcluded("a.b.c.d", d1), caAddToExcluded("a.b.c.*", d1), + caAddToExcluded("a.b.*", d1), caAddToExcluded("a.*", d1)); }; @Test public void codeActionsForUnknownLogLevelValue() throws BadLocationException { String value = "quarkus.log.level=WARNIN"; - Diagnostic d = d(0, 18, 24, "Invalid enum value: 'WARNIN' is invalid for type java.util.Optional", DiagnosticSeverity.Error, - ValidationType.value); + Diagnostic d = d(0, 18, 24, + "Invalid enum value: 'WARNIN' is invalid for type java.util.Optional", + DiagnosticSeverity.Error, ValidationType.value); testDiagnosticsFor(value, d); - testCodeActionsFor(value, d, - ca("Did you mean 'WARNING'?", te(0, 18, 0, 24, "WARNING"), d)); + testCodeActionsFor(value, d, ca("Did you mean 'WARNING'?", te(0, 18, 0, 24, "WARNING"), d)); }; @Test public void codeActionsForUnknownLogLevelStartsWith() throws BadLocationException { String value = "quarkus.log.level=F"; - Diagnostic d = d(0, 18, 19, "Invalid enum value: 'F' is invalid for type java.util.Optional", DiagnosticSeverity.Error, - ValidationType.value); + Diagnostic d = d(0, 18, 19, + "Invalid enum value: 'F' is invalid for type java.util.Optional", + DiagnosticSeverity.Error, ValidationType.value); testDiagnosticsFor(value, d); - testCodeActionsFor(value, d, - ca("Did you mean 'FINE'?", te(0, 18, 0, 19, "FINE"), d), + testCodeActionsFor(value, d, ca("Did you mean 'FINE'?", te(0, 18, 0, 19, "FINE"), d), ca("Did you mean 'FINER'?", te(0, 18, 0, 19, "FINER"), d), ca("Did you mean 'FINEST'?", te(0, 18, 0, 19, "FINEST"), d)); }; @@ -193,45 +164,52 @@ public void codeActionsForUnknownLogLevelStartsWith() throws BadLocationExceptio @Test public void codeActionsForUnknownLogLevelValueMappedProperty() throws BadLocationException { String value = "quarkus.log.category.\"org.acme\".level=WARNIN"; - Diagnostic d = d(0, 38, 44, "Invalid enum value: 'WARNIN' is invalid for type java.lang.String", DiagnosticSeverity.Error, - ValidationType.value); + Diagnostic d = d(0, 38, 44, "Invalid enum value: 'WARNIN' is invalid for type java.lang.String", + DiagnosticSeverity.Error, ValidationType.value); testDiagnosticsFor(value, d); - testCodeActionsFor(value, d, - ca("Did you mean 'WARNING'?", te(0, 38, 0, 44, "WARNING"), d)); + testCodeActionsFor(value, d, ca("Did you mean 'WARNING'?", te(0, 38, 0, 44, "WARNING"), d)); }; @Test public void codeActionsForUnknownEnum() throws BadLocationException { String value = "quarkus.log.syslog.async.overflow=BLACK"; - Diagnostic d = d(0, 34, 39, "Invalid enum value: 'BLACK' is invalid for type org.jboss.logmanager.handlers.AsyncHandler.OverflowAction", DiagnosticSeverity.Error, - ValidationType.value); + Diagnostic d = d(0, 34, 39, + "Invalid enum value: 'BLACK' is invalid for type org.jboss.logmanager.handlers.AsyncHandler.OverflowAction", + DiagnosticSeverity.Error, ValidationType.value); testDiagnosticsFor(value, d); - testCodeActionsFor(value, d, - ca("Did you mean 'BLOCK'?", te(0, 34, 0, 39, "BLOCK"), d)); + testCodeActionsFor(value, d, ca("Did you mean 'BLOCK'?", te(0, 34, 0, 39, "BLOCK"), d)); }; @Test public void codeActionsForUnknownEnumStartsWith() throws BadLocationException { + // verbatim String value = "quarkus.log.syslog.async.overflow=B"; - Diagnostic d = d(0, 34, 35, "Invalid enum value: 'B' is invalid for type org.jboss.logmanager.handlers.AsyncHandler.OverflowAction", DiagnosticSeverity.Error, - ValidationType.value); + Diagnostic d = d(0, 34, 35, + "Invalid enum value: 'B' is invalid for type org.jboss.logmanager.handlers.AsyncHandler.OverflowAction", + DiagnosticSeverity.Error, ValidationType.value); testDiagnosticsFor(value, d); - testCodeActionsFor(value, d, - ca("Did you mean 'BLOCK'?", te(0, 34, 0, 35, "BLOCK"), d)); + testCodeActionsFor(value, d, ca("Did you mean 'BLOCK'?", te(0, 34, 0, 35, "BLOCK"), d)); + + // kebab_case + value = "quarkus.log.syslog.async.overflow=b"; + d = d(0, 34, 35, + "Invalid enum value: 'b' is invalid for type org.jboss.logmanager.handlers.AsyncHandler.OverflowAction", + DiagnosticSeverity.Error, ValidationType.value); + + testDiagnosticsFor(value, d); + testCodeActionsFor(value, d, ca("Did you mean 'block'?", te(0, 34, 0, 35, "block"), d)); }; @Test public void codeActionsForUnknownBoolean() throws BadLocationException { String value = "quarkus.http.cors=fals"; - Diagnostic d = d(0, 18, 22, "Type mismatch: boolean expected", DiagnosticSeverity.Error, - ValidationType.value); + Diagnostic d = d(0, 18, 22, "Type mismatch: boolean expected", DiagnosticSeverity.Error, ValidationType.value); testDiagnosticsFor(value, d); - testCodeActionsFor(value, d, - ca("Did you mean 'false'?", te(0, 18, 0, 22, "false"), d)); + testCodeActionsFor(value, d, ca("Did you mean 'false'?", te(0, 18, 0, 22, "false"), d)); }; @Test @@ -239,32 +217,32 @@ public void codeActionsForReplaceUnknown() throws BadLocationException { String value = "quarkus.log.syslog.async.overflow=unknown-value"; Diagnostic d = d(0, 34, 47, "Invalid enum value: 'unknown-value' is invalid for type org.jboss.logmanager.handlers.AsyncHandler.OverflowAction", - DiagnosticSeverity.Error, - ValidationType.value); + DiagnosticSeverity.Error, ValidationType.value); testDiagnosticsFor(value, d); - testCodeActionsFor(value, d, - ca("Replace with 'BLOCK'?", te(0, 34, 0, 47, "BLOCK"), d), - ca("Replace with 'DISCARD'?", te(0, 34, 0, 47, "DISCARD"), d)); - + testCodeActionsFor(value, d, ca("Replace with 'block'?", te(0, 34, 0, 47, "block"), d), + ca("Replace with 'discard'?", te(0, 34, 0, 47, "discard"), d)); + } /** - * Returns a code action for diagnostic that causes item to - * be added to quarkus.tools.validation.unknown.excluded client configuration + * Returns a code action for diagnostic that causes + * item to be added to + * quarkus.tools.validation.unknown.excluded client configuration * * @param item the item to add to the client configuration array * @param diagnostic the diagnostic for the CodeAction * @return a code action that causes item to be added to - * quarkus.tools.validation.unknown.excluded client configuration + * quarkus.tools.validation.unknown.excluded client + * configuration */ private CodeAction caAddToExcluded(String item, Diagnostic diagnostic) { ConfigurationItemEdit configItemEdit = new ConfigurationItemEdit("quarkus.tools.validation.unknown.excluded", ConfigurationItemEditType.add, item); - + Command command = new Command("Add " + item + " to unknown excluded array", CommandKind.COMMAND_CONFIGURATION_UPDATE, Arrays.asList(configItemEdit)); - + return ca("Exclude '" + item + "' from unknown property validation?", command, diagnostic); } } \ No newline at end of file diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesCompletionTest.java b/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesCompletionTest.java index 35642246a..33914bec2 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesCompletionTest.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesCompletionTest.java @@ -18,8 +18,8 @@ import org.junit.Test; -import com.redhat.microprofile.commons.metadata.ItemMetadata; import com.redhat.microprofile.commons.MicroProfileProjectInfo; +import com.redhat.microprofile.commons.metadata.ItemMetadata; import com.redhat.microprofile.ls.commons.BadLocationException; /** @@ -63,7 +63,8 @@ public void completionOnKeyMap() throws BadLocationException { testCompletionFor(value, false, c("quarkus.log.category.{*}.level", "quarkus.log.category.{*}.level=inherit", r(0, 0, 20))); testCompletionFor(value, true, c("quarkus.log.category.{*}.level", - "quarkus.log.category.${1:key}.level=${2|DEBUG,ERROR,OFF,SEVERE,WARNING,INFO,CONFIG,FINE,FINER,FINEST,ALL|}", r(0, 0, 20))); + "quarkus.log.category.${1:key}.level=${2|DEBUG,ERROR,OFF,SEVERE,WARNING,INFO,CONFIG,FINE,FINER,FINEST,ALL|}", + r(0, 0, 20))); } @Test @@ -74,7 +75,8 @@ public void completionOnEmptyLine() throws BadLocationException { testCompletionFor(value, false, c("quarkus.log.category.{*}.level", "quarkus.log.category.{*}.level=inherit", r(1, 0, 0))); testCompletionFor(value, true, c("quarkus.log.category.{*}.level", - "quarkus.log.category.${1:key}.level=${2|DEBUG,ERROR,OFF,SEVERE,WARNING,INFO,CONFIG,FINE,FINER,FINEST,ALL|}", r(1, 0, 0))); + "quarkus.log.category.${1:key}.level=${2|DEBUG,ERROR,OFF,SEVERE,WARNING,INFO,CONFIG,FINE,FINER,FINEST,ALL|}", + r(1, 0, 0))); } @Test @@ -86,19 +88,19 @@ public void completionOnValueNoCompletionItems() throws BadLocationException { @Test public void completionOnValueOnAssign() throws BadLocationException { String value = "quarkus.log.console.async.overflow=| "; - testCompletionFor(value, true, c("BLOCK", "BLOCK", r(0, 35, 36)), c("DISCARD", "DISCARD", r(0, 35, 36))); + testCompletionFor(value, true, c("block", "block", r(0, 35, 36)), c("discard", "discard", r(0, 35, 36))); } @Test public void completionOnValueOnPropertyValue() throws BadLocationException { String value = "quarkus.log.console.async.overflow=BLO| "; - testCompletionFor(value, true, c("BLOCK", "BLOCK", r(0, 35, 39))); + testCompletionFor(value, true, c("block", "block", r(0, 35, 39))); } @Test public void completionOnValueBetweenPropertyValue() throws BadLocationException { String value = "quarkus.log.console.async.overflow=B|L"; - testCompletionFor(value, true, c("BLOCK", "BLOCK", r(0, 35, 37))); + testCompletionFor(value, true, c("block", "block", r(0, 35, 37))); } @Test @@ -108,14 +110,26 @@ public void completionOnKeyWithEnums() throws BadLocationException { testCompletionFor(value, false, c("quarkus.log.console.async.overflow", "quarkus.log.console.async.overflow=block", r(0, 0, 0))); testCompletionFor(value, true, c("quarkus.log.console.async.overflow", - "quarkus.log.console.async.overflow=${1|BLOCK,DISCARD|}", r(0, 0, 0))); + "quarkus.log.console.async.overflow=${1|block,discard|}", r(0, 0, 0))); // Boolean type testCompletionFor(value, false, c("quarkus.datasource.enable-metrics", "quarkus.datasource.enable-metrics=false", r(0, 0, 0))); testCompletionFor(value, true, c("quarkus.datasource.enable-metrics", "quarkus.datasource.enable-metrics=${1|false,true|}", r(0, 0, 0))); + } + @Test + public void completionOnValueWithEnumsKebabCase() throws BadLocationException { + String value = "quarkus.datasource.transaction-isolation-level=|"; + testCompletionFor(value, true, // + c("undefined", "undefined", r(0, 47, 47)), // + c("none", "none", r(0, 47, 47)), // + c("read-uncommitted", "read-uncommitted", r(0, 47, 47)), // + c("read-committed", "read-committed", r(0, 47, 47)), // + c("repeatable-read", "repeatable-read", r(0, 47, 47)), // + c("serializable", "serializable", r(0, 47, 47)) // + ); } @Test @@ -234,7 +248,8 @@ public void completionOnValueForLevelBasedOnRule() throws BadLocationException { public void completionSpacingSurroundingEquals() throws BadLocationException { String value = "|"; testCompletionFor(value, false, true, c("quarkus.http.cors", "quarkus.http.cors = false", r(0, 0, 0))); - testCompletionFor(value, true, true, c("quarkus.http.cors", "quarkus.http.cors = ${1|false,true|}", r(0, 0, 0))); + testCompletionFor(value, true, true, + c("quarkus.http.cors", "quarkus.http.cors = ${1|false,true|}", r(0, 0, 0))); } } diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesDefinitionTest.java b/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesDefinitionTest.java index 5b520528c..648006c71 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesDefinitionTest.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesDefinitionTest.java @@ -60,6 +60,15 @@ public void definitionOnOptionalEnumValue() throws BadLocationException, Interru r(0, 47, 51), r(87, 19, 23))); } + @Test + public void definitionOnOptionalEnumValueKebabCase() + throws BadLocationException, InterruptedException, ExecutionException { + String value = "quarkus.datasource.transaction-isolation-level=read-uncom|mitted"; + testDefinitionFor(value, ll( + "jdt://contents/agroal-api-1.7.jar/io.agroal.api.configuration/AgroalConnectionFactoryConfiguration$TransactionIsolation.class?=all-quarkus-extensions/C:%5C/Users%5C/azerr%5C/.m2%5C/repository%5C/io%5C/agroal%5C/agroal-api%5C/1.7%5C/agroal-api-1.7.jar%3Cio.agroal.api.configuration(AgroalConnectionFactoryConfiguration$TransactionIsolation.class", + r(0, 47, 63), r(87, 25, 41))); + } + @Test public void definitionOnMappedPropertyOptionalEnumValue() throws BadLocationException, InterruptedException, ExecutionException { diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesDiagnosticsTest.java b/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesDiagnosticsTest.java index b715deb36..985d71d0e 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesDiagnosticsTest.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesDiagnosticsTest.java @@ -13,11 +13,18 @@ import static com.redhat.microprofile.services.MicroProfileAssert.getDefaultMicroProfileProjectInfo; import static com.redhat.microprofile.services.MicroProfileAssert.testDiagnosticsFor; +import java.util.ArrayList; +import java.util.Arrays; + import org.eclipse.lsp4j.DiagnosticSeverity; import org.junit.Test; +import com.redhat.microprofile.commons.MicroProfileProjectInfo; +import com.redhat.microprofile.commons.metadata.ConverterKind; +import com.redhat.microprofile.commons.metadata.ItemHint; +import com.redhat.microprofile.commons.metadata.ItemHint.ValueHint; +import com.redhat.microprofile.commons.metadata.ItemMetadata; import com.redhat.microprofile.ls.commons.BadLocationException; -import com.redhat.microprofile.services.ValidationType; import com.redhat.microprofile.settings.MicroProfileValidationSettings; import com.redhat.microprofile.settings.MicroProfileValidationTypeSettings; @@ -420,4 +427,87 @@ public void validateValueForLevelBasedOnRule() throws BadLocationException { DiagnosticSeverity.Error, ValidationType.value)); } + @Test + public void validateValueForTransactionIsolationLevelEnumKebabCase() { + String value = "quarkus.datasource.transaction-isolation-level = READ_UNCOMMITTED"; + MicroProfileValidationSettings settings = new MicroProfileValidationSettings(); + testDiagnosticsFor(value, getDefaultMicroProfileProjectInfo(), settings); + } + + @Test + public void validateValueForTransactionIsolationLevelEnumVerbatim() { + String value = "quarkus.datasource.transaction-isolation-level = read-uncommitted"; + MicroProfileValidationSettings settings = new MicroProfileValidationSettings(); + testDiagnosticsFor(value, getDefaultMicroProfileProjectInfo(), settings); + } + + @Test + public void validateAccordingConverterKinds() { + MicroProfileProjectInfo projectInfo = new MicroProfileProjectInfo(); + projectInfo.setProperties(new ArrayList<>()); + projectInfo.setHints(new ArrayList<>()); + MicroProfileValidationSettings settings = new MicroProfileValidationSettings(); + + ItemMetadata p1 = new ItemMetadata(); + p1.setName("property.converters.none"); + p1.setType("MyEnumType"); + projectInfo.getProperties().add(p1); + + ItemMetadata p2 = new ItemMetadata(); + p2.setName("property.converters.verbatim"); + p2.setConverterKinds(Arrays.asList(ConverterKind.VERBATIM)); + p2.setType("MyEnumType"); + projectInfo.getProperties().add(p2); + + ItemMetadata p3 = new ItemMetadata(); + p3.setName("property.converters.kebab_case"); + p3.setConverterKinds(Arrays.asList(ConverterKind.KEBAB_CASE)); + p3.setType("MyEnumType"); + projectInfo.getProperties().add(p3); + + ItemMetadata p4 = new ItemMetadata(); + p4.setName("property.converters.both"); + p4.setConverterKinds(Arrays.asList(ConverterKind.KEBAB_CASE, ConverterKind.VERBATIM)); + p4.setType("MyEnumType"); + projectInfo.getProperties().add(p4); + + ItemHint hint = new ItemHint(); + hint.setName("MyEnumType"); + hint.setValues(new ArrayList<>()); + ValueHint valueHint = new ValueHint(); + valueHint.setValue("READ_UNCOMMITTED"); + hint.getValues().add(valueHint); + projectInfo.getHints().add(hint); + + // No converter + String value = "property.converters.none = READ_UNCOMMITTED"; + testDiagnosticsFor(value, projectInfo, settings); + value = "property.converters.none = read-uncommitted"; + testDiagnosticsFor(value, projectInfo, settings, // + d(0, 27, 43, "Invalid enum value: 'read-uncommitted' is invalid for type MyEnumType", + DiagnosticSeverity.Error, ValidationType.value)); + + // verbatim converter + value = "property.converters.verbatim = READ_UNCOMMITTED"; + testDiagnosticsFor(value, projectInfo, settings); + value = "property.converters.verbatim = read-uncommitted"; + testDiagnosticsFor(value, projectInfo, settings, // + d(0, 31, 47, "Invalid enum value: 'read-uncommitted' is invalid for type MyEnumType", + DiagnosticSeverity.Error, ValidationType.value)); + + // kebab_case converter + value = "property.converters.kebab_case = read-uncommitted"; + testDiagnosticsFor(value, projectInfo, settings); + value = "property.converters.kebab_case = READ_UNCOMMITTED"; + testDiagnosticsFor(value, projectInfo, settings, // + d(0, 33, 49, "Invalid enum value: 'READ_UNCOMMITTED' is invalid for type MyEnumType", + DiagnosticSeverity.Error, ValidationType.value)); + + // both converters + value = "property.converters.both = read-uncommitted"; + testDiagnosticsFor(value, projectInfo, settings); + value = "property.converters.both = READ_UNCOMMITTED"; + testDiagnosticsFor(value, projectInfo, settings); + + } } diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesHoverTest.java b/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesHoverTest.java index 7ae08ef14..6d4c689a4 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesHoverTest.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/ApplicationPropertiesHoverTest.java @@ -41,8 +41,6 @@ public void testQuarkusKeyHoverMarkdown() throws BadLocationException { " * Extension: `quarkus-core`"; assertHoverMarkdown(value, hoverLabel, 0); }; - - @Test public void testQuarkusKeyHoverPlaintext() throws BadLocationException { @@ -195,4 +193,12 @@ public void hoverOnValueForLevelBasedOnRule() throws BadLocationException { assertHoverMarkdown(value, hoverLabel, 23); } + @Test + public void hoverWithEnumsKebabCase() throws BadLocationException { + String value = "quarkus.datasource.transaction-isolation-level = read-unc|ommitted"; + // io.agroal.api.configuration.AgroalConnectionFactoryConfiguration.TransactionIsolation + // enum type + String hoverLabel = "**READ_UNCOMMITTED**" + System.lineSeparator(); + assertHoverMarkdown(value, hoverLabel, 49); + } } diff --git a/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/MicroProfileAssert.java b/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/MicroProfileAssert.java index 19c509bd5..fe8402675 100644 --- a/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/MicroProfileAssert.java +++ b/microprofile.ls/com.redhat.microprofile.ls/src/test/java/com/redhat/microprofile/services/MicroProfileAssert.java @@ -17,26 +17,6 @@ import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; -import com.google.gson.Gson; -import com.redhat.microprofile.commons.MicroProfileProjectInfo; -import com.redhat.microprofile.ls.MockMicroProfilePropertyDefinitionProvider; -import com.redhat.microprofile.ls.api.MicroProfilePropertyDefinitionProvider; -import com.redhat.microprofile.ls.commons.BadLocationException; -import com.redhat.microprofile.ls.commons.TextDocument; -import com.redhat.microprofile.ls.commons.client.CommandCapabilities; -import com.redhat.microprofile.ls.commons.client.CommandKind; -import com.redhat.microprofile.ls.commons.client.CommandKindCapabilities; -import com.redhat.microprofile.model.PropertiesModel; -import com.redhat.microprofile.services.MicroProfileLanguageService; -import com.redhat.microprofile.services.ValidationType; -import com.redhat.microprofile.settings.MicroProfileCommandCapabilities; -import com.redhat.microprofile.settings.MicroProfileCompletionSettings; -import com.redhat.microprofile.settings.MicroProfileFormattingSettings; -import com.redhat.microprofile.settings.MicroProfileHoverSettings; -import com.redhat.microprofile.settings.MicroProfileValidationSettings; -import com.redhat.microprofile.utils.DocumentationUtils; -import com.redhat.microprofile.utils.PositionUtils; - import org.eclipse.lsp4j.CodeAction; import org.eclipse.lsp4j.CodeActionContext; import org.eclipse.lsp4j.Command; @@ -62,9 +42,29 @@ import org.eclipse.lsp4j.TextEdit; import org.eclipse.lsp4j.VersionedTextDocumentIdentifier; import org.eclipse.lsp4j.WorkspaceEdit; +import org.eclipse.lsp4j.jsonrpc.json.adapters.EnumTypeAdapter; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.junit.Assert; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.redhat.microprofile.commons.MicroProfileProjectInfo; +import com.redhat.microprofile.ls.MockMicroProfilePropertyDefinitionProvider; +import com.redhat.microprofile.ls.api.MicroProfilePropertyDefinitionProvider; +import com.redhat.microprofile.ls.commons.BadLocationException; +import com.redhat.microprofile.ls.commons.TextDocument; +import com.redhat.microprofile.ls.commons.client.CommandCapabilities; +import com.redhat.microprofile.ls.commons.client.CommandKind; +import com.redhat.microprofile.ls.commons.client.CommandKindCapabilities; +import com.redhat.microprofile.model.PropertiesModel; +import com.redhat.microprofile.settings.MicroProfileCommandCapabilities; +import com.redhat.microprofile.settings.MicroProfileCompletionSettings; +import com.redhat.microprofile.settings.MicroProfileFormattingSettings; +import com.redhat.microprofile.settings.MicroProfileHoverSettings; +import com.redhat.microprofile.settings.MicroProfileValidationSettings; +import com.redhat.microprofile.utils.DocumentationUtils; +import com.redhat.microprofile.utils.PositionUtils; + /** * Quarkus assert * @@ -81,13 +81,17 @@ public class MicroProfileAssert { public static MicroProfileProjectInfo getDefaultMicroProfileProjectInfo() { if (DEFAULT_PROJECT == null) { - DEFAULT_PROJECT = new Gson().fromJson( + DEFAULT_PROJECT = createGson().fromJson( new InputStreamReader(MicroProfileAssert.class.getResourceAsStream("all-quarkus-properties.json")), MicroProfileProjectInfo.class); } return DEFAULT_PROJECT; } + private static Gson createGson() { + return new GsonBuilder().registerTypeAdapterFactory(new EnumTypeAdapter.Factory()).create(); + } + public static MicroProfilePropertyDefinitionProvider getDefaultMicroProfilePropertyDefinitionProvider() { if (DEFAULT_DEFINITION_PROVIDER == null) { DEFAULT_DEFINITION_PROVIDER = new MockMicroProfilePropertyDefinitionProvider(); @@ -107,19 +111,21 @@ public static void testCompletionFor(String value, boolean snippetSupport, Compl testCompletionFor(value, snippetSupport, false, null, expectedItems); } - public static void testCompletionFor(String value, boolean snippetSupport, boolean insertSpacing, CompletionItem... expectedItems) - throws BadLocationException { + public static void testCompletionFor(String value, boolean snippetSupport, boolean insertSpacing, + CompletionItem... expectedItems) throws BadLocationException { testCompletionFor(value, snippetSupport, insertSpacing, null, expectedItems); } public static void testCompletionFor(String value, boolean snippetSupport, Integer expectedCount, CompletionItem... expectedItems) throws BadLocationException { - testCompletionFor(value, snippetSupport, false, null, expectedCount, getDefaultMicroProfileProjectInfo(), expectedItems); + testCompletionFor(value, snippetSupport, false, null, expectedCount, getDefaultMicroProfileProjectInfo(), + expectedItems); } public static void testCompletionFor(String value, boolean snippetSupport, boolean insertSpacing, Integer expectedCount, CompletionItem... expectedItems) throws BadLocationException { - testCompletionFor(value, snippetSupport, insertSpacing, null, expectedCount, getDefaultMicroProfileProjectInfo(), expectedItems); + testCompletionFor(value, snippetSupport, insertSpacing, null, expectedCount, + getDefaultMicroProfileProjectInfo(), expectedItems); } public static void testCompletionFor(String value, boolean snippetSupport, String fileURI, Integer expectedCount, @@ -127,9 +133,9 @@ public static void testCompletionFor(String value, boolean snippetSupport, Strin testCompletionFor(value, snippetSupport, false, null, expectedCount, projectInfo, expectedItems); } - public static void testCompletionFor(String value, boolean snippetSupport, boolean insertSpacing, - String fileURI, Integer expectedCount, MicroProfileProjectInfo projectInfo, - CompletionItem... expectedItems) throws BadLocationException { + public static void testCompletionFor(String value, boolean snippetSupport, boolean insertSpacing, String fileURI, + Integer expectedCount, MicroProfileProjectInfo projectInfo, CompletionItem... expectedItems) + throws BadLocationException { int offset = value.indexOf('|'); value = value.substring(0, offset) + value.substring(offset + 1); @@ -147,8 +153,9 @@ public static void testCompletionFor(String value, boolean snippetSupport, boole formattingSettings.setSurroundEqualsWithSpaces(insertSpacing); MicroProfileLanguageService languageService = new MicroProfileLanguageService(); - CompletionList list = languageService.doComplete(model, position, projectInfo, completionSettings, formattingSettings, () -> { - }); + CompletionList list = languageService.doComplete(model, position, projectInfo, completionSettings, + formattingSettings, () -> { + }); assertCompletions(list, expectedCount, expectedItems); } @@ -356,8 +363,8 @@ public static void assertDocumentSymbols(List actual, DocumentSy public static void testDefinitionFor(String value, LocationLink... expected) throws BadLocationException, InterruptedException, ExecutionException { - testDefinitionFor(value, getDefaultMicroProfileProjectInfo(), getDefaultMicroProfilePropertyDefinitionProvider(), - expected); + testDefinitionFor(value, getDefaultMicroProfileProjectInfo(), + getDefaultMicroProfilePropertyDefinitionProvider(), expected); } public static void testDefinitionFor(String value, MicroProfileProjectInfo projectInfo, @@ -411,7 +418,8 @@ public static void testDiagnosticsFor(String value, Integer expectedCount, Micro } public static void testDiagnosticsFor(String value, String fileURI, Integer expectedCount, - MicroProfileProjectInfo projectInfo, MicroProfileValidationSettings validationSettings, Diagnostic... expected) { + MicroProfileProjectInfo projectInfo, MicroProfileValidationSettings validationSettings, + Diagnostic... expected) { PropertiesModel model = parse(value, fileURI); MicroProfileLanguageService languageService = new MicroProfileLanguageService(); List actual = languageService.doDiagnostics(model, projectInfo, validationSettings, () -> { @@ -445,27 +453,30 @@ public static Diagnostic d(int startLine, int startCharacter, int endLine, int e // ------------------- CodeAction assert public static void testCodeActionsFor(String value, Diagnostic diagnostic, CodeAction... expected) { - testCodeActionsFor(value, diagnostic, getDefaultMicroProfileProjectInfo(), new MicroProfileFormattingSettings(), expected); + testCodeActionsFor(value, diagnostic, getDefaultMicroProfileProjectInfo(), new MicroProfileFormattingSettings(), + expected); } public static void testCodeActionsFor(String value, Diagnostic diagnostic, MicroProfileProjectInfo projectInfo, CodeAction... expected) { - testCodeActionsFor(value, Collections.singletonList(diagnostic), diagnostic.getRange(), projectInfo, new MicroProfileFormattingSettings(), - expected); + testCodeActionsFor(value, Collections.singletonList(diagnostic), diagnostic.getRange(), projectInfo, + new MicroProfileFormattingSettings(), expected); } public static void testCodeActionsFor(String value, Diagnostic diagnostic, MicroProfileProjectInfo projectInfo, MicroProfileFormattingSettings formattingSettings, CodeAction... expected) { - testCodeActionsFor(value, Collections.singletonList(diagnostic), diagnostic.getRange(), projectInfo, formattingSettings, expected); + testCodeActionsFor(value, Collections.singletonList(diagnostic), diagnostic.getRange(), projectInfo, + formattingSettings, expected); } - public static void testCodeActionsFor(String value, List diagnostics, Range range, MicroProfileProjectInfo projectInfo, - CodeAction... expected) { + public static void testCodeActionsFor(String value, List diagnostics, Range range, + MicroProfileProjectInfo projectInfo, CodeAction... expected) { testCodeActionsFor(value, diagnostics, range, projectInfo, new MicroProfileFormattingSettings(), expected); } - public static void testCodeActionsFor(String value, List diagnostics, Range range, MicroProfileProjectInfo projectInfo, - MicroProfileFormattingSettings formattingSettings, CodeAction... expected) { + public static void testCodeActionsFor(String value, List diagnostics, Range range, + MicroProfileProjectInfo projectInfo, MicroProfileFormattingSettings formattingSettings, + CodeAction... expected) { PropertiesModel model = parse(value, null); MicroProfileLanguageService languageService = new MicroProfileLanguageService(); @@ -474,15 +485,14 @@ public static void testCodeActionsFor(String value, List diagnostics MicroProfileCommandCapabilities quarkusCommandCapabilities = new MicroProfileCommandCapabilities(); - List valueSet = Arrays.asList(CommandKind.COMMAND_CONFIGURATION_UPDATE); CommandKindCapabilities commandKindCapabilities = new CommandKindCapabilities(valueSet); CommandCapabilities commandCapabilities = new CommandCapabilities(commandKindCapabilities); quarkusCommandCapabilities.setCapabilities(commandCapabilities); - List actual = languageService.doCodeActions(context, range, model, projectInfo, - formattingSettings, quarkusCommandCapabilities); + List actual = languageService.doCodeActions(context, range, model, projectInfo, formattingSettings, + quarkusCommandCapabilities); assertCodeActions(actual, expected); } @@ -527,13 +537,14 @@ public static CodeAction ca(String title, TextEdit te, Command command, List