From 73ca6123d738547347a9dadeaf6090dd539ce697 Mon Sep 17 00:00:00 2001 From: azerr Date: Wed, 18 Jan 2023 04:12:05 +0100 Subject: [PATCH] Fragment support between Java / Template file See https://github.com/redhat-developer/vscode-quarkus/issues/563 Signed-off-by: azerr --- .../acme/qute/ItemResourceWithFragment.java | 54 +++++++ .../ItemResourceWithFragment/items.html | 0 .../ItemResourceWithFragment/items2$id1.html | 0 .../ItemResourceWithFragment/items2.html | 0 .../qute/jdt/java/JavaCodeLensTest.java | 52 +++++++ .../qute/jdt/java/JavaDiagnosticsTest.java | 34 ++++- .../qute/jdt/java/JavaDocumentLinkTest.java | 35 +++++ .../datamodel/DataModelBaseTemplate.java | 137 ++++++++++++++++++ .../commons/datamodel/DataModelFragment.java | 59 ++++++++ .../commons/datamodel/DataModelTemplate.java | 129 ++++++----------- .../qute/jdt/internal/QuteJavaConstants.java | 2 + .../AbstractQuteTemplateLinkCollector.java | 59 ++++++-- .../qute/jdt/internal/java/QuteErrorCode.java | 5 +- .../java/QuteJavaCodeLensCollector.java | 31 ++-- .../java/QuteJavaDiagnosticsCollector.java | 51 +++++-- .../java/QuteJavaDocumentLinkCollector.java | 11 +- .../template/TemplateDataCollector.java | 5 +- .../template/TemplateDataSupport.java | 4 +- .../datamodel/CheckedTemplateSupport.java | 119 ++++++++++++--- .../datamodel/TemplateFieldSupport.java | 9 +- .../qute/jdt/utils/AnnotationUtils.java | 28 ++++ .../qute/jdt/utils/JDTQuteProjectUtils.java | 19 ++- .../qute/jdt/utils/TemplatePathInfo.java | 75 ++++++++++ .../datamodel/DataModelBaseTemplate.java | 137 ++++++++++++++++++ .../commons/datamodel/DataModelFragment.java | 59 ++++++++ .../commons/datamodel/DataModelTemplate.java | 129 ++++++----------- .../template/sections/FragmentSection.java | 27 ++++ .../datamodel/DataModelSourceProvider.java | 36 +++++ .../datamodel/ExtendedDataModelFragment.java | 51 +++++++ .../datamodel/ExtendedDataModelParameter.java | 8 +- .../datamodel/ExtendedDataModelTemplate.java | 19 ++- .../redhat/qute/services/QuteCodeLens.java | 104 ++++++++----- .../qute/project/QuteQuickStartProject.java | 39 ++++- .../QuteCodeLensForDataModelFragmentTest.java | 93 ++++++++++++ ...QuteCodeLensForDataModelTemplateTest.java} | 4 +- 35 files changed, 1326 insertions(+), 298 deletions(-) create mode 100644 qute.jdt/com.redhat.qute.jdt.test/projects/maven/qute-quickstart/src/main/java/org/acme/qute/ItemResourceWithFragment.java create mode 100644 qute.jdt/com.redhat.qute.jdt.test/projects/maven/qute-quickstart/src/main/resources/templates/ItemResourceWithFragment/items.html create mode 100644 qute.jdt/com.redhat.qute.jdt.test/projects/maven/qute-quickstart/src/main/resources/templates/ItemResourceWithFragment/items2$id1.html create mode 100644 qute.jdt/com.redhat.qute.jdt.test/projects/maven/qute-quickstart/src/main/resources/templates/ItemResourceWithFragment/items2.html create mode 100644 qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelBaseTemplate.java create mode 100644 qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelFragment.java create mode 100644 qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/TemplatePathInfo.java create mode 100644 qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelBaseTemplate.java create mode 100644 qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelFragment.java create mode 100644 qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/DataModelSourceProvider.java create mode 100644 qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelFragment.java create mode 100644 qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/codelens/QuteCodeLensForDataModelFragmentTest.java rename qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/codelens/{QuteCodeLensForDataModelTest.java => QuteCodeLensForDataModelTemplateTest.java} (93%) diff --git a/qute.jdt/com.redhat.qute.jdt.test/projects/maven/qute-quickstart/src/main/java/org/acme/qute/ItemResourceWithFragment.java b/qute.jdt/com.redhat.qute.jdt.test/projects/maven/qute-quickstart/src/main/java/org/acme/qute/ItemResourceWithFragment.java new file mode 100644 index 000000000..dd99c24be --- /dev/null +++ b/qute.jdt/com.redhat.qute.jdt.test/projects/maven/qute-quickstart/src/main/java/org/acme/qute/ItemResourceWithFragment.java @@ -0,0 +1,54 @@ +package org.acme.qute; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +import io.quarkus.qute.CheckedTemplate; +import io.quarkus.qute.TemplateExtension; +import io.quarkus.qute.TemplateInstance; + +@Path("items2") +public class ItemResourceWithFragment { + + @CheckedTemplate + static class Templates { + static native TemplateInstance items(List items); + static native TemplateInstance items$id1(List items); + static native TemplateInstance items3$id2(List items); + static native TemplateInstance items3$(List items); + } + + @CheckedTemplate(ignoreFragments = true) + static class Templates2 { + static native TemplateInstance items2(List items); + static native TemplateInstance items2$id1(List items); + static native TemplateInstance items2$id2(List items); + } + + @GET + @Produces(MediaType.TEXT_HTML) + public TemplateInstance get() { + List items = new ArrayList<>(); + items.add(new Item(new BigDecimal(10), "Apple")); + items.add(new Item(new BigDecimal(16), "Pear")); + items.add(new Item(new BigDecimal(30), "Orange")); + return Templates.items(items); + } + + /** + * This template extension method implements the "discountedPrice" computed + * property. + */ + @TemplateExtension + static BigDecimal discountedPrice(Item item) { + return item.price.multiply(new BigDecimal("0.9")); + } + +} diff --git a/qute.jdt/com.redhat.qute.jdt.test/projects/maven/qute-quickstart/src/main/resources/templates/ItemResourceWithFragment/items.html b/qute.jdt/com.redhat.qute.jdt.test/projects/maven/qute-quickstart/src/main/resources/templates/ItemResourceWithFragment/items.html new file mode 100644 index 000000000..e69de29bb diff --git a/qute.jdt/com.redhat.qute.jdt.test/projects/maven/qute-quickstart/src/main/resources/templates/ItemResourceWithFragment/items2$id1.html b/qute.jdt/com.redhat.qute.jdt.test/projects/maven/qute-quickstart/src/main/resources/templates/ItemResourceWithFragment/items2$id1.html new file mode 100644 index 000000000..e69de29bb diff --git a/qute.jdt/com.redhat.qute.jdt.test/projects/maven/qute-quickstart/src/main/resources/templates/ItemResourceWithFragment/items2.html b/qute.jdt/com.redhat.qute.jdt.test/projects/maven/qute-quickstart/src/main/resources/templates/ItemResourceWithFragment/items2.html new file mode 100644 index 000000000..e69de29bb diff --git a/qute.jdt/com.redhat.qute.jdt.test/src/main/java/com/redhat/qute/jdt/java/JavaCodeLensTest.java b/qute.jdt/com.redhat.qute.jdt.test/src/main/java/com/redhat/qute/jdt/java/JavaCodeLensTest.java index 7515d1b7f..c45ac871c 100644 --- a/qute.jdt/com.redhat.qute.jdt.test/src/main/java/com/redhat/qute/jdt/java/JavaCodeLensTest.java +++ b/qute.jdt/com.redhat.qute.jdt.test/src/main/java/com/redhat/qute/jdt/java/JavaCodeLensTest.java @@ -198,6 +198,58 @@ public void checkedTemplateInInnerClass() throws CoreException, Exception { "qute.command.generate.template.file", Arrays.asList(items2Uri))); } + @Test + public void checkedTemplateWithFragment() throws CoreException, Exception { + + IJavaProject javaProject = loadMavenProject(QuteMavenProjectName.qute_quickstart); + + QuteJavaCodeLensParams params = new QuteJavaCodeLensParams(); + IFile javaFile = javaProject.getProject() + .getFile(new Path("src/main/java/org/acme/qute/ItemResourceWithFragment.java")); + params.setUri(javaFile.getLocation().toFile().toURI().toString()); + + List lenses = QuteSupportForJava.getInstance().codeLens(params, getJDTUtils(), + new NullProgressMonitor()); + assertEquals(6, lenses.size()); + + String itemsUri = javaProject.getProject() + .getFile("src/main/resources/templates/ItemResourceWithFragment/items.html").getLocationURI() + .toString(); + String items3Uri = javaProject.getProject() + .getFile("src/main/resources/templates/ItemResourceWithFragment/items3.html").getLocationURI() + .toString(); + String items2Uri = javaProject.getProject() + .getFile("src/main/resources/templates/ItemResourceWithFragment/items2.html").getLocationURI() + .toString(); + String items2Uri_id1 = javaProject.getProject() + .getFile("src/main/resources/templates/ItemResourceWithFragment/items2$id1.html").getLocationURI() + .toString(); + String items2Uri_id2 = javaProject.getProject() + .getFile("src/main/resources/templates/ItemResourceWithFragment/items2$id2.html").getLocationURI() + .toString(); + + assertCodeLens(lenses, // + cl(r(21, 2, 21, 57), // + "Open `src/main/resources/templates/ItemResourceWithFragment/items.html`", // + "qute.command.open.uri", Arrays.asList(itemsUri)), // + cl(r(22, 2, 22, 61), // + "Open `id1` fragment of `src/main/resources/templates/ItemResourceWithFragment/items.html`", // + "qute.command.open.uri", Arrays.asList(itemsUri, "id1")), // + cl(r(23, 2, 23, 62), // + "Create `src/main/resources/templates/ItemResourceWithFragment/items3.html`", // + "qute.command.generate.template.file", Arrays.asList(items3Uri)), // + + cl(r(29, 2, 29, 58), // + "Open `src/main/resources/templates/ItemResourceWithFragment/items2.html`", // + "qute.command.open.uri", Arrays.asList(items2Uri)), // + cl(r(30, 2, 30, 62), // + "Open `src/main/resources/templates/ItemResourceWithFragment/items2$id1.html`", // + "qute.command.open.uri", Arrays.asList(items2Uri_id1)), // + cl(r(31, 2, 31, 62), // + "Create `src/main/resources/templates/ItemResourceWithFragment/items2$id2.html`", // + "qute.command.generate.template.file", Arrays.asList(items2Uri_id2))); + } + public static Range r(int line, int startChar, int endChar) { return r(line, startChar, line, endChar); } diff --git a/qute.jdt/com.redhat.qute.jdt.test/src/main/java/com/redhat/qute/jdt/java/JavaDiagnosticsTest.java b/qute.jdt/com.redhat.qute.jdt.test/src/main/java/com/redhat/qute/jdt/java/JavaDiagnosticsTest.java index 00cbdb3ab..30e0e0918 100644 --- a/qute.jdt/com.redhat.qute.jdt.test/src/main/java/com/redhat/qute/jdt/java/JavaDiagnosticsTest.java +++ b/qute.jdt/com.redhat.qute.jdt.test/src/main/java/com/redhat/qute/jdt/java/JavaDiagnosticsTest.java @@ -140,8 +140,9 @@ public void checkedTemplateInInnerClass() throws CoreException, Exception { // static class Templates { // [Open `src/main/resources/templates/ItemResource/items.qute.html`] // static native TemplateInstance items(List items); - // [Create `src/main/resources/templates/ItemResource/map.qute.html`] - // static native TemplateInstance map(Map> items, Map.Entry entry); + // [Create `src/main/resources/templates/ItemResource/map.qute.html`] + // static native TemplateInstance map(Map> items, + // Map.Entry entry); IJavaProject javaProject = loadMavenProject(QuteMavenProjectName.qute_quickstart); @@ -165,6 +166,35 @@ public void checkedTemplateInInnerClass() throws CoreException, Exception { DiagnosticSeverity.Error, "qute", QuteErrorCode.NoMatchingTemplate.name())); } + @Test + public void checkedTemplateInWithFragment() throws CoreException, Exception { + + IJavaProject javaProject = loadMavenProject(QuteMavenProjectName.qute_quickstart); + + QuteJavaDiagnosticsParams params = new QuteJavaDiagnosticsParams(); + IFile javaFile = javaProject.getProject() + .getFile(new Path("src/main/java/org/acme/qute/ItemResourceWithFragment.java")); + params.setUris(Arrays.asList(javaFile.getLocation().toFile().toURI().toString())); + + List publishDiagnostics = QuteSupportForJava.getInstance().diagnostics(params, + getJDTUtils(), new NullProgressMonitor()); + assertEquals(1, publishDiagnostics.size()); + + List diagnostics = publishDiagnostics.get(0).getDiagnostics(); + assertEquals(3, 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.ItemResourceWithFragment$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()), // + new Diagnostic(r(31, 33, 31, 43), + "No template matching the path ItemResourceWithFragment/items2$id2 could be found for: org.acme.qute.ItemResourceWithFragment$Templates2", + 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/qute.jdt/com.redhat.qute.jdt.test/src/main/java/com/redhat/qute/jdt/java/JavaDocumentLinkTest.java b/qute.jdt/com.redhat.qute.jdt.test/src/main/java/com/redhat/qute/jdt/java/JavaDocumentLinkTest.java index c5a053ad9..4ca8c9f06 100644 --- a/qute.jdt/com.redhat.qute.jdt.test/src/main/java/com/redhat/qute/jdt/java/JavaDocumentLinkTest.java +++ b/qute.jdt/com.redhat.qute.jdt.test/src/main/java/com/redhat/qute/jdt/java/JavaDocumentLinkTest.java @@ -165,6 +165,41 @@ public void checkedTemplateInInnerClass() throws CoreException, Exception { templateFileUri, "Create `src/main/resources/templates/ItemResource/items2.qute.html`")); } + @Test + public void checkedTemplateWithFragment() throws CoreException, Exception { + + IJavaProject javaProject = loadMavenProject(QuteMavenProjectName.qute_quickstart); + + QuteJavaDocumentLinkParams params = new QuteJavaDocumentLinkParams(); + IFile javaFile = javaProject.getProject() + .getFile(new Path("src/main/java/org/acme/qute/ItemResourceWithFragment.java")); + params.setUri(javaFile.getLocation().toFile().toURI().toString()); + + List links = QuteSupportForJava.getInstance().documentLink(params, getJDTUtils(), + new NullProgressMonitor()); + assertEquals(6, links.size()); + + String templateFileUri = javaProject.getProject() + .getFile("src/main/resources/templates/ItemResourceWithFragment/items.html").getLocationURI() + .toString(); + + assertDocumentLink(links, // + dl(r(21, 33, 21, 38), // + templateFileUri, "Open `src/main/resources/templates/ItemResourceWithFragment/items.html`"), // + dl(r(22, 33, 22, 42), // + templateFileUri, "Open `src/main/resources/templates/ItemResourceWithFragment/items.html`"), // + dl(r(23, 33, 23, 43), // + templateFileUri, "Create `src/main/resources/templates/ItemResourceWithFragment/items3.html`"), // + dl(r(29, 33, 29, 39), // + templateFileUri, "Open `src/main/resources/templates/ItemResourceWithFragment/items2.html`"), // + dl(r(30, 33, 30, 43), // + templateFileUri, + "Open `src/main/resources/templates/ItemResourceWithFragment/items2$id1.html`"), // + dl(r(31, 33, 31, 43), // + templateFileUri, + "Open `src/main/resources/templates/ItemResourceWithFragment/items2$id2.html`")); + } + public static Range r(int line, int startChar, int endChar) { return r(line, startChar, line, endChar); } diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelBaseTemplate.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelBaseTemplate.java new file mode 100644 index 000000000..4280e3da6 --- /dev/null +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelBaseTemplate.java @@ -0,0 +1,137 @@ +/******************************************************************************* +* Copyright (c) 2023 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.qute.commons.datamodel; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Base class for data model fragment / template. + * + * @param data model parameter. + * + * @see Fragments + * @see Type-safe + * Fragments + * + * @author Angelo ZERR + */ + +public class DataModelBaseTemplate { + + private String sourceType; + + private String sourceMethod; + + private List parameters; + + private transient Map parametersMap; + + /** + * Returns the Java source type where this data model template is defined. + * + * @return the Java source type where this data model template is defined. + */ + public String getSourceType() { + return sourceType; + } + + /** + * Set the Java source type where this data model template is defined. + * + * @param sourceType the Java source type where this data model template is + * defined. + */ + public void setSourceType(String sourceType) { + this.sourceType = sourceType; + } + + /** + * Returns the Java source method where this data model template is defined and + * null otherwise. + * + * @return the Java source method where this data model template is defined and + * null otherwise. + */ + public String getSourceMethod() { + return sourceMethod; + } + + /** + * Set the Java source method where this data model template is defined and null + * otherwise. + * + * @param sourceMethod the Java source method where this data model template is + * defined and null otherwise. + */ + public void setSourceMethod(String sourceMethod) { + this.sourceMethod = sourceMethod; + } + + /** + * Returns the list of data model parameters. + * + * @return the list of data model parameters. + */ + public List getParameters() { + return parameters; + } + + /** + * Set the list of data model parameters. + * + * @param parameters the list of data model parameters. + */ + public void setParameters(List parameters) { + this.parameters = parameters; + } + + /** + * Returns the parameter from the given key and null otherwise. + * + * @param key the parameter key. + * + * @return the parameter from the given key and null otherwise. + */ + public T getParameter(String key) { + if (parameters == null) { + return null; + } + return getParametersMap().get(key); + } + + /** + * Add the given parameter. + * + * @param parameter the parameter to add. + */ + public void addParameter(T parameter) { + if (parameters == null) { + parameters = new ArrayList<>(); + } + parameters.add(parameter); + getParametersMap().put(parameter.getKey(), parameter); + } + + private Map getParametersMap() { + if (parametersMap == null) { + parametersMap = parameters.stream() + .collect(Collectors.toMap(DataModelParameter::getKey, Function.identity())); + } + return parametersMap; + } +} diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelFragment.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelFragment.java new file mode 100644 index 000000000..ed287602d --- /dev/null +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelFragment.java @@ -0,0 +1,59 @@ +/******************************************************************************* +* Copyright (c) 2023 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.qute.commons.datamodel; + +import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; + +/** + * Data model fragment hosts informations about the expected data model + * (parameters) for a given fragment. + * + * @param data model parameter. + * + * @see Fragments + * @see Type-safe + * Fragments + * + * @author Angelo ZERR + */ +public class DataModelFragment extends DataModelBaseTemplate { + + private String id; + + /** + * Returns the fragment id. + * + * @return the fragment id. + */ + public String getId() { + return id; + } + + /** + * Set the fragment id. + * + * @param id the fragment id + */ + public void setId(String id) { + this.id = id; + } + + @Override + public String toString() { + ToStringBuilder b = new ToStringBuilder(this); + b.add("id", this.id); + b.add("parameters", this.getParameters()); + return b.toString(); + } +} diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelTemplate.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelTemplate.java index 34e68d04e..327794604 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelTemplate.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelTemplate.java @@ -13,9 +13,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; @@ -23,23 +20,17 @@ * Data model template host informations about the expected data model * (parameters) for a given template. * - * @author Angelo ZERR - * * @param data model parameter. + * + * @author Angelo ZERR */ -public class DataModelTemplate { +public class DataModelTemplate extends DataModelBaseTemplate { private String templateUri; - private String sourceType; - - private String sourceMethod; - private String sourceField; - - private List parameters; - private transient Map parametersMap; + private List> fragments; /** * Returns the template Uri. @@ -59,47 +50,6 @@ public void setTemplateUri(String templateUri) { this.templateUri = templateUri; } - /** - * Returns the Java source type where this data model template is defined. - * - * @return the Java source type where this data model template is defined. - */ - public String getSourceType() { - return sourceType; - } - - /** - * Set the Java source type where this data model template is defined. - * - * @param sourceType the Java source type where this data model template is - * defined. - */ - public void setSourceType(String sourceType) { - this.sourceType = sourceType; - } - - /** - * Returns the Java source method where this data model template is defined and - * null otherwise. - * - * @return the Java source method where this data model template is defined and - * null otherwise. - */ - public String getSourceMethod() { - return sourceMethod; - } - - /** - * Set the Java source method where this data model template is defined and null - * otherwise. - * - * @param sourceMethod the Java source method where this data model template is - * defined and null otherwise. - */ - public void setSourceMethod(String sourceMethod) { - this.sourceMethod = sourceMethod; - } - /** * Returns the Java source field where this data model template is defined and * null otherwise. @@ -123,62 +73,69 @@ public void setSourceField(String sourceField) { } /** - * Returns the list of data model parameters. + * Add the given fragment. + * + * @param fragment the fragment to add. + */ + public void addFragment(DataModelFragment fragment) { + if (fragments == null) { + fragments = new ArrayList<>(); + } + fragments.add(fragment); + } + + /** + * Returns list of fragments and null otherwise. * - * @return the list of data model parameters. + * @return list of fragments and null otherwise. */ - public List getParameters() { - return parameters; + public List> getFragments() { + return fragments; } /** - * Set the list of data model parameters. + * Set the fragment list. * - * @param parameters the list of data model parameters. + * @param fragments the fragment list. */ - public void setParameters(List parameters) { - this.parameters = parameters; + public void setFragments(List> fragments) { + this.fragments = fragments; } /** - * Returns the parameter from the given key and null otherwise. + * Returns the fragment identified by the given id fragmentId and + * null otherwise. * - * @param key the parameter key. + * @param fragmentId the fragment id. * - * @return the parameter from the given key and null otherwise. + * @return the fragment identified by the given id fragmentId and + * null otherwise. */ - public T getParameter(String key) { - List parameters = getParameters(); - if (parameters == null) { + public DataModelFragment getFragment(String fragmentId) { + if (fragmentId == null) { return null; } - return getParametersMap().get(key); - } - - public void addParameter(T parameter) { - if (parameters == null) { - parameters = new ArrayList<>(); + List> fragments = getFragments(); + if (fragments == null || fragments.isEmpty()) { + return null; } - parameters.add(parameter); - getParametersMap().put(parameter.getKey(), parameter); - } - - private Map getParametersMap() { - if (parametersMap == null) { - parametersMap = parameters.stream() - .collect(Collectors.toMap(DataModelParameter::getKey, Function.identity())); + for (DataModelFragment fragment : fragments) { + if (fragmentId.equals(fragment.getId())) { + return fragment; + } } - return parametersMap; + return null; } @Override public String toString() { ToStringBuilder b = new ToStringBuilder(this); b.add("templateUri", this.templateUri); - b.add("sourceType", this.sourceType); - b.add("sourceMethod", this.sourceMethod); + b.add("sourceType", this.getSourceType()); + b.add("sourceMethod", this.getSourceMethod()); b.add("sourceField", this.sourceField); - b.add("parameters", this.parameters); + b.add("parameters", this.getParameters()); + b.add("fragments", this.getFragments()); return b.toString(); } } diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/QuteJavaConstants.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/QuteJavaConstants.java index 253fd03c8..6396c2136 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/QuteJavaConstants.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/QuteJavaConstants.java @@ -41,6 +41,8 @@ public class QuteJavaConstants { public static final String OLD_CHECKED_TEMPLATE_ANNOTATION = "io.quarkus.qute.api.CheckedTemplate"; + public static final String CHECKED_TEMPLATE_ANNOTATION_IGNORE_FRAGMENTS = "ignoreFragments"; + // @TemplateExtension public static final String TEMPLATE_EXTENSION_ANNOTATION = "io.quarkus.qute.TemplateExtension"; diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/AbstractQuteTemplateLinkCollector.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/AbstractQuteTemplateLinkCollector.java index dbc89205c..a9fc0f4af 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/AbstractQuteTemplateLinkCollector.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/AbstractQuteTemplateLinkCollector.java @@ -12,6 +12,7 @@ package com.redhat.qute.jdt.internal.java; import static com.redhat.qute.jdt.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION; +import static com.redhat.qute.jdt.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION_IGNORE_FRAGMENTS; import static com.redhat.qute.jdt.internal.QuteJavaConstants.OLD_CHECKED_TEMPLATE_ANNOTATION; import static com.redhat.qute.jdt.internal.QuteJavaConstants.TEMPLATE_CLASS; @@ -28,6 +29,7 @@ import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.Annotation; import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.SimpleName; @@ -44,6 +46,7 @@ import com.redhat.qute.jdt.utils.IJDTUtils; import com.redhat.qute.jdt.utils.JDTQuteProjectUtils; import com.redhat.qute.jdt.utils.JDTTypeUtils; +import com.redhat.qute.jdt.utils.TemplatePathInfo; /** * Abstract class which collects {@link MethodDeclaration} or @@ -118,7 +121,7 @@ public boolean visit(FieldDeclaration node) { .getLocationExpressionFromConstructorParameter(variable.getName().getIdentifier()); } String fieldName = variable.getName().getIdentifier(); - collectTemplateLink(node, locationExpression, getTypeDeclaration(node), null, fieldName); + collectTemplateLink(node, locationExpression, getTypeDeclaration(node), null, fieldName, false); } } return super.visit(node); @@ -151,10 +154,11 @@ public boolean visit(TypeDeclaration node) { // @CheckedTemplate // public static class Templates { // public static native TemplateInstance book(Book book); + boolean ignoreFragments = isIgnoreFragments(annotation); List body = node.bodyDeclarations(); for (Object declaration : body) { if (declaration instanceof MethodDeclaration) { - collectTemplateLink((MethodDeclaration) declaration, node); + collectTemplateLink((MethodDeclaration) declaration, node, ignoreFragments); } } } @@ -163,6 +167,31 @@ public boolean visit(TypeDeclaration node) { return super.visit(node); } + /** + * Returns true if @CheckedTemplate annotation declares that fragment must be + * ignored and false otherwise. + * + * + * @CheckedTemplate(ignoreFragments=true) + * + * + * @param checkedTemplateAnnotation the CheckedTemplate annotation. + * + * @return true if @CheckedTemplate annotation declares that fragment must be + * ignored and false otherwise. + */ + private static boolean isIgnoreFragments(Annotation checkedTemplateAnnotation) { + Boolean ignoreFragment = null; + try { + Expression ignoreFragmentExpr = AnnotationUtils.getAnnotationMemberValueExpression( + checkedTemplateAnnotation, CHECKED_TEMPLATE_ANNOTATION_IGNORE_FRAGMENTS); + ignoreFragment = AnnotationUtils.getBoolean(ignoreFragmentExpr); + } catch (Exception e) { + // Do nothing + } + return ignoreFragment != null ? ignoreFragment.booleanValue() : false; + } + @Override public void endVisit(TypeDeclaration node) { levelTypeDecl--; @@ -177,32 +206,36 @@ private static TypeDeclaration getTypeDeclaration(ASTNode node) { return parent != null && parent.getNodeType() == ASTNode.TYPE_DECLARATION ? (TypeDeclaration) parent : null; } - private void collectTemplateLink(MethodDeclaration methodDeclaration, TypeDeclaration type) { + private void collectTemplateLink(MethodDeclaration methodDeclaration, TypeDeclaration type, + boolean ignoreFragment) { String className = null; boolean innerClass = levelTypeDecl > 1; if (innerClass) { className = JDTTypeUtils.getSimpleClassName(typeRoot.getElementName()); } String methodName = methodDeclaration.getName().getIdentifier(); - collectTemplateLink(methodDeclaration, null, type, className, methodName); + collectTemplateLink(methodDeclaration, null, type, className, methodName, ignoreFragment); } private void collectTemplateLink(ASTNode fieldOrMethod, StringLiteral locationAnnotation, TypeDeclaration type, - String className, String fieldOrMethodName) { + String className, String fieldOrMethodName, boolean ignoreFragment) { try { String location = locationAnnotation != null ? locationAnnotation.getLiteralValue() : null; IProject project = typeRoot.getJavaProject().getProject(); - String templateFilePath = location != null ? JDTQuteProjectUtils.getTemplatePath(null, location) - : JDTQuteProjectUtils.getTemplatePath(className, fieldOrMethodName); + TemplatePathInfo templatePathInfo = location != null + ? JDTQuteProjectUtils.getTemplatePath(null, location, ignoreFragment) + : JDTQuteProjectUtils.getTemplatePath(className, fieldOrMethodName, ignoreFragment); IFile templateFile = null; if (location == null) { - templateFile = getTemplateFile(project, templateFilePath); - templateFilePath = templateFile.getLocation().makeRelativeTo(project.getLocation()).toString(); + templateFile = getTemplateFile(project, templatePathInfo.getTemplateUri()); + templatePathInfo = new TemplatePathInfo( + templateFile.getLocation().makeRelativeTo(project.getLocation()).toString(), + templatePathInfo.getFragmentId()); } else { - templateFile = project.getFile(templateFilePath); + templateFile = project.getFile(templatePathInfo.getTemplateUri()); } collectTemplateLink(fieldOrMethod, locationAnnotation, type, className, fieldOrMethodName, location, - templateFile, templateFilePath); + templateFile, templatePathInfo); } catch (JavaModelException e) { LOGGER.log(Level.SEVERE, "Error while creating Qute CodeLens for Java file.", e); } @@ -229,8 +262,8 @@ protected Range createRange(ASTNode fieldOrMethod) throws JavaModelException { } protected abstract void collectTemplateLink(ASTNode node, ASTNode locationAnnotation, TypeDeclaration type, - String className, String fieldOrMethodName, String location, IFile templateFile, String templateFilePath) - throws JavaModelException; + String className, String fieldOrMethodName, String location, IFile templateFile, + TemplatePathInfo templatePathInfo) throws JavaModelException; private static IFile getTemplateFile(IProject project, String templateFilePathWithoutExtension) { for (String suffix : suffixes) { diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteErrorCode.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteErrorCode.java index cb3510b22..fcd6e8393 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteErrorCode.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteErrorCode.java @@ -13,8 +13,9 @@ public enum QuteErrorCode implements IQuteErrorCode { - NoMatchingTemplate("No template matching the path {0} could be found for: {1}"); - + NoMatchingTemplate("No template matching the path {0} could be found for: {1}"), + FragmentNotDefined("Fragment [{0}] not defined in template {1}"); + private final String rawMessage; QuteErrorCode(String rawMessage) { diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaCodeLensCollector.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaCodeLensCollector.java index 15360eeb4..fa50edc56 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaCodeLensCollector.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaCodeLensCollector.java @@ -22,7 +22,6 @@ import org.eclipse.jdt.core.ITypeRoot; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.ASTNode; -import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; @@ -37,6 +36,7 @@ import com.redhat.qute.jdt.QuteCommandConstants; import com.redhat.qute.jdt.utils.IJDTUtils; import com.redhat.qute.jdt.utils.JDTQuteProjectUtils; +import com.redhat.qute.jdt.utils.TemplatePathInfo; /** * Report codelens for opening/creating Qute template for: @@ -53,6 +53,8 @@ public class QuteJavaCodeLensCollector extends AbstractQuteTemplateLinkCollector private static final String QUTE_COMMAND_OPEN_URI_MESSAGE = "Open `{0}`"; + private static final String QUTE_COMMAND_OPEN_URI_WITH_FRAGMENT_MESSAGE = "Open `{0}` fragment of `{1}`"; + private static final String QUTE_COMMAND_GENERATE_TEMPLATE_MESSAGE = "Create `{0}`"; private final List lenses; @@ -64,21 +66,31 @@ public QuteJavaCodeLensCollector(ITypeRoot typeRoot, List lenses, IJDT } @Override - protected void collectTemplateLink(ASTNode fieldOrMethod, ASTNode locationAnnotation, TypeDeclaration type, String className, String fieldOrMethodName, - String location, IFile templateFile, String templateFilePath) throws JavaModelException { + protected void collectTemplateLink(ASTNode fieldOrMethod, ASTNode locationAnnotation, TypeDeclaration type, + String className, String fieldOrMethodName, String location, IFile templateFile, + TemplatePathInfo templatePathInfo) throws JavaModelException { + if (!templatePathInfo.isValid()) { + // It is an empty fragment which is not valid, don't generate a codelens. + return; + } Command command = null; + String templateUri = templatePathInfo.getTemplateUri(); + String fragmentId = templatePathInfo.getFragmentId(); if (templateFile.exists()) { - command = new Command(MessageFormat.format(QUTE_COMMAND_OPEN_URI_MESSAGE, templateFilePath), // + String title = templatePathInfo.hasFragment() + ? MessageFormat.format(QUTE_COMMAND_OPEN_URI_WITH_FRAGMENT_MESSAGE, fragmentId, templateUri) + : MessageFormat.format(QUTE_COMMAND_OPEN_URI_MESSAGE, templateUri); + command = new Command(title, // QuteCommandConstants.QUTE_COMMAND_OPEN_URI, - Arrays.asList(templateFile.getLocationURI().toString())); + Arrays.asList(templateFile.getLocationURI().toString(), fragmentId)); } else { List parameters = createParameters(fieldOrMethod); GenerateTemplateInfo info = new GenerateTemplateInfo(); info.setParameters(parameters); info.setProjectUri(JDTQuteProjectUtils.getProjectUri(typeRoot.getJavaProject())); info.setTemplateFileUri(templateFile.getLocationURI().toString()); - info.setTemplateFilePath(templateFilePath); - command = new Command(MessageFormat.format(QUTE_COMMAND_GENERATE_TEMPLATE_MESSAGE, templateFilePath), // + info.setTemplateFilePath(templateUri); + command = new Command(MessageFormat.format(QUTE_COMMAND_GENERATE_TEMPLATE_MESSAGE, templateUri), // QuteCommandConstants.QUTE_COMMAND_GENERATE_TEMPLATE_FILE, Arrays.asList(info)); } Range range = utils.toRange(typeRoot, fieldOrMethod.getStartPosition(), fieldOrMethod.getLength()); @@ -93,11 +105,6 @@ private static List createParameters(ASTNode node) { return Collections.emptyList(); } - private static List createParameter(FieldDeclaration node) { - List parameters = new ArrayList<>(); - return parameters; - } - private static List createParameter(MethodDeclaration method) { List parameters = new ArrayList<>(); @SuppressWarnings("rawtypes") diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaDiagnosticsCollector.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaDiagnosticsCollector.java index 21e2ff878..0663b19d2 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaDiagnosticsCollector.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaDiagnosticsCollector.java @@ -26,6 +26,7 @@ import org.eclipse.lsp4j.Range; import com.redhat.qute.jdt.utils.IJDTUtils; +import com.redhat.qute.jdt.utils.TemplatePathInfo; /** * Report diagnostics error for non existing Qute template for: @@ -52,22 +53,52 @@ public QuteJavaDiagnosticsCollector(ITypeRoot typeRoot, List diagnos @Override protected void collectTemplateLink(ASTNode fieldOrMethod, ASTNode locationAnnotation, TypeDeclaration type, - String className, String fieldOrMethodName, String location, IFile templateFile, String templateFilePath) - throws JavaModelException { - if (!templateFile.exists()) { - // No template matching the path HelloResource/index could be found for: - // org.acme.HelloResource$Templates.index - String path = createPath(className, fieldOrMethodName, location); + String className, String fieldOrMethodName, String location, IFile templateFile, + TemplatePathInfo templatePathInfo) throws JavaModelException { + QuteErrorCode error = getQuteErrorCode(templatePathInfo, templateFile); + if (error == null) { + return; + } + + String path = createPath(className, fieldOrMethodName, location); + String fragmentId = templatePathInfo.getFragmentId(); + if (templatePathInfo.hasFragment() && path.endsWith(fragmentId)) { + // Adjust path by removing fragment information + path = path.substring(0, path.length() - (1 /* '$') */ + fragmentId.length())); + } + Range range = createRange(locationAnnotation != null ? locationAnnotation : fieldOrMethod); + + switch (error) { + case FragmentNotDefined: { + Diagnostic diagnostic = createDiagnostic(range, DiagnosticSeverity.Error, error, "", path); + this.diagnostics.add(diagnostic); + break; + } + case NoMatchingTemplate: { ITypeBinding binding = type.resolveBinding(); String fullQualifiedName = ((IType) binding.getJavaElement()).getFullyQualifiedName(); - Range range = createRange(locationAnnotation != null ? locationAnnotation : fieldOrMethod); - Diagnostic diagnostic = createDiagnostic(range, DiagnosticSeverity.Error, QuteErrorCode.NoMatchingTemplate, - path, fullQualifiedName); + Diagnostic diagnostic = createDiagnostic(range, DiagnosticSeverity.Error, error, path, fullQualifiedName); this.diagnostics.add(diagnostic); + break; + } + } + } + + private static QuteErrorCode getQuteErrorCode(TemplatePathInfo templatePathInfo, IFile templateFile) { + if (!templatePathInfo.isValid()) { + // It is an empty fragment which is not valid, report an error + // Fragment [] not defined in template GreetingResource/myTemplate.html + return QuteErrorCode.FragmentNotDefined; + } + if (!templateFile.exists()) { + // No template matching the path HelloResource/index could be found for: + // org.acme.HelloResource$Templates.index + return QuteErrorCode.NoMatchingTemplate; } + return null; } - private String createPath(String className, String fieldOrMethodName, String location) { + private static String createPath(String className, String fieldOrMethodName, String location) { if (location != null) { return location; } diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaDocumentLinkCollector.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaDocumentLinkCollector.java index 7260d81c9..842ffae0a 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaDocumentLinkCollector.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaDocumentLinkCollector.java @@ -24,6 +24,7 @@ import org.eclipse.lsp4j.Range; import com.redhat.qute.jdt.utils.IJDTUtils; +import com.redhat.qute.jdt.utils.TemplatePathInfo; /** * Report document link for opening/creating Qute template for: @@ -52,10 +53,14 @@ public QuteJavaDocumentLinkCollector(ITypeRoot typeRoot, List link @Override protected void collectTemplateLink(ASTNode fieldOrMethod, ASTNode locationAnnotation, TypeDeclaration type, - String className, String fieldOrMethodName, String location, IFile templateFile, String templateFilePath) - throws JavaModelException { + String className, String fieldOrMethodName, String location, IFile templateFile, + TemplatePathInfo templatePathInfo) throws JavaModelException { + if (!templatePathInfo.isValid()) { + // It is an empty fragment which is not valid, don't generate a document link. + return; + } String templateUri = templateFile.getLocationURI().toString(); - String tooltip = getTooltip(templateFile, templateFilePath); + String tooltip = getTooltip(templateFile, templatePathInfo.getTemplateUri()); Range range = createRange(locationAnnotation != null ? locationAnnotation : fieldOrMethod); DocumentLink link = new DocumentLink(range, templateUri, null, tooltip); links.add(link); diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/TemplateDataCollector.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/TemplateDataCollector.java index 911966be8..c7f3681e7 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/TemplateDataCollector.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/TemplateDataCollector.java @@ -17,6 +17,7 @@ import org.eclipse.jdt.core.dom.StringLiteral; import com.redhat.qute.commons.datamodel.DataModelParameter; +import com.redhat.qute.commons.datamodel.DataModelBaseTemplate; import com.redhat.qute.commons.datamodel.DataModelTemplate; /** @@ -47,9 +48,9 @@ */ public class TemplateDataCollector extends TemplateDataVisitor { - private final DataModelTemplate template; + private final DataModelBaseTemplate template; - public TemplateDataCollector(DataModelTemplate template, IProgressMonitor monitor) { + public TemplateDataCollector(DataModelBaseTemplate template, IProgressMonitor monitor) { this.template = template; } diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/TemplateDataSupport.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/TemplateDataSupport.java index 4d466a56c..23da31154 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/TemplateDataSupport.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/TemplateDataSupport.java @@ -25,7 +25,7 @@ import org.eclipse.lsp4j.Location; import com.redhat.qute.commons.datamodel.DataModelParameter; -import com.redhat.qute.commons.datamodel.DataModelTemplate; +import com.redhat.qute.commons.datamodel.DataModelBaseTemplate; import com.redhat.qute.jdt.utils.IJDTUtils; /** @@ -49,7 +49,7 @@ public class TemplateDataSupport { * @param monitor the progress monitor. */ public static void collectParametersFromDataMethodInvocation(IMember fieldOrMethod, - DataModelTemplate template, IProgressMonitor monitor) { + DataModelBaseTemplate template, IProgressMonitor monitor) { try { search(fieldOrMethod, new TemplateDataCollector(template, monitor), monitor); } catch (CoreException e) { diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/datamodel/CheckedTemplateSupport.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/datamodel/CheckedTemplateSupport.java index 30c00c892..51f47d42d 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/datamodel/CheckedTemplateSupport.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/datamodel/CheckedTemplateSupport.java @@ -12,11 +12,13 @@ package com.redhat.qute.jdt.internal.template.datamodel; import static com.redhat.qute.jdt.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION; +import static com.redhat.qute.jdt.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION_IGNORE_FRAGMENTS; import static com.redhat.qute.jdt.internal.QuteJavaConstants.OLD_CHECKED_TEMPLATE_ANNOTATION; import static com.redhat.qute.jdt.utils.JDTQuteProjectUtils.getTemplatePath; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; @@ -29,13 +31,17 @@ import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; +import com.redhat.qute.commons.datamodel.DataModelBaseTemplate; +import com.redhat.qute.commons.datamodel.DataModelFragment; import com.redhat.qute.commons.datamodel.DataModelParameter; import com.redhat.qute.commons.datamodel.DataModelTemplate; import com.redhat.qute.jdt.internal.resolver.ITypeResolver; import com.redhat.qute.jdt.internal.template.TemplateDataSupport; import com.redhat.qute.jdt.template.datamodel.AbstractAnnotationTypeReferenceDataModelProvider; import com.redhat.qute.jdt.template.datamodel.SearchContext; +import com.redhat.qute.jdt.utils.AnnotationUtils; import com.redhat.qute.jdt.utils.JDTTypeUtils; +import com.redhat.qute.jdt.utils.TemplatePathInfo; /** * CheckedTemplate support for template files: @@ -75,27 +81,54 @@ protected String[] getAnnotationNames() { } @Override - protected void processAnnotation(IJavaElement javaElement, IAnnotation annotation, String annotationName, - SearchContext context, IProgressMonitor monitor) throws JavaModelException { + protected void processAnnotation(IJavaElement javaElement, IAnnotation checkedTemplateAnnotation, + String annotationName, SearchContext context, IProgressMonitor monitor) throws JavaModelException { if (javaElement instanceof IType) { IType type = (IType) javaElement; - collectDataModelTemplateForCheckedTemplate(type, context.getTypeResolver(type), + boolean ignoreFragments = isIgnoreFragments(checkedTemplateAnnotation); + collectDataModelTemplateForCheckedTemplate(type, ignoreFragments, context.getTypeResolver(type), context.getDataModelProject().getTemplates(), monitor); } } + /** + * Returns true if @CheckedTemplate annotation declares that fragment must be + * ignored and false otherwise. + * + * + * @CheckedTemplate(ignoreFragments=true) + * + * + * @param checkedTemplateAnnotation the CheckedTemplate annotation. + * + * @return true if @CheckedTemplate annotation declares that fragment must be + * ignored and false otherwise. + */ + private static boolean isIgnoreFragments(IAnnotation checkedTemplateAnnotation) { + try { + Boolean ignoreFragments = AnnotationUtils.getAnnotationMemberValueAsBoolean(checkedTemplateAnnotation, + CHECKED_TEMPLATE_ANNOTATION_IGNORE_FRAGMENTS); + return ignoreFragments != null ? ignoreFragments.booleanValue() : false; + } catch (Exception e) { + // Do nothing + return false; + } + } + /** * Collect data model template from @CheckedTemplate. * - * @param type the Java type. - * @param typeResolver the Java type resolver. - * @param templates the data model templates to update with collect of - * template. - * @param monitor the progress monitor. + * @param type the Java type. + * @param ignoreFragments true if fragments must be ignored and false otherwise. + * @param typeResolver the Java type resolver. + * @param templates the data model templates to update with collect of + * template. + * @param monitor the progress monitor. * @throws JavaModelException */ - private static void collectDataModelTemplateForCheckedTemplate(IType type, ITypeResolver typeResolver, - List> templates, IProgressMonitor monitor) throws JavaModelException { + private static void collectDataModelTemplateForCheckedTemplate(IType type, boolean ignoreFragments, + ITypeResolver typeResolver, List> templates, IProgressMonitor monitor) + throws JavaModelException { boolean innerClass = type.getParent() != null && type.getParent().getElementType() == IJavaElement.TYPE; String className = !innerClass ? null : JDTTypeUtils.getSimpleClassName( @@ -106,28 +139,69 @@ private static void collectDataModelTemplateForCheckedTemplate(IType type, IType // method. IMethod[] methods = type.getMethods(); for (IMethod method : methods) { - DataModelTemplate template = createTemplateDataModel(method, className, type, - typeResolver, monitor); - templates.add(template); + + // src/main/resources/templates/${className}/${methodName}.qute.html + TemplatePathInfo templatePathInfo = getTemplatePath(className, method.getElementName(), ignoreFragments); + + // Get or create template + String templateUri = templatePathInfo.getTemplateUri(); + String fragmentId = templatePathInfo.getFragmentId(); + + DataModelTemplate template = null; + Optional> existingTemplate = templates.stream() + .filter(t -> t.getTemplateUri().equals(templateUri)) // + .findFirst(); + if (existingTemplate.isEmpty()) { + template = createTemplateDataModel(templateUri, method, type); + templates.add(template); + } else { + template = existingTemplate.get(); + if (fragmentId == null) { + template.setSourceMethod(method.getElementName()); + } + } + + if (fragmentId != null && fragmentId.length() > 0) { + // The method name has '$' to define fragment id (ex : foo$bar) + // Create fragment + DataModelFragment fragment = createFragmentDataModel(fragmentId, method, type); + template.addFragment(fragment); + // collect parameters for the fragment + collectParameters(method, typeResolver, fragment, monitor); + } else { + // collect parameters for the template + collectParameters(method, typeResolver, template, monitor); + } } } - private static DataModelTemplate createTemplateDataModel(IMethod method, String className, - IType type, ITypeResolver typeResolver, IProgressMonitor monitor) { - String methodName = method.getElementName(); - // src/main/resources/templates/${className}/${methodName}.qute.html - String templateUri = getTemplatePath(className, methodName); + private static DataModelTemplate createTemplateDataModel(String templateUri, IMethod method, + IType type) { // Create template data model with: // - template uri : Qute template file which must be bind with data model. // - source type : the Java class which defines Templates - // - + // - source method: : the Java method which defines Template DataModelTemplate template = new DataModelTemplate(); template.setParameters(new ArrayList<>()); template.setTemplateUri(templateUri); template.setSourceType(type.getFullyQualifiedName()); - template.setSourceMethod(methodName); + template.setSourceMethod(method.getElementName()); + return template; + } + private static DataModelFragment createFragmentDataModel(String fragmentId, IMethod method, + IType type) { + DataModelFragment template = new DataModelFragment(); + template.setParameters(new ArrayList<>()); + template.setId(fragmentId); + template.setSourceType(type.getFullyQualifiedName()); + template.setSourceMethod(method.getElementName()); + return template; + } + + public static void collectParameters(IMethod method, ITypeResolver typeResolver, + DataModelBaseTemplate templateOrFragment, IProgressMonitor monitor) { try { ILocalVariable[] parameters = method.getParameters(); if (parameters.length > 0) { @@ -135,7 +209,7 @@ private static DataModelTemplate createTemplateDataModel(IMe for (int i = 0; i < parameters.length; i++) { DataModelParameter parameter = createParameterDataModel(parameters[i], varargs && i == parameters.length - 1, typeResolver); - template.getParameters().add(parameter); + templateOrFragment.getParameters().add(parameter); } } } catch (Exception e) { @@ -143,8 +217,7 @@ private static DataModelTemplate createTemplateDataModel(IMe "Error while getting method template parameter of '" + method.getElementName() + "'.", e); } // Collect data parameters for the given template - TemplateDataSupport.collectParametersFromDataMethodInvocation(method, template, monitor); - return template; + TemplateDataSupport.collectParametersFromDataMethodInvocation(method, templateOrFragment, monitor); } private static DataModelParameter createParameterDataModel(ILocalVariable methodParameter, boolean varags, diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/datamodel/TemplateFieldSupport.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/datamodel/TemplateFieldSupport.java index 6ecc5ed30..f24da8b45 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/datamodel/TemplateFieldSupport.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/datamodel/TemplateFieldSupport.java @@ -113,13 +113,14 @@ private static void collectDataModelTemplateForTemplateField(IField field, templates.add(template); } - private static DataModelTemplate createTemplateDataModel(IField field, String locationFromConstructorParameter, - IProgressMonitor monitor) { + private static DataModelTemplate createTemplateDataModel(IField field, + String locationFromConstructorParameter, IProgressMonitor monitor) { - String location = locationFromConstructorParameter != null ? locationFromConstructorParameter : getLocation(field); + String location = locationFromConstructorParameter != null ? locationFromConstructorParameter + : getLocation(field); String fieldName = field.getElementName(); // src/main/resources/templates/${methodName}.qute.html - String templateUri = getTemplatePath(null, location != null ? location : fieldName); + String templateUri = getTemplatePath(null, location != null ? location : fieldName, true).getTemplateUri(); // Create template data model with: // - template uri : Qute template file which must be bind with data model. diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/AnnotationUtils.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/AnnotationUtils.java index 01343b1a7..7dadef470 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/AnnotationUtils.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/AnnotationUtils.java @@ -192,6 +192,24 @@ public static String getAnnotationMemberValue(IAnnotation annotation, String mem return null; } + /** + * Returns the value of the given member name of the given annotation. + * + * @param annotation the annotation. + * @param memberName the member name. + * @return the value of the given member name of the given annotation. + * @throws JavaModelException + */ + public static Boolean getAnnotationMemberValueAsBoolean(IAnnotation annotation, String memberName) + throws JavaModelException { + for (IMemberValuePair pair : annotation.getMemberValuePairs()) { + if (memberName.equals(pair.getMemberName())) { + return getValueAsBoolean(pair); + } + } + return null; + } + public static String getValueAsString(IMemberValuePair pair) { return pair.getValue() != null ? pair.getValue().toString() : null; } @@ -246,4 +264,14 @@ public static Expression getAnnotationMemberValueExpression(Annotation annotatio return null; } + public static Boolean getBoolean(Expression expression) { + if (expression == null) { + return null; + } + Object expressionValue = expression.resolveConstantExpressionValue(); + if (expressionValue instanceof Boolean) { + return (Boolean) expressionValue; + } + return null; + } } diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/JDTQuteProjectUtils.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/JDTQuteProjectUtils.java index 53059f141..1cdacaeae 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/JDTQuteProjectUtils.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/JDTQuteProjectUtils.java @@ -84,13 +84,22 @@ public static boolean hasQuteSupport(IJavaProject javaProject) { return JDTTypeUtils.findType(javaProject, QuteJavaConstants.ENGINE_BUILDER_CLASS) != null; } - public static String getTemplatePath(String className, String methodOrFieldName) { - StringBuilder path = new StringBuilder(TEMPLATES_BASE_DIR); + public static TemplatePathInfo getTemplatePath(String className, String methodOrFieldName, boolean ignoreFragments) { + String fragmentId = null; + StringBuilder templateUri = new StringBuilder(TEMPLATES_BASE_DIR); if (className != null) { - path.append(className); - path.append('/'); + templateUri.append(className); + templateUri.append('/'); + if (!ignoreFragments) { + int fragmentIndex = methodOrFieldName != null ? methodOrFieldName.lastIndexOf('$') : -1; + if (fragmentIndex != -1) { + fragmentId = methodOrFieldName.substring(fragmentIndex + 1, methodOrFieldName.length()); + methodOrFieldName = methodOrFieldName.substring(0, fragmentIndex); + } + } } - return path.append(methodOrFieldName).toString(); + templateUri.append(methodOrFieldName); + return new TemplatePathInfo(templateUri.toString(), fragmentId); } public static CompilationUnit getASTRoot(ITypeRoot typeRoot) { diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/TemplatePathInfo.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/TemplatePathInfo.java new file mode 100644 index 000000000..8141da5a5 --- /dev/null +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/TemplatePathInfo.java @@ -0,0 +1,75 @@ +/******************************************************************************* +* Copyright (c) 2023 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.qute.jdt.utils; + +import org.apache.commons.lang3.StringUtils; + +/** + * Template path information which stores : + * + *
    + *
  • the template Uri
  • + *
  • the fragment if or null
  • + *
+ * + * @author Angelo ZERR + * + */ +public class TemplatePathInfo { + + private final String templateUri; + + private final String fragmentId; + + public TemplatePathInfo(String templateUri, String fragmentId) { + this.templateUri = templateUri; + this.fragmentId = fragmentId; + } + + /** + * Returns the template Uri. + * + * @return the template Uri. + */ + public String getTemplateUri() { + return templateUri; + } + + /** + * Returns the fragment id and null otherwise. + * + * @return the fragment id and null otherwise. + */ + public String getFragmentId() { + return fragmentId; + } + + /** + * Returns true if a fragment id is defined and false otherwise. + * + * @return true if a fragment id is defined and false otherwise. + */ + public boolean hasFragment() { + return StringUtils.isNotEmpty(fragmentId); + } + + /** + * Returns true if fragment is null or non empty and false otherwise. + * + * @return true if fragment is null or non empty and false otherwise. + */ + public boolean isValid() { + // A fragment cannot be empty + return (fragmentId == null || hasFragment()); + } + +} diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelBaseTemplate.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelBaseTemplate.java new file mode 100644 index 000000000..4280e3da6 --- /dev/null +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelBaseTemplate.java @@ -0,0 +1,137 @@ +/******************************************************************************* +* Copyright (c) 2023 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.qute.commons.datamodel; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Base class for data model fragment / template. + * + * @param data model parameter. + * + * @see Fragments + * @see Type-safe + * Fragments + * + * @author Angelo ZERR + */ + +public class DataModelBaseTemplate { + + private String sourceType; + + private String sourceMethod; + + private List parameters; + + private transient Map parametersMap; + + /** + * Returns the Java source type where this data model template is defined. + * + * @return the Java source type where this data model template is defined. + */ + public String getSourceType() { + return sourceType; + } + + /** + * Set the Java source type where this data model template is defined. + * + * @param sourceType the Java source type where this data model template is + * defined. + */ + public void setSourceType(String sourceType) { + this.sourceType = sourceType; + } + + /** + * Returns the Java source method where this data model template is defined and + * null otherwise. + * + * @return the Java source method where this data model template is defined and + * null otherwise. + */ + public String getSourceMethod() { + return sourceMethod; + } + + /** + * Set the Java source method where this data model template is defined and null + * otherwise. + * + * @param sourceMethod the Java source method where this data model template is + * defined and null otherwise. + */ + public void setSourceMethod(String sourceMethod) { + this.sourceMethod = sourceMethod; + } + + /** + * Returns the list of data model parameters. + * + * @return the list of data model parameters. + */ + public List getParameters() { + return parameters; + } + + /** + * Set the list of data model parameters. + * + * @param parameters the list of data model parameters. + */ + public void setParameters(List parameters) { + this.parameters = parameters; + } + + /** + * Returns the parameter from the given key and null otherwise. + * + * @param key the parameter key. + * + * @return the parameter from the given key and null otherwise. + */ + public T getParameter(String key) { + if (parameters == null) { + return null; + } + return getParametersMap().get(key); + } + + /** + * Add the given parameter. + * + * @param parameter the parameter to add. + */ + public void addParameter(T parameter) { + if (parameters == null) { + parameters = new ArrayList<>(); + } + parameters.add(parameter); + getParametersMap().put(parameter.getKey(), parameter); + } + + private Map getParametersMap() { + if (parametersMap == null) { + parametersMap = parameters.stream() + .collect(Collectors.toMap(DataModelParameter::getKey, Function.identity())); + } + return parametersMap; + } +} diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelFragment.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelFragment.java new file mode 100644 index 000000000..ed287602d --- /dev/null +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelFragment.java @@ -0,0 +1,59 @@ +/******************************************************************************* +* Copyright (c) 2023 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.qute.commons.datamodel; + +import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; + +/** + * Data model fragment hosts informations about the expected data model + * (parameters) for a given fragment. + * + * @param data model parameter. + * + * @see Fragments + * @see Type-safe + * Fragments + * + * @author Angelo ZERR + */ +public class DataModelFragment extends DataModelBaseTemplate { + + private String id; + + /** + * Returns the fragment id. + * + * @return the fragment id. + */ + public String getId() { + return id; + } + + /** + * Set the fragment id. + * + * @param id the fragment id + */ + public void setId(String id) { + this.id = id; + } + + @Override + public String toString() { + ToStringBuilder b = new ToStringBuilder(this); + b.add("id", this.id); + b.add("parameters", this.getParameters()); + return b.toString(); + } +} diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelTemplate.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelTemplate.java index 34e68d04e..327794604 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelTemplate.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelTemplate.java @@ -13,9 +13,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; @@ -23,23 +20,17 @@ * Data model template host informations about the expected data model * (parameters) for a given template. * - * @author Angelo ZERR - * * @param data model parameter. + * + * @author Angelo ZERR */ -public class DataModelTemplate { +public class DataModelTemplate extends DataModelBaseTemplate { private String templateUri; - private String sourceType; - - private String sourceMethod; - private String sourceField; - - private List parameters; - private transient Map parametersMap; + private List> fragments; /** * Returns the template Uri. @@ -59,47 +50,6 @@ public void setTemplateUri(String templateUri) { this.templateUri = templateUri; } - /** - * Returns the Java source type where this data model template is defined. - * - * @return the Java source type where this data model template is defined. - */ - public String getSourceType() { - return sourceType; - } - - /** - * Set the Java source type where this data model template is defined. - * - * @param sourceType the Java source type where this data model template is - * defined. - */ - public void setSourceType(String sourceType) { - this.sourceType = sourceType; - } - - /** - * Returns the Java source method where this data model template is defined and - * null otherwise. - * - * @return the Java source method where this data model template is defined and - * null otherwise. - */ - public String getSourceMethod() { - return sourceMethod; - } - - /** - * Set the Java source method where this data model template is defined and null - * otherwise. - * - * @param sourceMethod the Java source method where this data model template is - * defined and null otherwise. - */ - public void setSourceMethod(String sourceMethod) { - this.sourceMethod = sourceMethod; - } - /** * Returns the Java source field where this data model template is defined and * null otherwise. @@ -123,62 +73,69 @@ public void setSourceField(String sourceField) { } /** - * Returns the list of data model parameters. + * Add the given fragment. + * + * @param fragment the fragment to add. + */ + public void addFragment(DataModelFragment fragment) { + if (fragments == null) { + fragments = new ArrayList<>(); + } + fragments.add(fragment); + } + + /** + * Returns list of fragments and null otherwise. * - * @return the list of data model parameters. + * @return list of fragments and null otherwise. */ - public List getParameters() { - return parameters; + public List> getFragments() { + return fragments; } /** - * Set the list of data model parameters. + * Set the fragment list. * - * @param parameters the list of data model parameters. + * @param fragments the fragment list. */ - public void setParameters(List parameters) { - this.parameters = parameters; + public void setFragments(List> fragments) { + this.fragments = fragments; } /** - * Returns the parameter from the given key and null otherwise. + * Returns the fragment identified by the given id fragmentId and + * null otherwise. * - * @param key the parameter key. + * @param fragmentId the fragment id. * - * @return the parameter from the given key and null otherwise. + * @return the fragment identified by the given id fragmentId and + * null otherwise. */ - public T getParameter(String key) { - List parameters = getParameters(); - if (parameters == null) { + public DataModelFragment getFragment(String fragmentId) { + if (fragmentId == null) { return null; } - return getParametersMap().get(key); - } - - public void addParameter(T parameter) { - if (parameters == null) { - parameters = new ArrayList<>(); + List> fragments = getFragments(); + if (fragments == null || fragments.isEmpty()) { + return null; } - parameters.add(parameter); - getParametersMap().put(parameter.getKey(), parameter); - } - - private Map getParametersMap() { - if (parametersMap == null) { - parametersMap = parameters.stream() - .collect(Collectors.toMap(DataModelParameter::getKey, Function.identity())); + for (DataModelFragment fragment : fragments) { + if (fragmentId.equals(fragment.getId())) { + return fragment; + } } - return parametersMap; + return null; } @Override public String toString() { ToStringBuilder b = new ToStringBuilder(this); b.add("templateUri", this.templateUri); - b.add("sourceType", this.sourceType); - b.add("sourceMethod", this.sourceMethod); + b.add("sourceType", this.getSourceType()); + b.add("sourceMethod", this.getSourceMethod()); b.add("sourceField", this.sourceField); - b.add("parameters", this.parameters); + b.add("parameters", this.getParameters()); + b.add("fragments", this.getFragments()); return b.toString(); } } diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/sections/FragmentSection.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/sections/FragmentSection.java index c2c0cd0e8..ca4674c6c 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/sections/FragmentSection.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/sections/FragmentSection.java @@ -60,6 +60,33 @@ public SectionKind getSectionKind() { return SectionKind.FRAGMENT; } + /** + * Returns the fragment id and null otherwise. + * + * @return the fragment id and null otherwise. + */ + public String getId() { + Parameter id = getIdParameter(); + if (id != null) { + return id.getValue(); + } + return null; + } + + /** + * Returns the AST fragment id parameter and null otherwise. + * + * @return the AST fragment id parameter and null otherwise. + */ + public Parameter getIdParameter() { + for (Parameter parameter : getParameters()) { + if (ID.equals(parameter.getName())) { + return parameter; + } + } + return null; + } + @Override public ParametersInfo getParametersInfo() { return PARAMETER_INFOS; diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/DataModelSourceProvider.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/DataModelSourceProvider.java new file mode 100644 index 000000000..4fa6a0665 --- /dev/null +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/DataModelSourceProvider.java @@ -0,0 +1,36 @@ +/******************************************************************************* +* Copyright (c) 2023 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.qute.project.datamodel; + +import java.util.List; + +import com.redhat.qute.commons.QuteJavaDefinitionParams; + +/** + * Data model source provider API implemented by data model template / fragment. + * + * @author Angelo ZERR + * + */ +public interface DataModelSourceProvider { + + String getSourceType(); + + String getSourceField(); + + String getSourceMethod(); + + QuteJavaDefinitionParams toJavaDefinitionParams(String projectUri); + + List getParameters(); + +} diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelFragment.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelFragment.java new file mode 100644 index 000000000..f7e4ddd0b --- /dev/null +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelFragment.java @@ -0,0 +1,51 @@ +/******************************************************************************* +* Copyright (c) 2023 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.qute.project.datamodel; + +import com.redhat.qute.commons.QuteJavaDefinitionParams; +import com.redhat.qute.commons.datamodel.DataModelFragment; +import com.redhat.qute.commons.datamodel.DataModelParameter; + +/** + * Data model fragment which implements {@link DataModelSourceProvider} used to + * go to the Java definition of the fragment. + * + * @author Angelo ZERR + * + */ +public class ExtendedDataModelFragment extends DataModelFragment + implements DataModelSourceProvider { + + public ExtendedDataModelFragment(DataModelFragment fragment) { + super.setId(fragment.getId()); + super.setSourceType(fragment.getSourceType()); + super.setSourceMethod(fragment.getSourceMethod()); + super.setParameters(ExtendedDataModelTemplate.createParameters(fragment.getParameters(), this)); + } + + @Override + public QuteJavaDefinitionParams toJavaDefinitionParams(String projectUri) { + String sourceType = getSourceType(); + String sourceField = null; + String sourceMethod = getSourceMethod(); + + QuteJavaDefinitionParams params = new QuteJavaDefinitionParams(sourceType, projectUri); + params.setSourceField(sourceField); + params.setSourceMethod(sourceMethod); + return params; + } + + @Override + public String getSourceField() { + return null; + } +} diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelParameter.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelParameter.java index d48b78a8c..b8b2011e9 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelParameter.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelParameter.java @@ -18,9 +18,9 @@ public class ExtendedDataModelParameter extends DataModelParameter implements JavaTypeInfoProvider { - private final ExtendedDataModelTemplate template; + private final DataModelSourceProvider template; - public ExtendedDataModelParameter(DataModelParameter parameter, ExtendedDataModelTemplate template) { + public ExtendedDataModelParameter(DataModelParameter parameter, DataModelSourceProvider template) { super.setKey(parameter.getKey()); super.setSourceType(parameter.getSourceType()); super.setDataMethodInvocation(parameter.isDataMethodInvocation()); @@ -37,12 +37,12 @@ public Node getJavaTypeOwnerNode() { return null; } - public ExtendedDataModelTemplate getTemplate() { + private DataModelSourceProvider getTemplate() { return template; } public QuteJavaDefinitionParams toJavaDefinitionParams(String projectUri) { - ExtendedDataModelTemplate dataModelTemplate = getTemplate(); + DataModelSourceProvider dataModelTemplate = getTemplate(); String sourceType = dataModelTemplate.getSourceType(); String sourceField = dataModelTemplate.getSourceField(); String sourceMethod = dataModelTemplate.getSourceMethod(); diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelTemplate.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelTemplate.java index c3a004d2c..53b20cd21 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelTemplate.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelTemplate.java @@ -16,10 +16,12 @@ import java.util.stream.Collectors; import com.redhat.qute.commons.QuteJavaDefinitionParams; +import com.redhat.qute.commons.datamodel.DataModelFragment; import com.redhat.qute.commons.datamodel.DataModelParameter; import com.redhat.qute.commons.datamodel.DataModelTemplate; -public class ExtendedDataModelTemplate extends DataModelTemplate { +public class ExtendedDataModelTemplate extends DataModelTemplate + implements DataModelSourceProvider { public ExtendedDataModelTemplate(DataModelTemplate template) { super.setTemplateUri(template.getTemplateUri()); @@ -27,10 +29,22 @@ public ExtendedDataModelTemplate(DataModelTemplate template) super.setSourceMethod(template.getSourceMethod()); super.setSourceField(template.getSourceField()); super.setParameters(createParameters(template.getParameters(), this)); + super.setFragments(createFragments(template.getFragments(), this)); } - private List createParameters(List parameters, + private List> createFragments( + List> fragments, ExtendedDataModelTemplate template) { + if (fragments == null) { + return Collections.emptyList(); + } + return fragments.stream() // + .map(fragment -> new ExtendedDataModelFragment(fragment)) // + .collect(Collectors.toList()); + } + + protected static List createParameters(List parameters, + DataModelSourceProvider template) { if (parameters == null) { return Collections.emptyList(); } @@ -39,6 +53,7 @@ private List createParameters(List> getCodelens(Template template cancelChecker.checkCanceled(); List lenses = new ArrayList<>(); - // #insert code lens references - QuteProject project = template.getProject(); - collectInsertCodeLenses(template, template, project, lenses, cancelChecker); + // Collect checked template code lenses at the root of the template + collectDataModelFoTemplateCodeLenses(templateDataModel, template, settings, lenses, cancelChecker); - // checked template code lenses - collectDataModelCodeLenses(templateDataModel, template, settings, lenses, cancelChecker); + // Visit AST template to collect codelenses: + // * for #insert + // * for #fragment + QuteProject project = template.getProject(); + collectCodeLenses(templateDataModel, template, template, settings, project, lenses, + cancelChecker); if (UserTagUtils.isUserTag(template)) { // Template is an user tag @@ -77,7 +82,15 @@ public CompletableFuture> getCodelens(Template template }); } - private static void collectDataModelCodeLenses(ExtendedDataModelTemplate templateDataModel, Template template, + private static void collectDataModelFoTemplateCodeLenses(DataModelSourceProvider templateDataModel, + Template template, + SharedSettings settings, List lenses, CancelChecker cancelChecker) { + collectDataModelCodeLenses(LEFT_TOP_RANGE, templateDataModel, template.getProjectUri(), settings, lenses, + cancelChecker); + } + + private static void collectDataModelCodeLenses(Range range, DataModelSourceProvider templateDataModel, + String projectUri, SharedSettings settings, List lenses, CancelChecker cancelChecker) { if (templateDataModel == null || templateDataModel.getSourceType() == null) { return; @@ -85,14 +98,11 @@ private static void collectDataModelCodeLenses(ExtendedDataModelTemplate templat cancelChecker.checkCanceled(); - String projectUri = template.getProjectUri(); - boolean canSupportJavaDefinition = settings.getCommandCapabilities() .isCommandSupported(COMMAND_JAVA_DEFINITION); // Method/Field which is bound with the template String title = createCheckedTemplateTitle(templateDataModel); - Range range = LEFT_TOP_RANGE; Command command = !canSupportJavaDefinition ? new Command(title, "") : new Command(title, COMMAND_JAVA_DEFINITION, Arrays.asList(templateDataModel.toJavaDefinitionParams(projectUri))); @@ -121,7 +131,7 @@ private static String createParameterTitle(ExtendedDataModelParameter parameter) return title.toString(); } - private static String createCheckedTemplateTitle(DataModelTemplate dataModel) { + private static String createCheckedTemplateTitle(DataModelSourceProvider dataModel) { String className = dataModel.getSourceType(); int index = className.lastIndexOf('.'); className = className.substring(index + 1, className.length()); @@ -136,35 +146,63 @@ private static String createCheckedTemplateTitle(DataModelTemplate dataModel) return title.toString(); } - private static void collectInsertCodeLenses(Node parent, Template template, QuteProject project, + private static void collectCodeLenses(ExtendedDataModelTemplate templateDataModel, Node parent, + Template template, SharedSettings settings, QuteProject project, List lenses, CancelChecker cancelChecker) { cancelChecker.checkCanceled(); if (parent.getKind() == NodeKind.Section) { Section section = (Section) parent; - if (section.getSectionKind() == SectionKind.INSERT) { - - if (project != null) { - Parameter parameter = section.getParameterAtIndex(0); - if (parameter != null) { - String tag = parameter.getValue(); - // TODO : implement findNbreferencesOfInsertTag correctly - int nbReferences = 0; // project.findNbreferencesOfInsertTag(template.getTemplateId(), tag); - if (nbReferences > 0) { - String title = nbReferences == 1 ? "1 reference" : nbReferences + " references"; - Range range = QutePositionUtility.createRange(parameter); - Command command = new Command(title, ""); - CodeLens codeLens = new CodeLens(range, command, null); - lenses.add(codeLens); - } - } - } - + switch (section.getSectionKind()) { + case INSERT: + collectInsertCodeLens(project, section, lenses); + break; + case FRAGMENT: + collectFragmentCodeLens(templateDataModel, section, settings, project, lenses, cancelChecker); + break; + default: } - } List children = parent.getChildren(); for (Node node : children) { - collectInsertCodeLenses(node, template, project, lenses, cancelChecker); + collectCodeLenses(templateDataModel, node, template, settings, project, lenses, cancelChecker); + } + } + + private static void collectFragmentCodeLens(ExtendedDataModelTemplate templateDataModel, Section section, + SharedSettings settings, QuteProject project, List lenses, CancelChecker cancelChecker) { + if (templateDataModel == null) { + return; + } + FragmentSection fragment = (FragmentSection) section; + String fragmentId = fragment.getId(); + if (StringUtils.isEmpty(fragmentId)) { + return; + } + ExtendedDataModelFragment fragmentDataModel = (ExtendedDataModelFragment) templateDataModel + .getFragment(fragmentId); + if (fragmentDataModel == null) { + return; + } + Range range = QutePositionUtility.selectStartTagName(section); + collectDataModelCodeLenses(range, fragmentDataModel, project.getUri(), settings, lenses, + cancelChecker); + } + + public static void collectInsertCodeLens(QuteProject project, Section section, List lenses) { + if (project != null) { + Parameter parameter = section.getParameterAtIndex(0); + if (parameter != null) { + String tag = parameter.getValue(); + // TODO : implement findNbreferencesOfInsertTag correctly + int nbReferences = 0; // project.findNbreferencesOfInsertTag(template.getTemplateId(), tag); + if (nbReferences > 0) { + String title = nbReferences == 1 ? "1 reference" : nbReferences + " references"; + Range range = QutePositionUtility.createRange(parameter); + Command command = new Command(title, ""); + CodeLens codeLens = new CodeLens(range, command, null); + lenses.add(codeLens); + } + } } } diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/QuteQuickStartProject.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/QuteQuickStartProject.java index 1ef961ec5..0c1f7d326 100644 --- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/QuteQuickStartProject.java +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/QuteQuickStartProject.java @@ -25,6 +25,7 @@ import com.redhat.qute.commons.ResolvedJavaTypeInfo; import com.redhat.qute.commons.annotations.RegisterForReflectionAnnotation; import com.redhat.qute.commons.annotations.TemplateDataAnnotation; +import com.redhat.qute.commons.datamodel.DataModelFragment; import com.redhat.qute.commons.datamodel.DataModelParameter; import com.redhat.qute.commons.datamodel.DataModelTemplate; import com.redhat.qute.commons.datamodel.resolvers.NamespaceResolverInfo; @@ -44,8 +45,9 @@ public class QuteQuickStartProject extends MockQuteProject { public final static String PROJECT_URI = "qute-quickstart"; public static final String ITEMRESOURCE_ITEMS_TEMPLATE_URI = "src/main/resources/templates/ItemResource/items"; + public static final String ITEMRESOURCE_ITEMS_WITH_FRAGMENTS_TEMPLATE_URI = "src/main/resources/templates/ItemResourceWithFragments/items"; public static final String NATIVEITEMRESOURCE_ITEMS_TEMPLATE_URI = "src/main/resources/templates/NativeItemResource/items"; - + public QuteQuickStartProject(ProjectInfo projectInfo, QuteDataModelProjectProvider dataModelProvider, QuteUserTagProvider tagProvider) { super(projectInfo, dataModelProvider, tagProvider); @@ -162,8 +164,10 @@ private void createSourceTypes(List cache) { registerField("review : org.acme.Review", item); JavaMemberInfo itemIsAvailableMethod = registerMethod("isAvailable() : java.lang.Boolean", item); itemIsAvailableMethod.setDocumentation("Returns true if the item is available and false otherwise"); - JavaMemberInfo itemIsAvailableMethodOverload = registerMethod("isAvailable(index : int) : java.lang.Boolean", item); - itemIsAvailableMethodOverload.setDocumentation("Returns true if the item at the given index is available and false otherwise"); + JavaMemberInfo itemIsAvailableMethodOverload = registerMethod("isAvailable(index : int) : java.lang.Boolean", + item); + itemIsAvailableMethodOverload + .setDocumentation("Returns true if the item at the given index is available and false otherwise"); registerMethod("getReview2() : org.acme.Review", item); // Override BaseItem#getReviews() registerMethod("getReviews() : java.util.List", item); @@ -180,13 +184,16 @@ private void createSourceTypes(List cache) { registerMethod("convert() : java.lang.String", classA); registerField("name : java.lang.String", classA); - ResolvedJavaTypeInfo classAWithGeneric = createResolvedJavaTypeInfo("org.acme.qute.cyclic.ClassAWithGeneric", cache, false, + ResolvedJavaTypeInfo classAWithGeneric = createResolvedJavaTypeInfo("org.acme.qute.cyclic.ClassAWithGeneric", + cache, false, "org.acme.qute.cyclic.ClassCWithGeneric"); - createResolvedJavaTypeInfo("org.acme.qute.cyclic.ClassBWithGeneric", cache, false, "org.acme.qute.cyclic.ClassAWithGeneric"); - createResolvedJavaTypeInfo("org.acme.qute.cyclic.ClassCWithGeneric", cache, false, "org.acme.qute.cyclic.ClassBWithGeneric"); + createResolvedJavaTypeInfo("org.acme.qute.cyclic.ClassBWithGeneric", cache, false, + "org.acme.qute.cyclic.ClassAWithGeneric"); + createResolvedJavaTypeInfo("org.acme.qute.cyclic.ClassCWithGeneric", cache, false, + "org.acme.qute.cyclic.ClassBWithGeneric"); registerMethod("convert() : java.lang.String", classAWithGeneric); registerField("name : java.lang.String", classAWithGeneric); - + // org.acme.MachineStatus ResolvedJavaTypeInfo machineStatus = createResolvedJavaTypeInfo("org.acme.MachineStatus", cache, false); machineStatus.setJavaTypeKind(JavaTypeKind.Enum); @@ -291,6 +298,7 @@ protected List> createTemplates() { } private static void createItemsTemplate(List> templates) { + // Simple template DataModelTemplate template = new DataModelTemplate(); template.setTemplateUri(ITEMRESOURCE_ITEMS_TEMPLATE_URI); template.setSourceType("org.acme.qute.ItemResource$Templates"); @@ -302,6 +310,23 @@ private static void createItemsTemplate(List"); template.addParameter(parameter); + + // Template with fragments + DataModelTemplate templateWithFragment = new DataModelTemplate(); + templateWithFragment.setTemplateUri(ITEMRESOURCE_ITEMS_WITH_FRAGMENTS_TEMPLATE_URI); + templateWithFragment.setSourceType("org.acme.qute.ItemResourceWithFragments$Templates"); + templateWithFragment.setSourceMethod("items"); + templates.add(templateWithFragment); + + DataModelFragment fragment = new DataModelFragment<>(); + fragment.setId("id2"); + fragment.setSourceType("org.acme.qute.ItemResourceWithFragments$Templates"); + fragment.setSourceMethod("items$id2"); + fragment.addParameter(parameter); + templateWithFragment.setFragments(Arrays.asList(fragment)); + + // ItemResource$Templates#items(Item item) + templateWithFragment.addParameter(parameter); } private static void createItemsNativeTemplate(List> templates) { diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/codelens/QuteCodeLensForDataModelFragmentTest.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/codelens/QuteCodeLensForDataModelFragmentTest.java new file mode 100644 index 000000000..43769b55a --- /dev/null +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/codelens/QuteCodeLensForDataModelFragmentTest.java @@ -0,0 +1,93 @@ +/******************************************************************************* +* Copyright (c) 2023 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.qute.services.codelens; + +import static com.redhat.qute.QuteAssert.cl; +import static com.redhat.qute.QuteAssert.r; +import static com.redhat.qute.QuteAssert.testCodeLensFor; + +import org.junit.jupiter.api.Test; + +import com.redhat.qute.services.commands.QuteClientCommandConstants; + +/** + * Tests for Qute code lens and data model for fragment. + * + * @author Angelo ZERR + * + */ +public class QuteCodeLensForDataModelFragmentTest { + + @Test + public void noCheckedTemplateMatching() throws Exception { + String value = "{#fragment }\r\n" + + " \r\n" + + "{/fragment}\r\n" + + "\r\n" + + "{#fragment id=id2 }\r\n" + + " \r\n" + + "{/fragment}\r\n" + + "\r\n" + + "{#fragment id=id3 }\r\n" + + " \r\n" + + "{/fragment}"; + testCodeLensFor(value, "src/main/resources/templates/ItemResourceWithFragments/XXXXXXXXXXX.qute.html"); + testCodeLensFor(value, "src/main/resources/templates/ItemResourceWithFragments/items.XXXXXXXXXXX.html"); + } + + @Test + public void checkedTemplateMatching() throws Exception { + // Display information about data model (classes and parameters) as codelens. + String value = "{#fragment }\r\n" + + " \r\n" + + "{/fragment}\r\n" + + "\r\n" + + "{#fragment id=id2 }\r\n" + + " \r\n" + + "{/fragment}\r\n" + + "\r\n" + + "{#fragment id=id3 }\r\n" + + " \r\n" + + "{/fragment}"; + testCodeLensFor(value, "src/main/resources/templates/ItemResourceWithFragments/items.qute.html", // + cl(r(0, 0, 0, 0), "ItemResourceWithFragments$Templates#items(...)", + QuteClientCommandConstants.COMMAND_JAVA_DEFINITION), // + cl(r(0, 0, 0, 0), "items : List", QuteClientCommandConstants.COMMAND_JAVA_DEFINITION), + cl(r(4, 1, 4, 10), "ItemResourceWithFragments$Templates#items$id2(...)", + QuteClientCommandConstants.COMMAND_JAVA_DEFINITION), // + cl(r(4, 1, 4, 10), "items : List", QuteClientCommandConstants.COMMAND_JAVA_DEFINITION)); + + testCodeLensFor(value, "src/main/resources/templates/ItemResourceWithFragments/items", // + cl(r(0, 0, 0, 0), "ItemResourceWithFragments$Templates#items(...)", + QuteClientCommandConstants.COMMAND_JAVA_DEFINITION), // + cl(r(0, 0, 0, 0), "items : List", QuteClientCommandConstants.COMMAND_JAVA_DEFINITION), + cl(r(4, 1, 4, 10), "ItemResourceWithFragments$Templates#items$id2(...)", + QuteClientCommandConstants.COMMAND_JAVA_DEFINITION), // + cl(r(4, 1, 4, 10), "items : List", QuteClientCommandConstants.COMMAND_JAVA_DEFINITION)); + + testCodeLensFor(value, "src/main/resources/templates/ItemResourceWithFragments/items.qute", // + cl(r(0, 0, 0, 0), "ItemResourceWithFragments$Templates#items(...)", + QuteClientCommandConstants.COMMAND_JAVA_DEFINITION), // + cl(r(0, 0, 0, 0), "items : List", QuteClientCommandConstants.COMMAND_JAVA_DEFINITION), + cl(r(4, 1, 4, 10), "ItemResourceWithFragments$Templates#items$id2(...)", + QuteClientCommandConstants.COMMAND_JAVA_DEFINITION), // + cl(r(4, 1, 4, 10), "items : List", QuteClientCommandConstants.COMMAND_JAVA_DEFINITION)); + + testCodeLensFor(value, "src/main/resources/templates/ItemResourceWithFragments/items.html", // + cl(r(0, 0, 0, 0), "ItemResourceWithFragments$Templates#items(...)", + QuteClientCommandConstants.COMMAND_JAVA_DEFINITION), // + cl(r(0, 0, 0, 0), "items : List", QuteClientCommandConstants.COMMAND_JAVA_DEFINITION), + cl(r(4, 1, 4, 10), "ItemResourceWithFragments$Templates#items$id2(...)", + QuteClientCommandConstants.COMMAND_JAVA_DEFINITION), // + cl(r(4, 1, 4, 10), "items : List", QuteClientCommandConstants.COMMAND_JAVA_DEFINITION)); + } +} diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/codelens/QuteCodeLensForDataModelTest.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/codelens/QuteCodeLensForDataModelTemplateTest.java similarity index 93% rename from qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/codelens/QuteCodeLensForDataModelTest.java rename to qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/codelens/QuteCodeLensForDataModelTemplateTest.java index b613eb33d..8f80f05dc 100644 --- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/codelens/QuteCodeLensForDataModelTest.java +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/codelens/QuteCodeLensForDataModelTemplateTest.java @@ -20,12 +20,12 @@ import com.redhat.qute.services.commands.QuteClientCommandConstants; /** - * Tests for Qute code lens and data model. + * Tests for Qute code lens and data model for template. * * @author Angelo ZERR * */ -public class QuteCodeLensForDataModelTest { +public class QuteCodeLensForDataModelTemplateTest { @Test public void noCheckedTemplateMatching() throws Exception {