From f55035d2259c5b86537780250eb915cbd51a6180 Mon Sep 17 00:00:00 2001 From: azerr Date: Wed, 17 Jul 2024 21:16:18 +0200 Subject: [PATCH] feat: Qute: Cannot locate hyphenated template name Fixes https://github.com/redhat-developer/quarkus-ls/issues/975 Signed-off-by: azerr --- .../java/org/acme/sample/ItemResource.java | 36 +++++++++ .../qute/psi/internal/QuteJavaConstants.java | 5 +- .../AbstractQuteTemplateLinkCollector.java | 25 +++---- .../datamodel/CheckedTemplateSupport.java | 74 +++++++++++++++++-- .../datamodel/TemplateFieldSupport.java | 8 +- .../datamodel/TemplateRecordsSupport.java | 3 +- .../qute/psi/utils/PsiQuteProjectUtils.java | 46 ++++++++---- .../qute/psi/utils/TemplateNameStrategy.java | 22 ++++++ .../qute/psi/java/MavenJavaCodeLensTest.java | 32 ++++++++ .../psi/java/MavenJavaDiagnosticsTest.java | 54 ++++++++------ .../psi/java/MavenJavaDocumentLinkTest.java | 28 +++++++ .../TemplateGetDataModelProjectTest.java | 48 ++++++++++-- 12 files changed, 308 insertions(+), 73 deletions(-) create mode 100644 projects/qute/projects/maven/qute-record/src/main/java/org/acme/sample/ItemResource.java create mode 100644 src/main/java/com/redhat/devtools/intellij/qute/psi/utils/TemplateNameStrategy.java diff --git a/projects/qute/projects/maven/qute-record/src/main/java/org/acme/sample/ItemResource.java b/projects/qute/projects/maven/qute-record/src/main/java/org/acme/sample/ItemResource.java new file mode 100644 index 000000000..1853fa5fb --- /dev/null +++ b/projects/qute/projects/maven/qute-record/src/main/java/org/acme/sample/ItemResource.java @@ -0,0 +1,36 @@ +package org.acme.sample; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +import io.quarkus.qute.CheckedTemplate; +import io.quarkus.qute.TemplateExtension; +import io.quarkus.qute.TemplateInstance; + +@Path("items") +public class ItemResource { + + @CheckedTemplate(defaultName=CheckedTemplate.ELEMENT_NAME) + static class Templates { + static native TemplateInstance HelloWorld(String name); + + } + + @CheckedTemplate(defaultName=CheckedTemplate.HYPHENATED_ELEMENT_NAME) + static class Templates2 { + static native TemplateInstance HelloWorld(String name); + + } + + @CheckedTemplate(defaultName=CheckedTemplate.UNDERSCORED_ELEMENT_NAME) + static class Templates3 { + static native TemplateInstance HelloWorld(String name); + } + + +} diff --git a/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/QuteJavaConstants.java b/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/QuteJavaConstants.java index e2a8d5626..da0680a08 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/QuteJavaConstants.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/QuteJavaConstants.java @@ -52,7 +52,10 @@ public class QuteJavaConstants { public static final String CHECKED_TEMPLATE_ANNOTATION_IGNORE_FRAGMENTS = "ignoreFragments"; public static final String CHECKED_TEMPLATE_ANNOTATION_BASE_PATH = "basePath"; - + public static final String CHECKED_TEMPLATE_ANNOTATION_DEFAULT_NAME = "defaultName"; + public static final String CHECKED_TEMPLATE_ANNOTATION_DEFAULT_NAME_HYPHENATED_ELEMENT_NAME = "<>"; + public static final String CHECKED_TEMPLATE_ANNOTATION_DEFAULT_NAME_UNDERSCORED_ELEMENT_NAME = "<>"; + // @TemplateExtension public static final String TEMPLATE_EXTENSION_ANNOTATION = "io.quarkus.qute.TemplateExtension"; diff --git a/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/java/AbstractQuteTemplateLinkCollector.java b/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/java/AbstractQuteTemplateLinkCollector.java index beea521a6..fee4dc31c 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/java/AbstractQuteTemplateLinkCollector.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/java/AbstractQuteTemplateLinkCollector.java @@ -22,13 +22,10 @@ import com.intellij.psi.impl.source.PsiClassReferenceType; import com.intellij.psi.util.PsiTreeUtil; import com.redhat.devtools.intellij.qute.psi.internal.QuteJavaConstants; +import com.redhat.devtools.intellij.qute.psi.utils.*; import com.redhat.devtools.lsp4ij.LSPIJUtils; import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.utils.IPsiUtils; import com.redhat.devtools.intellij.qute.psi.internal.AnnotationLocationSupport; -import com.redhat.devtools.intellij.qute.psi.utils.AnnotationUtils; -import com.redhat.devtools.intellij.qute.psi.utils.PsiQuteProjectUtils; -import com.redhat.devtools.intellij.qute.psi.utils.PsiTypeUtils; -import com.redhat.devtools.intellij.qute.psi.utils.TemplatePathInfo; import org.eclipse.lsp4j.Range; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -40,8 +37,7 @@ import java.util.logging.Logger; import static com.redhat.devtools.intellij.qute.psi.internal.QuteJavaConstants.*; -import static com.redhat.devtools.intellij.qute.psi.internal.template.datamodel.CheckedTemplateSupport.getBasePath; -import static com.redhat.devtools.intellij.qute.psi.internal.template.datamodel.CheckedTemplateSupport.isIgnoreFragments; +import static com.redhat.devtools.intellij.qute.psi.internal.template.datamodel.CheckedTemplateSupport.*; import static com.redhat.devtools.intellij.qute.psi.utils.PsiQuteProjectUtils.*; /** @@ -122,7 +118,7 @@ public void visitField(PsiField node) { .getLocationExpressionFromConstructorParameter(node.getName()); } String fieldName = node.getName(); - collectTemplateLink(null, node, locationExpression, getTypeDeclaration(node), null, fieldName, false); + collectTemplateLink(null, node, locationExpression, getTypeDeclaration(node), null, fieldName, false, TemplateNameStrategy.ELEMENT_NAME); } super.visitField(node); } @@ -172,8 +168,9 @@ private void visitClassType(PsiClass node) { // public static native TemplateInstance book(Book book); boolean ignoreFragments = isIgnoreFragments(annotation); String basePath = getBasePath(annotation); + TemplateNameStrategy templateNameStrategy = getDefaultName(annotation); for (PsiMethod method : node.getMethods()) { - collectTemplateLink(basePath, method, node, ignoreFragments); + collectTemplateLink(basePath, method, node, ignoreFragments, templateNameStrategy); } } } @@ -191,7 +188,7 @@ private void visitClassType(PsiClass node) { private void visitRecordType(PsiClass node) { if (isImplementTemplateInstance(node)) { String recordName = node.getName(); - collectTemplateLink(null, node, null, node, null, recordName, false); + collectTemplateLink(null, node, null, node, null, recordName, false, TemplateNameStrategy.ELEMENT_NAME); } } @@ -219,25 +216,25 @@ private static PsiClass getTypeDeclaration(PsiElement node) { return PsiTreeUtil.getParentOfType(node, PsiClass.class); } - private void collectTemplateLink(String basePath, PsiMethod methodDeclaration, PsiClass type, boolean ignoreFragments) { + private void collectTemplateLink(String basePath, PsiMethod methodDeclaration, PsiClass type, boolean ignoreFragments, TemplateNameStrategy templateNameStrategy) { String className = null; boolean innerClass = levelTypeDecl > 1; if (innerClass) { className = PsiTypeUtils.getSimpleClassName(typeRoot.getName()); } String methodName = methodDeclaration.getName(); - collectTemplateLink(basePath, methodDeclaration, null, type, className, methodName, ignoreFragments); + collectTemplateLink(basePath, methodDeclaration, null, type, className, methodName, ignoreFragments,templateNameStrategy); } private void collectTemplateLink(String basePath, PsiElement fieldOrMethod, PsiLiteralValue locationAnnotation, PsiClass type, String className, - String fieldOrMethodName, boolean ignoreFragment) { + String fieldOrMethodName, boolean ignoreFragment, TemplateNameStrategy templateNameStrategy) { try { String location = locationAnnotation != null && locationAnnotation.getValue() instanceof String ? (String) locationAnnotation.getValue() : null; Module project = utils.getModule(); TemplatePathInfo templatePathInfo = location != null - ? PsiQuteProjectUtils.getTemplatePath(null, basePath, null, location, ignoreFragment) - : PsiQuteProjectUtils.getTemplatePath(null, basePath, className, fieldOrMethodName, ignoreFragment); + ? PsiQuteProjectUtils.getTemplatePath(null, basePath, null, location, ignoreFragment, templateNameStrategy) + : PsiQuteProjectUtils.getTemplatePath(null, basePath, className, fieldOrMethodName, ignoreFragment, templateNameStrategy); String templateUriWithoutBaseDir = templatePathInfo.getTemplateUri(); boolean definedSuffix = location != null; diff --git a/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/CheckedTemplateSupport.java b/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/CheckedTemplateSupport.java index bdebf4732..f9159231f 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/CheckedTemplateSupport.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/CheckedTemplateSupport.java @@ -33,6 +33,7 @@ import com.redhat.devtools.intellij.qute.psi.utils.AnnotationUtils; import com.redhat.devtools.intellij.qute.psi.utils.PsiTypeUtils; +import com.redhat.devtools.intellij.qute.psi.utils.TemplateNameStrategy; import com.redhat.devtools.intellij.qute.psi.utils.TemplatePathInfo; import com.redhat.qute.commons.datamodel.DataModelBaseTemplate; import com.redhat.qute.commons.datamodel.DataModelFragment; @@ -81,7 +82,8 @@ protected void processAnnotation(PsiElement javaElement, PsiAnnotation checkedTe PsiClass type = (PsiClass) javaElement; boolean ignoreFragments = isIgnoreFragments(checkedTemplateAnnotation); String basePath = getBasePath(checkedTemplateAnnotation); - collectDataModelTemplateForCheckedTemplate(type, context.getRelativeTemplateBaseDir(), basePath, ignoreFragments, context.getTypeResolver(type), + TemplateNameStrategy templateNameStrategy = getDefaultName(checkedTemplateAnnotation); + collectDataModelTemplateForCheckedTemplate(type, context.getRelativeTemplateBaseDir(), basePath, ignoreFragments, templateNameStrategy, context.getTypeResolver(type), context.getDataModelProject().getTemplates(), monitor); } } @@ -119,12 +121,11 @@ public static boolean isIgnoreFragments(PsiAnnotation checkedTemplateAnnotation) /** * Returns the basePath value declared in the @CheckedTemplate annotation, relative to the templates root, to search the templates from. - * - * @CheckedTemplate(basePath="somewhere") - * + * * * @param checkedTemplateAnnotation the CheckedTemplate annotation. * @return the basePath value declared in the @CheckedTemplate annotation + * @CheckedTemplate(basePath="somewhere") */ public static String getBasePath(PsiAnnotation checkedTemplateAnnotation) { String basePath = null; @@ -146,6 +147,53 @@ public static String getBasePath(PsiAnnotation checkedTemplateAnnotation) { return basePath; } + /** + * Returns the defaultName value declared in the @CheckedTemplate annotation. + * + * + * @param checkedTemplateAnnotation the CheckedTemplate annotation. + * @return the basePath value declared in the @CheckedTemplate annotation + * @CheckedTemplate(defaultName="somewhere") + */ + public static TemplateNameStrategy getDefaultName(PsiAnnotation checkedTemplateAnnotation) { + TemplateNameStrategy templateNameStrategy = TemplateNameStrategy.ELEMENT_NAME; + try { + for (PsiNameValuePair pair : checkedTemplateAnnotation.getParameterList().getAttributes()) { + if (CHECKED_TEMPLATE_ANNOTATION_DEFAULT_NAME.equalsIgnoreCase(pair.getAttributeName())) { + if (pair.getValue() != null + && pair.getValue().getReference() != null + && pair.getValue().getReference().resolve() != null && + pair.getValue().getReference().resolve() instanceof PsiField field) { + Object value = field.computeConstantValue(); + if (value != null) { + templateNameStrategy = getDefaultName(value.toString()); + } + } + } + } + } catch (ProcessCanceledException e) { + //Since 2024.2 ProcessCanceledException extends CancellationException so we can't use multicatch to keep backward compatibility + //TODO delete block when minimum required version is 2024.2 + throw e; + } catch (IndexNotReadyException | CancellationException e) { + throw e; + } catch (Exception e) { + // Do nothing + } + return templateNameStrategy; + } + + private static TemplateNameStrategy getDefaultName(String defaultName) { + switch (defaultName) { + case CHECKED_TEMPLATE_ANNOTATION_DEFAULT_NAME_HYPHENATED_ELEMENT_NAME: + return TemplateNameStrategy.HYPHENATED_ELEMENT_NAME; + + case CHECKED_TEMPLATE_ANNOTATION_DEFAULT_NAME_UNDERSCORED_ELEMENT_NAME: + return TemplateNameStrategy.UNDERSCORED_ELEMENT_NAME; + } + return TemplateNameStrategy.ELEMENT_NAME; + } + /** * Collect data model template from @CheckedTemplate. * @@ -155,8 +203,14 @@ public static String getBasePath(PsiAnnotation checkedTemplateAnnotation) { * @param templates the data model templates to update with collect of template. * @param monitor the progress monitor. */ - private static void collectDataModelTemplateForCheckedTemplate(PsiClass type, String templatesBaseDir, String basePath, boolean ignoreFragments, ITypeResolver typeResolver, - List> templates, ProgressIndicator monitor) { + private static void collectDataModelTemplateForCheckedTemplate(PsiClass type, + String templatesBaseDir, + String basePath, + boolean ignoreFragments, + TemplateNameStrategy templateNameStrategy, + ITypeResolver typeResolver, + List> templates, + ProgressIndicator monitor) { boolean innerClass = type.getContainingClass() != null; String className = !innerClass ? null : PsiTypeUtils.getSimpleClassName(type.getContainingFile().getName()); @@ -166,7 +220,7 @@ private static void collectDataModelTemplateForCheckedTemplate(PsiClass type, St PsiMethod[] methods = type.getMethods(); for (PsiMethod method : methods) { // src/main/resources/templates/${className}/${methodName}.qute.html - TemplatePathInfo templatePathInfo = getTemplatePath(templatesBaseDir, basePath, className, method.getName(), ignoreFragments); + TemplatePathInfo templatePathInfo = getTemplatePath(templatesBaseDir, basePath, className, method.getName(), ignoreFragments, templateNameStrategy); // Get or create template String templateUri = templatePathInfo.getTemplateUri(); @@ -234,7 +288,11 @@ public static void collectParameters(PsiMethod method, ITypeResolver typeResolve for (int i = 0; i < parameters.getParametersCount(); i++) { DataModelParameter parameter = createParameterDataModel(parameters.getParameter(i), varargs && i == parameters.getParametersCount() - 1, typeResolver); - templateOrFragment.getParameters().add(parameter); + if (templateOrFragment.getParameter(parameter.getKey()) == null) { + // Add parameter if it doesn't exist + // to avoid parameters duplication + templateOrFragment.getParameters().add(parameter); + } } } diff --git a/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/TemplateFieldSupport.java b/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/TemplateFieldSupport.java index dcb3c68e9..1e68d4b48 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/TemplateFieldSupport.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/TemplateFieldSupport.java @@ -37,6 +37,7 @@ import com.redhat.devtools.intellij.qute.psi.template.datamodel.SearchContext; import com.redhat.devtools.intellij.qute.psi.utils.AnnotationUtils; +import com.redhat.devtools.intellij.qute.psi.utils.TemplateNameStrategy; import com.redhat.qute.commons.datamodel.DataModelParameter; import com.redhat.qute.commons.datamodel.DataModelTemplate; @@ -106,7 +107,10 @@ private static AnnotationLocationSupport getAnnotationLocationSupport(PsiFile co } private static void collectDataModelTemplateForTemplateField(PsiField field, - List> templates, String relativeTemplateBaseDir, String location, ProgressIndicator monitor) { + List> templates, + String relativeTemplateBaseDir, + String location, + ProgressIndicator monitor) { DataModelTemplate template = createTemplateDataModel(field, relativeTemplateBaseDir, location, monitor); templates.add(template); } @@ -117,7 +121,7 @@ private static DataModelTemplate createTemplateDataModel(Psi String location = locationFromConstructorParameter != null ? locationFromConstructorParameter : getLocation(field); String fieldName = field.getName(); // src/main/resources/templates/${methodName}.qute.html - String templateUri = getTemplatePath(relativeTemplateBaseDir, null, null, location != null ? location : fieldName, true).getTemplateUri(); + String templateUri = getTemplatePath(relativeTemplateBaseDir, null, null, location != null ? location : fieldName, true, TemplateNameStrategy.ELEMENT_NAME).getTemplateUri(); // Create template data model with: // - template uri : Qute template file which must be bind with data model. diff --git a/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/TemplateRecordsSupport.java b/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/TemplateRecordsSupport.java index 5c405511b..75fdd3c46 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/TemplateRecordsSupport.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/TemplateRecordsSupport.java @@ -18,6 +18,7 @@ import com.redhat.devtools.intellij.qute.psi.template.datamodel.AbstractInterfaceImplementationDataModelProvider; import com.redhat.devtools.intellij.qute.psi.template.datamodel.SearchContext; import com.redhat.devtools.intellij.qute.psi.utils.PsiTypeUtils; +import com.redhat.devtools.intellij.qute.psi.utils.TemplateNameStrategy; import com.redhat.qute.commons.datamodel.DataModelParameter; import com.redhat.qute.commons.datamodel.DataModelTemplate; @@ -81,7 +82,7 @@ private static DataModelTemplate createTemplateDataModel(Psi String recordName = type.getName(); // src/main/resources/templates/${recordName}.qute.html - String templateUri = getTemplatePath(relativeTemplateBaseDir, null, null, recordName, true).getTemplateUri(); + String templateUri = getTemplatePath(relativeTemplateBaseDir, null, null, recordName, true, TemplateNameStrategy.ELEMENT_NAME).getTemplateUri(); // Create template data model with: // - template uri : Qute template file which must be bind with data model. diff --git a/src/main/java/com/redhat/devtools/intellij/qute/psi/utils/PsiQuteProjectUtils.java b/src/main/java/com/redhat/devtools/intellij/qute/psi/utils/PsiQuteProjectUtils.java index c8fc70641..6c3021ca5 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/psi/utils/PsiQuteProjectUtils.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/psi/utils/PsiQuteProjectUtils.java @@ -20,6 +20,7 @@ import com.redhat.devtools.lsp4ij.LSPIJUtils; import com.redhat.devtools.intellij.qute.psi.internal.QuteJavaConstants; import com.redhat.qute.commons.ProjectInfo; +import io.quarkus.runtime.util.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.model.java.JavaResourceRootType; @@ -64,7 +65,6 @@ public static ProjectInfo getProjectInfo(Module javaProject) { * Returns the full path of the Qute templates base dir '$base-dir-of-module/src/main/resources/templates' for the given module. * * @param javaProject the Java module project. - * * @return the full path of the Qute templates base dir '$base-dir-of-module/src/main/resources/templates' for the given module. */ private static String getTemplateBaseDir(Module javaProject) { @@ -77,10 +77,10 @@ private static String getTemplateBaseDir(Module javaProject) { public static @NotNull String getRelativeTemplateBaseDir(Module module) { VirtualFile resourcesDir = findBestResourcesDir(module); - return getRelativeTemplateBaseDir(module, resourcesDir); + return getRelativeTemplateBaseDir(module, resourcesDir); } - public static @NotNull String getRelativeTemplateBaseDir(Module module, @Nullable VirtualFile resourcesDir) { + public static @NotNull String getRelativeTemplateBaseDir(Module module, @Nullable VirtualFile resourcesDir) { String relativeResourcesPath = RESOURCES_BASE_DIR; if (resourcesDir != null) { for (VirtualFile root : ModuleRootManager.getInstance(module).getContentRoots()) { @@ -98,7 +98,6 @@ private static String getTemplateBaseDir(Module javaProject) { * Returns the best 'resources' directory for the given Java module project and null otherwise. * * @param javaProject the Java module project. - * * @return the best resources dir for the given Java module project. */ public static @Nullable VirtualFile findBestResourcesDir(@NotNull Module javaProject) { @@ -163,17 +162,7 @@ public static boolean hasQuteSupport(Module javaProject) { return PsiTypeUtils.findType(javaProject, QuteJavaConstants.ENGINE_BUILDER_CLASS) != null; } - public static String getTemplatePath(String basePath, String className, String methodOrFieldName) { - StringBuilder path = new StringBuilder(); - if (basePath != null && !DEFAULTED.equals(basePath)) { - appendAndSlash(path, basePath); - } else if (className != null) { - appendAndSlash(path, className); - } - return path.append(methodOrFieldName).toString(); - } - - public static TemplatePathInfo getTemplatePath(String templatesBaseDir, String basePath, String className, String methodOrFieldName, boolean ignoreFragments) { + public static TemplatePathInfo getTemplatePath(String templatesBaseDir, String basePath, String className, String methodOrFieldName, boolean ignoreFragments, TemplateNameStrategy templateNameStrategy) { String fragmentId = null; StringBuilder templateUri = new StringBuilder(templatesBaseDir != null ? templatesBaseDir : ""); if (basePath != null && !DEFAULTED.equals(basePath)) { @@ -188,10 +177,35 @@ public static TemplatePathInfo getTemplatePath(String templatesBaseDir, String b methodOrFieldName = methodOrFieldName.substring(0, fragmentIndex); } } - templateUri.append(methodOrFieldName); + templateUri.append(defaultedName(templateNameStrategy, methodOrFieldName)); return new TemplatePathInfo(templateUri.toString(), fragmentId); } + /** + * @param defaultNameStrategy + * @param value + * @return + * @see QuteProcessor#defaultName + */ + private static String defaultedName(TemplateNameStrategy defaultNameStrategy, String value) { + switch (defaultNameStrategy) { + case ELEMENT_NAME: + return value; + case HYPHENATED_ELEMENT_NAME: + return StringUtil.hyphenate(value); + case UNDERSCORED_ELEMENT_NAME: + return String.join("_", new Iterable() { + @Override + public Iterator iterator() { + return StringUtil.lowerCase(StringUtil.camelHumpsIterator(value)); + } + }); + default: + return value; + } + } + /** * Appends a segment to a path, add trailing "/" if necessary * diff --git a/src/main/java/com/redhat/devtools/intellij/qute/psi/utils/TemplateNameStrategy.java b/src/main/java/com/redhat/devtools/intellij/qute/psi/utils/TemplateNameStrategy.java new file mode 100644 index 000000000..736314166 --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/qute/psi/utils/TemplateNameStrategy.java @@ -0,0 +1,22 @@ +/******************************************************************************* +* Copyright (c) 2022 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 +* +* SPDX-License-Identifier: EPL-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package com.redhat.devtools.intellij.qute.psi.utils; + +/** + * Qute template name strategy managed with {@link CheckedTemplate#defaultName}/ + */ +public enum TemplateNameStrategy { + + ELEMENT_NAME, // + HYPHENATED_ELEMENT_NAME, // + UNDERSCORED_ELEMENT_NAME +} diff --git a/src/test/java/com/redhat/devtools/intellij/qute/psi/java/MavenJavaCodeLensTest.java b/src/test/java/com/redhat/devtools/intellij/qute/psi/java/MavenJavaCodeLensTest.java index 5f7d523bb..a985e0b54 100644 --- a/src/test/java/com/redhat/devtools/intellij/qute/psi/java/MavenJavaCodeLensTest.java +++ b/src/test/java/com/redhat/devtools/intellij/qute/psi/java/MavenJavaCodeLensTest.java @@ -374,6 +374,38 @@ public void testTemplateRecord() throws Exception { "qute.command.generate.template.file", Arrays.asList(bonjourFileUri))); } + @Test + public void testCheckedTemplateWithDefaultName() throws Exception { + // @CheckedTemplate(defaultName=CheckedTemplate.HYPHENATED_ELEMENT_NAME) + // static class Templates { + // static native TemplateInstance HelloWorld(String name); + + var module = loadMavenProject(QuteMavenProjectName.qute_record); + + QuteJavaCodeLensParams params = new QuteJavaCodeLensParams(); + String javaFileUri = LSPIJUtils.toUri(module).resolve("src/main/java/org/acme/sample/ItemResource.java").toASCIIString(); + params.setUri(javaFileUri); + + List lenses = QuteSupportForJava.getInstance().codeLens(params, PsiUtilsLSImpl.getInstance(myProject), + new EmptyProgressIndicator()); + assertEquals(3, lenses.size()); + + String helloFileUri = LSPIJUtils.toUri(module).resolve("src/main/resources/templates/ItemResource/HelloWorld.html").toASCIIString(); + String hello2FileUri = LSPIJUtils.toUri(module).resolve("src/main/resources/templates/ItemResource/hello-world.html").toASCIIString(); + String hello3FileUri = LSPIJUtils.toUri(module).resolve("src/main/resources/templates/ItemResource/hello_world.html").toASCIIString(); + + assertCodeLens(lenses, // + cl(r(19, 2, 19, 57), // + "Create `src/main/resources/templates/ItemResource/HelloWorld.html`", // + "qute.command.generate.template.file", Arrays.asList(helloFileUri)), // + cl(r(25, 2, 25, 57), // + "Create `src/main/resources/templates/ItemResource/hello-world.html`", // + "qute.command.generate.template.file", Arrays.asList(hello2FileUri)), // + cl(r(31, 2, 31, 57), // + "Create `src/main/resources/templates/ItemResource/hello_world.html`", // + "qute.command.generate.template.file", Arrays.asList(hello3FileUri))); + } + public static Range r(int line, int startChar, int endChar) { return r(line, startChar, line, endChar); } diff --git a/src/test/java/com/redhat/devtools/intellij/qute/psi/java/MavenJavaDiagnosticsTest.java b/src/test/java/com/redhat/devtools/intellij/qute/psi/java/MavenJavaDiagnosticsTest.java index ed0cb7220..1b6ff7e92 100644 --- a/src/test/java/com/redhat/devtools/intellij/qute/psi/java/MavenJavaDiagnosticsTest.java +++ b/src/test/java/com/redhat/devtools/intellij/qute/psi/java/MavenJavaDiagnosticsTest.java @@ -254,29 +254,6 @@ public void testCheckedTemplateWithCustomBasePath() throws Exception { DiagnosticSeverity.Error, "qute", QuteErrorCode.FragmentNotDefined.name())); } - public void testCheckedTemplateInInnerClassWithCustomBasePath() throws Exception { - - QuteJavaDiagnosticsParams params = new QuteJavaDiagnosticsParams(); - String javaFileUri = LSPIJUtils.toUri(module).resolve("src/main/java/org/acme/qute/ItemResourceWithCustomBasePath.java").toASCIIString(); - params.setUris(Arrays.asList(javaFileUri)); - - List publishDiagnostics = QuteSupportForJava.getInstance().diagnostics(params, - PsiUtilsLSImpl.getInstance(myProject), new EmptyProgressIndicator()); - assertEquals(1, publishDiagnostics.size()); - - List diagnostics = publishDiagnostics.get(0).getDiagnostics(); - assertEquals(2, diagnostics.size()); - - assertDiagnostic(diagnostics, // - new Diagnostic(r(23, 33, 23, 43), - "No template matching the path ItemResourceWithFragment/items3 could be found for: org.acme.qute.ItemResourceWithCustomBasePath$Templates", - DiagnosticSeverity.Error, "qute", QuteErrorCode.NoMatchingTemplate.name()), // - new Diagnostic(r(24, 33, 24, 40), - "Fragment [] not defined in template ItemResourceWithFragment/items3$", - DiagnosticSeverity.Error, "qute", QuteErrorCode.FragmentNotDefined.name()) - ); - } - @Test public void testTemplateRecord() throws Exception { @@ -306,6 +283,37 @@ public void testTemplateRecord() throws Exception { DiagnosticSeverity.Error, "qute", QuteErrorCode.NoMatchingTemplate.name())); } + @Test + public void testCheckedTemplateWithDefaultName() throws Exception { + + // @CheckedTemplate(defaultName=CheckedTemplate.HYPHENATED_ELEMENT_NAME) + // static class Templates { + // static native TemplateInstance HelloWorld(String name); + + var module = loadMavenProject(QuteMavenProjectName.qute_record); + QuteJavaDiagnosticsParams params = new QuteJavaDiagnosticsParams(); + String javaFileUri = LSPIJUtils.toUri(module).resolve("src/main/java/org/acme/sample/ItemResource.java").toASCIIString(); + params.setUris(Arrays.asList(javaFileUri)); + + List publishDiagnostics = QuteSupportForJava.getInstance().diagnostics(params, + PsiUtilsLSImpl.getInstance(myProject), new EmptyProgressIndicator()); + + assertEquals(1, publishDiagnostics.size()); + + List diagnostics = publishDiagnostics.get(0).getDiagnostics(); + assertEquals(3, diagnostics.size()); + + assertDiagnostic(diagnostics, // + new Diagnostic(r(19, 33, 19, 43), + "No template matching the path ItemResource/HelloWorld could be found for: org.acme.sample.ItemResource$Templates", + DiagnosticSeverity.Error, "qute", QuteErrorCode.NoMatchingTemplate.name()), // + new Diagnostic(r(25, 33, 25, 43), + "No template matching the path ItemResource/HelloWorld could be found for: org.acme.sample.ItemResource$Templates2", + DiagnosticSeverity.Error, "qute", QuteErrorCode.NoMatchingTemplate.name()), // + new Diagnostic(r(31, 33, 31, 43), + "No template matching the path ItemResource/HelloWorld could be found for: org.acme.sample.ItemResource$Templates3", + DiagnosticSeverity.Error, "qute", QuteErrorCode.NoMatchingTemplate.name())); + } public static Range r(int line, int startChar, int endChar) { return r(line, startChar, line, endChar); diff --git a/src/test/java/com/redhat/devtools/intellij/qute/psi/java/MavenJavaDocumentLinkTest.java b/src/test/java/com/redhat/devtools/intellij/qute/psi/java/MavenJavaDocumentLinkTest.java index 7a5408cfa..4f7ff9b34 100644 --- a/src/test/java/com/redhat/devtools/intellij/qute/psi/java/MavenJavaDocumentLinkTest.java +++ b/src/test/java/com/redhat/devtools/intellij/qute/psi/java/MavenJavaDocumentLinkTest.java @@ -308,6 +308,34 @@ public void testTemplateRecord() throws Exception { templateFileUri, "Create `src/main/resources/templates/Bonjour.html`")); } + @Test + public void testCheckedTemplateWithDefaultName() throws Exception { + + // @CheckedTemplate(defaultName=CheckedTemplate.HYPHENATED_ELEMENT_NAME) + // static class Templates { + // static native TemplateInstance HelloWorld(String name); + + var module = loadMavenProject(QuteMavenProjectName.qute_record); + QuteJavaDocumentLinkParams params = new QuteJavaDocumentLinkParams(); + String javaFileUri = LSPIJUtils.toUri(module).resolve("src/main/java/org/acme/sample/ItemResource.java").toASCIIString(); + params.setUri(javaFileUri); + + List links = QuteSupportForJava.getInstance().documentLink(params, PsiUtilsLSImpl.getInstance(myProject), + new EmptyProgressIndicator()); + assertEquals(3, links.size()); + + String helloFileUri = LSPIJUtils.toUri(module).resolve("src/main/resources/templates/ItemResource/HelloWorld.html").toASCIIString(); + String hello2FileUri = LSPIJUtils.toUri(module).resolve("src/main/resources/templates/ItemResource/hello-world.html").toASCIIString(); + String hello3FileUri = LSPIJUtils.toUri(module).resolve("src/main/resources/templates/ItemResource/hello_world.html").toASCIIString(); + + assertDocumentLink(links, // + dl(r(19, 33, 19, 43), // + helloFileUri, "Create `src/main/resources/templates/ItemResource/HelloWorld.html`"), // + dl(r(25, 33, 25, 43), // + hello2FileUri, "Create `src/main/resources/templates/ItemResource/hello-world.html`"), // + dl(r(31, 33, 31, 43), // + hello3FileUri, "Create `src/main/resources/templates/ItemResource/hello_world.html`")); + } public static Range r(int line, int startChar, int endChar) { return r(line, startChar, line, endChar); diff --git a/src/test/java/com/redhat/devtools/intellij/qute/psi/template/TemplateGetDataModelProjectTest.java b/src/test/java/com/redhat/devtools/intellij/qute/psi/template/TemplateGetDataModelProjectTest.java index dfd209be4..2a60da69d 100644 --- a/src/test/java/com/redhat/devtools/intellij/qute/psi/template/TemplateGetDataModelProjectTest.java +++ b/src/test/java/com/redhat/devtools/intellij/qute/psi/template/TemplateGetDataModelProjectTest.java @@ -147,7 +147,7 @@ private static void checkedTemplateInnerClass(DataModelProject", false, items); + assertParameter("items", "java.util.List", false, parameters, 0); // static native TemplateInstance map(Map> items, // Map.Entry entry); @@ -164,8 +164,8 @@ private static void checkedTemplateInnerClass(DataModelProject>", false, - map); - assertParameter("entry", "java.util.Map$Entry", false, map); + parameters, 0); + assertParameter("entry", "java.util.Map$Entry", false, parameters, 1); } private static void checkedTemplate(DataModelProject> project) { @@ -183,7 +183,7 @@ private static void checkedTemplate(DataModelProject hello3Template = project @@ -199,7 +199,7 @@ private static void checkedTemplate(DataModelProject resolvers) { @@ -358,7 +358,7 @@ private static void testValueResolversFromTemplateGlobal(List } @Test - public void quarkus3() throws Exception { + public void testQuarkus3() throws Exception { loadMavenProject(QuteMavenProjectName.quarkus3); QuteDataModelProjectParams params = new QuteDataModelProjectParams(QuteMavenProjectName.quarkus3); @@ -374,7 +374,7 @@ public void quarkus3() throws Exception { } @Test - public void quteRecord() throws Exception { + public void testQuteRecord() throws Exception { loadMavenProject(QuteMavenProjectName.qute_record); QuteDataModelProjectParams params = new QuteDataModelProjectParams(QuteMavenProjectName.qute_record); @@ -390,7 +390,7 @@ public void quteRecord() throws Exception { .findDataModelTemplate("src/main/resources/templates/Hello"); Assert.assertNotNull(helloTemplate); Assert.assertEquals("src/main/resources/templates/Hello", helloTemplate.getTemplateUri()); - Assert.assertEquals("org.acme.sample.HelloResource$Hello", helloTemplate.getSourceType()); + Assert.assertEquals("org.acme.sample.HelloResource.Hello", helloTemplate.getSourceType()); Assert.assertNull(helloTemplate.getSourceField()); Assert.assertNull(helloTemplate.getSourceMethod()); @@ -407,4 +407,36 @@ public void quteRecord() throws Exception { assertParameter("foo", "int", true, helloParameters, 1); } + @Test + public void testCheckedTemplateWithDefaultName() throws Exception { + loadMavenProject(QuteMavenProjectName.qute_record); + + QuteDataModelProjectParams params = new QuteDataModelProjectParams(QuteMavenProjectName.qute_record); + DataModelProject> project = QuteSupportForTemplate.getInstance() + .getDataModelProject(params, getJDTUtils(), new EmptyProgressIndicator()); + Assert.assertNotNull(project); + + // public class HelloResource { + // record Hello(String name) implements TemplateInstance {} + + // Hello + DataModelTemplate helloTemplate = project + .findDataModelTemplate("src/main/resources/templates/ItemResource/hello-world.html"); + Assert.assertNotNull(helloTemplate); + Assert.assertEquals("src/main/resources/templates/ItemResource/hello-world", helloTemplate.getTemplateUri()); + Assert.assertEquals("org.acme.sample.ItemResource$Templates2", helloTemplate.getSourceType()); + Assert.assertEquals("HelloWorld", helloTemplate.getSourceMethod()); + Assert.assertNull(helloTemplate.getSourceField()); + + List helloParameters = helloTemplate.getParameters(); + Assert.assertNotNull(helloParameters); + + Assert.assertEquals(1, helloParameters.size()); + + // static class Templates2 { + // static native TemplateInstance HelloWorld(String name); + assertParameter("name", "java.lang.String", false, helloParameters, 0); + + } + }