From 4bc8ce5b72b11a3fffecf17f4b37a2702e0ab871 Mon Sep 17 00:00:00 2001 From: azerr Date: Fri, 18 Oct 2024 13:55:12 +0200 Subject: [PATCH] TemplateExtension match any support Signed-off-by: azerr --- .../QuteCompletionsForExpression.java | 40 +- .../redhat/qute/project/BaseQuteProject.java | 114 +++++ .../qute/project/MockQuteProjectRegistry.java | 4 + .../qute/project/QuteQuickStartProject.java | 99 +--- .../qute/project/roq/RoqCollection.json | 33 ++ .../qute/project/roq/RoqCollections.json | 46 ++ .../redhat/qute/project/roq/RoqDataModel.json | 461 ++++++++++++++++++ .../redhat/qute/project/roq/RoqProject.java | 71 +++ .../com/redhat/qute/project/roq/Site.json | 76 +++ .../completions/roq/RoqCompletionsTest.java | 118 +++++ 10 files changed, 962 insertions(+), 100 deletions(-) create mode 100644 qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/BaseQuteProject.java create mode 100644 qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqCollection.json create mode 100644 qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqCollections.json create mode 100644 qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqDataModel.json create mode 100644 qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqProject.java create mode 100644 qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/Site.json create mode 100644 qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/completions/roq/RoqCompletionsTest.java diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/completions/QuteCompletionsForExpression.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/completions/QuteCompletionsForExpression.java index 32dbde3cc..4acf2d1bb 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/completions/QuteCompletionsForExpression.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/completions/QuteCompletionsForExpression.java @@ -247,17 +247,49 @@ private CompletableFuture doCompleteExpressionForMemberPart(Part } Part previousPart = parts.getPreviousPart(part); return project.resolveJavaType(previousPart) // - .thenApply(resolvedType -> { + .thenCompose(resolvedType -> { cancelChecker.checkCanceled(); if (!isValidJavaType(resolvedType)) { - return EMPTY_COMPLETION; + Part p = parts.getPreviousPart(previousPart); + if (p != null) { + return project.resolveJavaType(p) // + .thenCompose(resolvedType2 -> { + cancelChecker.checkCanceled(); + if (resolvedType2 == null) { + return EMPTY_FUTURE_COMPLETION; + } + List resolvers = project.getResolversFor(resolvedType2); + for (MethodValueResolver method : resolvers) { + if (ValueResolver.MATCH_NAME_ANY.equals(method.getMatchName()) + && !method.isVoidMethod()) { + String returnType = method.getReturnType(); + return project.resolveJavaType(returnType) // + .thenApply(r -> { + cancelChecker.checkCanceled(); + if (r == null) { + return EMPTY_COMPLETION; + } + return doCompleteForJavaTypeMembers(r, start, end, template, + project, + infixNotation, completionSettings, + formattingSettings, + nativeImagesSettings); + }); + } + } + return EMPTY_FUTURE_COMPLETION; + }); + } +; + return EMPTY_FUTURE_COMPLETION; } // Completion for member of the given Java class // ex : org.acme.Item - return doCompleteForJavaTypeMembers(resolvedType, start, end, template, project, - infixNotation, completionSettings, formattingSettings, nativeImagesSettings); + return CompletableFuture + .completedFuture(doCompleteForJavaTypeMembers(resolvedType, start, end, template, project, + infixNotation, completionSettings, formattingSettings, nativeImagesSettings)); }); } diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/BaseQuteProject.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/BaseQuteProject.java new file mode 100644 index 000000000..9081072c5 --- /dev/null +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/BaseQuteProject.java @@ -0,0 +1,114 @@ +package com.redhat.qute.project; + +import java.util.Arrays; +import java.util.List; + +import com.redhat.qute.commons.InvalidMethodReason; +import com.redhat.qute.commons.JavaTypeInfo; +import com.redhat.qute.commons.JavaTypeKind; +import com.redhat.qute.commons.ProjectInfo; +import com.redhat.qute.commons.ResolvedJavaTypeInfo; + +public abstract class BaseQuteProject extends MockQuteProject { + + public BaseQuteProject(ProjectInfo projectInfo, QuteProjectRegistry projectRegistry) { + super(projectInfo, projectRegistry); + } + + @Override + protected void fillJavaTypes(List cache) { + createJavaTypeInfo("java.util.List", JavaTypeKind.Interface, cache); + createJavaTypeInfo("java.util.Map", JavaTypeKind.Interface, cache); + } + + @Override + protected void fillResolvedJavaTypes(List resolvedJavaTypes) { + createBinaryTypes(resolvedJavaTypes); + } + + private void createBinaryTypes(List cache) { + // Java type primitives + createResolvedJavaTypeInfo("java.lang.Object", cache, true); + createResolvedJavaTypeInfo("java.lang.Boolean", cache, true); + createResolvedJavaTypeInfo("java.lang.Integer", cache, true); + createResolvedJavaTypeInfo("java.lang.Double", cache, true); + createResolvedJavaTypeInfo("java.lang.Long", cache, true); + createResolvedJavaTypeInfo("java.lang.Float", cache, true); + createResolvedJavaTypeInfo("java.math.BigDecimal", cache, true); + + // String + ResolvedJavaTypeInfo string = createResolvedJavaTypeInfo("java.lang.String", cache, true); + registerField("UTF16 : byte", string); + registerMethod("isEmpty() : boolean", string); + registerMethod("codePointCount(beginIndex : int,endIndex : int) : int", string); + string.setInvalidMethod("getChars", InvalidMethodReason.VoidReturn); // void getChars(int srcBegin, int srcEnd, + // char dst[], int dstBegin) + registerMethod("charAt(index : int) : char", string); + registerMethod("getBytes(charsetName : java.lang.String) : byte[]", string); + registerMethod("getBytes() : byte[]", string); + + // BigInteger + ResolvedJavaTypeInfo bigInteger = createResolvedJavaTypeInfo("java.math.BigInteger", cache, true); + registerMethod("divide(val : java.math.BigInteger) : java.math.BigInteger", bigInteger); + + // Iterator + ResolvedJavaTypeInfo iterator = createResolvedJavaTypeInfo("java.util.Iterator", cache, true); + registerMethod("hasNext() : boolean", iterator); + registerMethod("next() : E", iterator); + + // Iterable + ResolvedJavaTypeInfo iterable = createResolvedJavaTypeInfo("java.lang.Iterable", cache, true); + registerMethod("iterator() : java.util.Iterator", iterable); + + // Collection + ResolvedJavaTypeInfo collection = createResolvedJavaTypeInfo("java.util.Collection", cache, true); + collection.setExtendedTypes(Arrays.asList("java.lang.Iterable")); + + // List + ResolvedJavaTypeInfo list = createResolvedJavaTypeInfo("java.util.List", cache, true); + list.setExtendedTypes(Arrays.asList("java.util.Collection")); + registerMethod("size() : int", list); + registerMethod("get(index : int) : E", list); + registerMethod("subList(fromIndex : int, toIndex: int) : java.util.List", list); + + // Set + ResolvedJavaTypeInfo set = createResolvedJavaTypeInfo("java.util.Set", cache, true); + set.setExtendedTypes(Arrays.asList("java.lang.Iterable")); + + // Map + ResolvedJavaTypeInfo map = createResolvedJavaTypeInfo("java.util.Map", cache, true); + registerMethod("keySet() : java.util.Set", map); + registerMethod("values() : java.util.Collection", map); + registerMethod("entrySet() : java.util.Set>", map); + registerMethod("get(key : K) : V", map); + + // Map.Entry + ResolvedJavaTypeInfo mapEntry = createResolvedJavaTypeInfo("java.util.Map$Entry", cache, true); + registerMethod("getKey() : K", mapEntry); + registerMethod("getValue() : V", mapEntry); + + // AbstractMap + ResolvedJavaTypeInfo abstractMap = createResolvedJavaTypeInfo("java.util.AbstractMap", cache, true); + abstractMap.setExtendedTypes(Arrays.asList("java.util.Map")); + + // HashMap + ResolvedJavaTypeInfo hashMap = createResolvedJavaTypeInfo("java.util.HashMap", cache, true); + hashMap.setExtendedTypes(Arrays.asList("java.util.AbstractMap", "java.util.Map")); + + // https://quarkus.io/guides/qute-reference#evaluation-of-completionstage-and-uni-objects + createResolvedJavaTypeInfo("java.util.concurrent.CompletionStage", cache, true); + ResolvedJavaTypeInfo completableFuture = createResolvedJavaTypeInfo("java.util.concurrent.CompletableFuture", + cache, true); + completableFuture.setExtendedTypes(Arrays.asList("java.util.concurrent.CompletionStage")); + createResolvedJavaTypeInfo("io.smallrye.mutiny.Uni", cache, true); + ResolvedJavaTypeInfo asyncResultUni = createResolvedJavaTypeInfo("io.smallrye.mutiny.vertx.AsyncResultUni", + cache, true); + asyncResultUni.setExtendedTypes(Arrays.asList("io.smallrye.mutiny.Uni")); + + // RawString for raw and safe resolver tests + ResolvedJavaTypeInfo rawString = createResolvedJavaTypeInfo("io.quarkus.qute.RawString", cache, true); + registerMethod("getValue() : java.lang.String", rawString); + registerMethod("toString() : java.lang.String", rawString); + } + +} diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/MockQuteProjectRegistry.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/MockQuteProjectRegistry.java index 66c5ff677..3fb01aba1 100644 --- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/MockQuteProjectRegistry.java +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/MockQuteProjectRegistry.java @@ -37,6 +37,7 @@ import com.redhat.qute.commons.usertags.UserTagInfo; import com.redhat.qute.project.multiple.QuteProjectA; import com.redhat.qute.project.multiple.QuteProjectB; +import com.redhat.qute.project.roq.RoqProject; public class MockQuteProjectRegistry extends QuteProjectRegistry { @@ -64,6 +65,9 @@ protected QuteProject createProject(ProjectInfo projectInfo) { if (QuteProjectB.PROJECT_URI.equals(projectInfo.getUri())) { return new QuteProjectB(this); } + if (RoqProject.PROJECT_URI.equals(projectInfo.getUri())) { + return new RoqProject(projectInfo, this); + } return super.createProject(projectInfo); } 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 c0aeede4e..66286b587 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 @@ -19,7 +19,6 @@ import com.redhat.qute.commons.InvalidMethodReason; import com.redhat.qute.commons.JavaMemberInfo; import com.redhat.qute.commons.JavaMethodInfo; -import com.redhat.qute.commons.JavaTypeInfo; import com.redhat.qute.commons.JavaTypeKind; import com.redhat.qute.commons.ProjectInfo; import com.redhat.qute.commons.ResolvedJavaTypeInfo; @@ -42,7 +41,7 @@ * @author Angelo ZERR * */ -public class QuteQuickStartProject extends MockQuteProject { +public class QuteQuickStartProject extends BaseQuteProject { public final static String PROJECT_URI = "qute-quickstart"; @@ -56,95 +55,9 @@ public QuteQuickStartProject(ProjectInfo projectInfo, QuteProjectRegistry projec @Override protected void fillResolvedJavaTypes(List cache) { - createBinaryTypes(cache); + super.fillResolvedJavaTypes(cache); createSourceTypes(cache); } - - private void createBinaryTypes(List cache) { - // Java type primitives - createResolvedJavaTypeInfo("java.lang.Object", cache, true); - createResolvedJavaTypeInfo("java.lang.Boolean", cache, true); - createResolvedJavaTypeInfo("java.lang.Integer", cache, true); - createResolvedJavaTypeInfo("java.lang.Double", cache, true); - createResolvedJavaTypeInfo("java.lang.Long", cache, true); - createResolvedJavaTypeInfo("java.lang.Float", cache, true); - createResolvedJavaTypeInfo("java.math.BigDecimal", cache, true); - - // String - ResolvedJavaTypeInfo string = createResolvedJavaTypeInfo("java.lang.String", cache, true); - registerField("UTF16 : byte", string); - registerMethod("isEmpty() : boolean", string); - registerMethod("codePointCount(beginIndex : int,endIndex : int) : int", string); - string.setInvalidMethod("getChars", InvalidMethodReason.VoidReturn); // void getChars(int srcBegin, int srcEnd, - // char dst[], int dstBegin) - registerMethod("charAt(index : int) : char", string); - registerMethod("getBytes(charsetName : java.lang.String) : byte[]", string); - registerMethod("getBytes() : byte[]", string); - - // BigInteger - ResolvedJavaTypeInfo bigInteger = createResolvedJavaTypeInfo("java.math.BigInteger", cache, true); - registerMethod("divide(val : java.math.BigInteger) : java.math.BigInteger", bigInteger); - - // Iterator - ResolvedJavaTypeInfo iterator = createResolvedJavaTypeInfo("java.util.Iterator", cache, true); - registerMethod("hasNext() : boolean", iterator); - registerMethod("next() : E", iterator); - - // Iterable - ResolvedJavaTypeInfo iterable = createResolvedJavaTypeInfo("java.lang.Iterable", cache, true); - registerMethod("iterator() : java.util.Iterator", iterable); - - // Collection - ResolvedJavaTypeInfo collection = createResolvedJavaTypeInfo("java.util.Collection", cache, true); - collection.setExtendedTypes(Arrays.asList("java.lang.Iterable")); - - // List - ResolvedJavaTypeInfo list = createResolvedJavaTypeInfo("java.util.List", cache, true); - list.setExtendedTypes(Arrays.asList("java.util.Collection")); - registerMethod("size() : int", list); - registerMethod("get(index : int) : E", list); - registerMethod("subList(fromIndex : int, toIndex: int) : java.util.List", list); - - // Set - ResolvedJavaTypeInfo set = createResolvedJavaTypeInfo("java.util.Set", cache, true); - set.setExtendedTypes(Arrays.asList("java.lang.Iterable")); - - // Map - ResolvedJavaTypeInfo map = createResolvedJavaTypeInfo("java.util.Map", cache, true); - registerMethod("keySet() : java.util.Set", map); - registerMethod("values() : java.util.Collection", map); - registerMethod("entrySet() : java.util.Set>", map); - registerMethod("get(key : K) : V", map); - - // Map.Entry - ResolvedJavaTypeInfo mapEntry = createResolvedJavaTypeInfo("java.util.Map$Entry", cache, true); - registerMethod("getKey() : K", mapEntry); - registerMethod("getValue() : V", mapEntry); - - // AbstractMap - ResolvedJavaTypeInfo abstractMap = createResolvedJavaTypeInfo("java.util.AbstractMap", cache, true); - abstractMap.setExtendedTypes(Arrays.asList("java.util.Map")); - - // HashMap - ResolvedJavaTypeInfo hashMap = createResolvedJavaTypeInfo("java.util.HashMap", cache, true); - hashMap.setExtendedTypes(Arrays.asList("java.util.AbstractMap", "java.util.Map")); - - // https://quarkus.io/guides/qute-reference#evaluation-of-completionstage-and-uni-objects - createResolvedJavaTypeInfo("java.util.concurrent.CompletionStage", cache, true); - ResolvedJavaTypeInfo completableFuture = createResolvedJavaTypeInfo("java.util.concurrent.CompletableFuture", - cache, true); - completableFuture.setExtendedTypes(Arrays.asList("java.util.concurrent.CompletionStage")); - createResolvedJavaTypeInfo("io.smallrye.mutiny.Uni", cache, true); - ResolvedJavaTypeInfo asyncResultUni = createResolvedJavaTypeInfo("io.smallrye.mutiny.vertx.AsyncResultUni", - cache, true); - asyncResultUni.setExtendedTypes(Arrays.asList("io.smallrye.mutiny.Uni")); - - // RawString for raw and safe resolver tests - ResolvedJavaTypeInfo rawString = createResolvedJavaTypeInfo("io.quarkus.qute.RawString", cache, true); - registerMethod("getValue() : java.lang.String", rawString); - registerMethod("toString() : java.lang.String", rawString); - } - private void createSourceTypes(List cache) { createResolvedJavaTypeInfo("org.acme", cache, true).setJavaTypeKind(JavaTypeKind.Package); @@ -339,7 +252,7 @@ private void createSourceTypes(List cache) { // void method registerMethod("timeoutGame() : void", renardeLogin); - + // https://quarkus.io/guides/qute-reference#evaluation-of-completionstage-and-uni-objects ResolvedJavaTypeInfo completionStagePOJO = createResolvedJavaTypeInfo("org.acme.CompletionStagePOJO", cache, false); @@ -529,12 +442,6 @@ protected void fillValueResolvers(List resolvers) { } - @Override - protected void fillJavaTypes(List cache) { - createJavaTypeInfo("java.util.List", JavaTypeKind.Interface, cache); - createJavaTypeInfo("java.util.Map", JavaTypeKind.Interface, cache); - } - @Override protected void fillNamespaceResolverInfos(Map infos) { NamespaceResolverInfo inject = new NamespaceResolverInfo(); diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqCollection.json b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqCollection.json new file mode 100644 index 000000000..543003cc8 --- /dev/null +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqCollection.json @@ -0,0 +1,33 @@ +{ + "signature": "io.quarkiverse.roq.frontmatter.runtime.model.RoqCollection", + "extendedTypes": [ + "java.util.ArrayList" + ], + "fields": [], + "methods": [ + { + "signature": "resolveNextPage(page : io.quarkiverse.roq.frontmatter.runtime.model.DocumentPage) : io.quarkiverse.roq.frontmatter.runtime.model.DocumentPage" + }, + { + "signature": "resolvePreviousPage(page : io.quarkiverse.roq.frontmatter.runtime.model.DocumentPage) : io.quarkiverse.roq.frontmatter.runtime.model.DocumentPage" + }, + { + "signature": "resolvePrevPage(page : io.quarkiverse.roq.frontmatter.runtime.model.DocumentPage) : io.quarkiverse.roq.frontmatter.runtime.model.DocumentPage" + }, + { + "signature": "paginated(paginator : io.quarkiverse.roq.frontmatter.runtime.model.Paginator) : java.util.List" + }, + { + "signature": "by(keys : java.lang.String...) : java.util.List" + }, + { + "signature": "group(keys : java.lang.String...) : java.util.Map>" + } + ], + "binary": true, + "templateDataAnnotations": [ + {} + ], + "typeKind": 2, + "invalidMethods": {} +} \ No newline at end of file diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqCollections.json b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqCollections.json new file mode 100644 index 000000000..001cc6189 --- /dev/null +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqCollections.json @@ -0,0 +1,46 @@ +{ + "signature": "io.quarkiverse.roq.frontmatter.runtime.model.RoqCollections", + "extendedTypes": [ + "java.lang.Record" + ], + "fields": [ + { + "signature": "collections : java.util.Map" + } + ], + "methods": [ + { + "signature": "get(name : java.lang.String) : io.quarkiverse.roq.frontmatter.runtime.model.RoqCollection" + }, + { + "signature": "resolveNextPage(page : io.quarkiverse.roq.frontmatter.runtime.model.DocumentPage) : io.quarkiverse.roq.frontmatter.runtime.model.DocumentPage" + }, + { + "signature": "resolvePreviousPage(page : io.quarkiverse.roq.frontmatter.runtime.model.DocumentPage) : io.quarkiverse.roq.frontmatter.runtime.model.DocumentPage" + }, + { + "signature": "resolveCollection(page : io.quarkiverse.roq.frontmatter.runtime.model.DocumentPage) : io.quarkiverse.roq.frontmatter.runtime.model.RoqCollection" + }, + { + "signature": "resolvePrevPage(page : io.quarkiverse.roq.frontmatter.runtime.model.DocumentPage) : io.quarkiverse.roq.frontmatter.runtime.model.DocumentPage" + }, + { + "signature": "toString() : java.lang.String" + }, + { + "signature": "hashCode() : int" + }, + { + "signature": "equals(o : java.lang.Object) : boolean" + }, + { + "signature": "collections() : java.util.Map" + } + ], + "binary": true, + "templateDataAnnotations": [ + {} + ], + "typeKind": 0, + "invalidMethods": {} +} \ No newline at end of file diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqDataModel.json b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqDataModel.json new file mode 100644 index 000000000..9013403d9 --- /dev/null +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqDataModel.json @@ -0,0 +1,461 @@ +{ + "templates": [], + "namespaceResolverInfos": { + "inject": { + "namespaces": [ + "inject", + "cdi" + ], + "description": "A CDI bean annotated with `@Named` can be referenced in any template through `cdi` and/or `inject` namespaces.", + "url": "https://quarkus.io/guides/qute-reference#injecting-beans-directly-in-templates" + } + }, + "valueResolvers": [ + { + "namespace": "fm", + "signature": "pageNumber(arg0 : int, arg1 : int) : java.lang.String", + "sourceType": "io.quarkiverse.roq.frontmatter.runtime.RoqFrontMatterMessages", + "kind": 7, + "data": { + "locale": "en", + "message": "Page {index} of {total}" + } + }, + { + "signature": "numberOfWords(text : java.lang.String) : long", + "sourceType": "io.quarkiverse.roq.frontmatter.runtime.RoqTemplateExtension", + "binary": true, + "kind": 4 + }, + { + "matchName": "*", + "signature": "collection(collections : io.quarkiverse.roq.frontmatter.runtime.model.RoqCollections, key : java.lang.String) : io.quarkiverse.roq.frontmatter.runtime.model.RoqCollection", + "sourceType": "io.quarkiverse.roq.frontmatter.runtime.RoqTemplateExtension", + "binary": true, + "kind": 4 + }, + { + "signature": "readTime(page : io.quarkiverse.roq.frontmatter.runtime.model.Page) : java.lang.Object", + "sourceType": "io.quarkiverse.roq.frontmatter.runtime.RoqTemplateExtension", + "binary": true, + "kind": 4 + }, + { + "signature": "slugify(text : java.lang.String) : java.lang.String", + "sourceType": "io.quarkiverse.roq.frontmatter.runtime.RoqTemplateExtension", + "binary": true, + "kind": 4 + }, + { + "signature": "asStrings(o : java.lang.Object) : java.util.List", + "sourceType": "io.quarkiverse.roq.frontmatter.runtime.RoqTemplateExtension", + "binary": true, + "kind": 4 + }, + { + "matchName": "*", + "signature": "collection(collections : io.quarkiverse.roq.frontmatter.runtime.model.RoqCollections, key : java.lang.String) : io.quarkiverse.roq.frontmatter.runtime.model.RoqCollection", + "sourceType": "io.quarkiverse.roq.frontmatter.runtime.RoqTemplateExtension", + "binary": true, + "kind": 3 + }, + { + "signature": "now : java.time.LocalDateTime", + "sourceType": "io.quarkiverse.roq.frontmatter.runtime.RoqTemplateGlobal", + "kind": 5, + "globalVariable": true + }, + { + "signature": "roqVersion : java.lang.String", + "sourceType": "io.quarkiverse.roq.frontmatter.runtime.RoqTemplateGlobal", + "kind": 5, + "globalVariable": true + }, + { + "signature": "locale : java.lang.String", + "sourceType": "io.quarkiverse.roq.frontmatter.runtime.RoqTemplateGlobal", + "kind": 5, + "globalVariable": true + }, + { + "namespace": "io_quarkiverse_roq_frontmatter_runtime_model_Page", + "signature": "getImgFromData(data : io.vertx.core.json.JsonObject) : java.lang.String", + "sourceType": "io.quarkiverse.roq.frontmatter.runtime.model.Page", + "kind": 1 + }, + { + "namespace": "io_quarkiverse_roq_frontmatter_runtime_model_Page", + "signature": "resolveImgUrl(rootUrl : io.quarkiverse.roq.frontmatter.runtime.model.RootUrl, data : io.vertx.core.json.JsonObject) : io.quarkiverse.roq.frontmatter.runtime.model.RoqUrl", + "sourceType": "io.quarkiverse.roq.frontmatter.runtime.model.Page", + "kind": 1 + }, + { + "namespace": "io_quarkiverse_roq_frontmatter_runtime_model_PageInfo", + "signature": "HTML_OUTPUT_EXTENSIONS : java.util.Set", + "sourceType": "io.quarkiverse.roq.frontmatter.runtime.model.PageInfo", + "kind": 1 + }, + { + "namespace": "io_quarkiverse_roq_frontmatter_runtime_model_PageInfo", + "signature": "create(id : java.lang.String, draft : boolean, imagesRootPath : java.lang.String, dateString : java.lang.String, rawContent : java.lang.String, sourcePath : java.lang.String, quteTemplatePath : java.lang.String) : io.quarkiverse.roq.frontmatter.runtime.model.PageInfo", + "sourceType": "io.quarkiverse.roq.frontmatter.runtime.model.PageInfo", + "kind": 1 + }, + { + "namespace": "io_quarkiverse_roq_frontmatter_runtime_model_RoqUrl", + "signature": "isFullPath(path : java.lang.String) : boolean", + "sourceType": "io.quarkiverse.roq.frontmatter.runtime.model.RoqUrl", + "kind": 1 + }, + { + "namespace": "io_quarkiverse_roq_frontmatter_runtime_model_RoqUrl", + "signature": "fromRoot(root : io.quarkiverse.roq.frontmatter.runtime.model.RootUrl, path : java.lang.String) : io.quarkiverse.roq.frontmatter.runtime.model.RoqUrl", + "sourceType": "io.quarkiverse.roq.frontmatter.runtime.model.RoqUrl", + "kind": 1 + }, + { + "signature": "get(list : java.util.List, index : int) : T", + "sourceType": "io.quarkus.qute.runtime.extensions.CollectionTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "getByIndex(list : java.util.List, index : java.lang.String) : T", + "sourceType": "io.quarkus.qute.runtime.extensions.CollectionTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "reversed(list : java.util.List) : java.util.Iterator", + "sourceType": "io.quarkus.qute.runtime.extensions.CollectionTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "take(list : java.util.List, n : int) : java.util.List", + "sourceType": "io.quarkus.qute.runtime.extensions.CollectionTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "takeLast(list : java.util.List, n : int) : java.util.List", + "sourceType": "io.quarkus.qute.runtime.extensions.CollectionTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "orEmpty(iterable : java.util.Collection) : java.util.Collection", + "sourceType": "io.quarkus.qute.runtime.extensions.CollectionTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "first(list : java.util.List) : T", + "sourceType": "io.quarkus.qute.runtime.extensions.CollectionTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "last(list : java.util.List) : T", + "sourceType": "io.quarkus.qute.runtime.extensions.CollectionTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "getByIndex(list : java.util.List, index : java.lang.String) : T", + "sourceType": "io.quarkus.qute.runtime.extensions.CollectionTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "namespace": "config", + "matchName": "*", + "signature": "getConfigProperty(propertyName : java.lang.String) : java.lang.Object", + "sourceType": "io.quarkus.qute.runtime.extensions.ConfigTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "namespace": "config", + "signature": "property(propertyName : java.lang.String) : java.lang.Object", + "sourceType": "io.quarkus.qute.runtime.extensions.ConfigTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "namespace": "config", + "matchName": "boolean", + "signature": "booleanProperty(propertyName : java.lang.String) : java.lang.Object", + "sourceType": "io.quarkus.qute.runtime.extensions.ConfigTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "namespace": "config", + "matchName": "integer", + "signature": "integerProperty(propertyName : java.lang.String) : java.lang.Object", + "sourceType": "io.quarkus.qute.runtime.extensions.ConfigTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "matchName": "*", + "signature": "map(arg0 : java.util.Map, arg1 : java.lang.String) : java.lang.Object", + "sourceType": "io.quarkus.qute.runtime.extensions.MapTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "get(map : java.util.Map, key : java.lang.Object) : V", + "sourceType": "io.quarkus.qute.runtime.extensions.MapTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "containsKey(map : java.util.Map, key : java.lang.Object) : boolean", + "sourceType": "io.quarkus.qute.runtime.extensions.MapTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "matchName": "*", + "signature": "map(arg0 : java.util.Map, arg1 : java.lang.String) : java.lang.Object", + "sourceType": "io.quarkus.qute.runtime.extensions.MapTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "signature": "mod(number : java.lang.Integer, mod : java.lang.Integer) : java.lang.Integer", + "sourceType": "io.quarkus.qute.runtime.extensions.NumberTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "addToInt(number : java.lang.Integer, name : java.lang.String, other : java.lang.Integer) : java.lang.Integer", + "sourceType": "io.quarkus.qute.runtime.extensions.NumberTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "addToInt(number : java.lang.Integer, name : java.lang.String, other : java.lang.Long) : java.lang.Long", + "sourceType": "io.quarkus.qute.runtime.extensions.NumberTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "addToLong(number : java.lang.Long, name : java.lang.String, other : java.lang.Integer) : java.lang.Long", + "sourceType": "io.quarkus.qute.runtime.extensions.NumberTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "addToLong(number : java.lang.Long, name : java.lang.String, other : java.lang.Long) : java.lang.Long", + "sourceType": "io.quarkus.qute.runtime.extensions.NumberTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "subtractFromInt(number : java.lang.Integer, name : java.lang.String, other : java.lang.Integer) : java.lang.Integer", + "sourceType": "io.quarkus.qute.runtime.extensions.NumberTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "subtractFromInt(number : java.lang.Integer, name : java.lang.String, other : java.lang.Long) : java.lang.Long", + "sourceType": "io.quarkus.qute.runtime.extensions.NumberTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "subtractFromLong(number : java.lang.Long, name : java.lang.String, other : java.lang.Integer) : java.lang.Long", + "sourceType": "io.quarkus.qute.runtime.extensions.NumberTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "subtractFromLong(number : java.lang.Long, name : java.lang.String, other : java.lang.Long) : java.lang.Long", + "sourceType": "io.quarkus.qute.runtime.extensions.NumberTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "addToInt(number : java.lang.Integer, name : java.lang.String, other : java.lang.Integer) : java.lang.Integer", + "sourceType": "io.quarkus.qute.runtime.extensions.NumberTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "signature": "addToInt(number : java.lang.Integer, name : java.lang.String, other : java.lang.Long) : java.lang.Long", + "sourceType": "io.quarkus.qute.runtime.extensions.NumberTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "signature": "addToLong(number : java.lang.Long, name : java.lang.String, other : java.lang.Integer) : java.lang.Long", + "sourceType": "io.quarkus.qute.runtime.extensions.NumberTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "signature": "addToLong(number : java.lang.Long, name : java.lang.String, other : java.lang.Long) : java.lang.Long", + "sourceType": "io.quarkus.qute.runtime.extensions.NumberTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "signature": "subtractFromInt(number : java.lang.Integer, name : java.lang.String, other : java.lang.Integer) : java.lang.Integer", + "sourceType": "io.quarkus.qute.runtime.extensions.NumberTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "signature": "subtractFromInt(number : java.lang.Integer, name : java.lang.String, other : java.lang.Long) : java.lang.Long", + "sourceType": "io.quarkus.qute.runtime.extensions.NumberTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "signature": "subtractFromLong(number : java.lang.Long, name : java.lang.String, other : java.lang.Integer) : java.lang.Long", + "sourceType": "io.quarkus.qute.runtime.extensions.NumberTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "signature": "subtractFromLong(number : java.lang.Long, name : java.lang.String, other : java.lang.Long) : java.lang.Long", + "sourceType": "io.quarkus.qute.runtime.extensions.NumberTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "signature": "or(value : T, other : T) : T", + "sourceType": "io.quarkus.qute.runtime.extensions.OrOperatorTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "fmtInstance(format : java.lang.String, ignoredPropertyName : java.lang.String, args : java.lang.Object...) : java.lang.String", + "sourceType": "io.quarkus.qute.runtime.extensions.StringTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "signature": "fmtInstance(format : java.lang.String, ignoredPropertyName : java.lang.String, locale : java.util.Locale, args : java.lang.Object...) : java.lang.String", + "sourceType": "io.quarkus.qute.runtime.extensions.StringTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "namespace": "str", + "signature": "fmt(ignoredPropertyName : java.lang.String, format : java.lang.String, args : java.lang.Object...) : java.lang.String", + "sourceType": "io.quarkus.qute.runtime.extensions.StringTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "namespace": "str", + "signature": "fmt(ignoredPropertyName : java.lang.String, locale : java.util.Locale, format : java.lang.String, args : java.lang.Object...) : java.lang.String", + "sourceType": "io.quarkus.qute.runtime.extensions.StringTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "matchName": "+", + "signature": "plus(str : java.lang.String, val : java.lang.Object) : java.lang.String", + "sourceType": "io.quarkus.qute.runtime.extensions.StringTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "signature": "format(temporal : java.time.temporal.TemporalAccessor, pattern : java.lang.String) : java.lang.String", + "sourceType": "io.quarkus.qute.runtime.extensions.TimeTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "format(temporal : java.time.temporal.TemporalAccessor, pattern : java.lang.String, locale : java.util.Locale) : java.lang.String", + "sourceType": "io.quarkus.qute.runtime.extensions.TimeTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "format(temporal : java.time.temporal.TemporalAccessor, pattern : java.lang.String, locale : java.util.Locale, timeZone : java.time.ZoneId) : java.lang.String", + "sourceType": "io.quarkus.qute.runtime.extensions.TimeTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "namespace": "time", + "signature": "format(dateTimeObject : java.lang.Object, pattern : java.lang.String) : java.lang.String", + "sourceType": "io.quarkus.qute.runtime.extensions.TimeTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "namespace": "time", + "signature": "format(dateTimeObject : java.lang.Object, pattern : java.lang.String, locale : java.util.Locale) : java.lang.String", + "sourceType": "io.quarkus.qute.runtime.extensions.TimeTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "namespace": "time", + "signature": "format(dateTimeObject : java.lang.Object, pattern : java.lang.String, locale : java.util.Locale, timeZone : java.time.ZoneId) : java.lang.String", + "sourceType": "io.quarkus.qute.runtime.extensions.TimeTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "getFormattableObject(value : java.lang.Object, timeZone : java.time.ZoneId) : java.time.temporal.TemporalAccessor", + "sourceType": "io.quarkus.qute.runtime.extensions.TimeTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "signature": "formatterForKey(key : io.quarkus.qute.runtime.extensions.TimeTemplateExtensions$Key) : java.time.format.DateTimeFormatter", + "sourceType": "io.quarkus.qute.runtime.extensions.TimeTemplateExtensions", + "binary": true, + "kind": 4 + }, + { + "namespace": "time", + "signature": "format(dateTimeObject : java.lang.Object, pattern : java.lang.String) : java.lang.String", + "sourceType": "io.quarkus.qute.runtime.extensions.TimeTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "namespace": "time", + "signature": "format(dateTimeObject : java.lang.Object, pattern : java.lang.String, locale : java.util.Locale) : java.lang.String", + "sourceType": "io.quarkus.qute.runtime.extensions.TimeTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "namespace": "time", + "signature": "format(dateTimeObject : java.lang.Object, pattern : java.lang.String, locale : java.util.Locale, timeZone : java.time.ZoneId) : java.lang.String", + "sourceType": "io.quarkus.qute.runtime.extensions.TimeTemplateExtensions", + "binary": true, + "kind": 3 + }, + { + "signature": "convertToMarkdown(text : java.lang.String, ignoredName : java.lang.String) : java.lang.String", + "sourceType": "io.quarkiverse.qute.web.markdown.runtime.MarkdownSectionHelperFactory", + "binary": true, + "kind": 3 + }, + { + "named": "bundle", + "namespace": "inject", + "signature": "io.quarkiverse.web.bundler.runtime.Bundle", + "sourceType": "io.quarkiverse.web.bundler.runtime.Bundle", + "kind": 6 + }, + { + "named": "vertxRequest", + "namespace": "inject", + "signature": "getCurrentRequest(rc : io.vertx.ext.web.RoutingContext) : io.vertx.core.http.HttpServerRequest", + "sourceType": "io.quarkus.vertx.http.runtime.CurrentRequestProducer", + "kind": 6 + } + ] +} \ No newline at end of file diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqProject.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqProject.java new file mode 100644 index 000000000..244924652 --- /dev/null +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqProject.java @@ -0,0 +1,71 @@ +package com.redhat.qute.project.roq; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.List; +import java.util.Map; + +import com.google.gson.GsonBuilder; +import com.redhat.qute.commons.ProjectInfo; +import com.redhat.qute.commons.ResolvedJavaTypeInfo; +import com.redhat.qute.commons.datamodel.DataModelParameter; +import com.redhat.qute.commons.datamodel.DataModelProject; +import com.redhat.qute.commons.datamodel.DataModelTemplate; +import com.redhat.qute.commons.datamodel.resolvers.NamespaceResolverInfo; +import com.redhat.qute.commons.datamodel.resolvers.ValueResolverInfo; +import com.redhat.qute.project.BaseQuteProject; +import com.redhat.qute.project.QuteProjectRegistry; + +public class RoqProject extends BaseQuteProject { + + public static final String PROJECT_URI = "roq"; + private DataModelProject> dataModel; + + public RoqProject(ProjectInfo projectInfo, QuteProjectRegistry projectRegistry) { + super(projectInfo, projectRegistry); + } + + private DataModelProject> loadDataModel(String fileName) { + InputStream in = this.getClass().getResourceAsStream(fileName); + return new GsonBuilder().create().fromJson(new InputStreamReader(in), + DataModelProject.class); + } + + @Override + protected void fillResolvedJavaTypes(List resolvedJavaTypes) { + super.fillResolvedJavaTypes(resolvedJavaTypes); + loadResolvedJavaType("Site.json", resolvedJavaTypes); + loadResolvedJavaType("RoqCollection.json", resolvedJavaTypes); + loadResolvedJavaType("RoqCollections.json", resolvedJavaTypes); + } + + private void loadResolvedJavaType(String fileName, List resolvedJavaTypes) { + InputStream in = this.getClass().getResourceAsStream(fileName); + ResolvedJavaTypeInfo resolvedJavaType = new GsonBuilder().create().fromJson(new InputStreamReader(in), + ResolvedJavaTypeInfo.class); + resolvedJavaTypes.add(resolvedJavaType); + } + + @Override + protected void fillTemplates(List> templates) { + + } + + @Override + protected void fillValueResolvers(List valueResolvers) { + valueResolvers.addAll(getDataModel().getValueResolvers()); + } + + private DataModelProject> getDataModel() { + if (dataModel == null) { + dataModel = loadDataModel("RoqDataModel.json"); + } + return dataModel; + } + + @Override + protected void fillNamespaceResolverInfos(Map namespaces) { + + } + +} diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/Site.json b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/Site.json new file mode 100644 index 000000000..86afb5946 --- /dev/null +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/Site.json @@ -0,0 +1,76 @@ +{ + "signature": "io.quarkiverse.roq.frontmatter.runtime.model.Site", + "extendedTypes": [ + "java.lang.Record" + ], + "fields": [ + { + "signature": "url : io.quarkiverse.roq.frontmatter.runtime.model.RoqUrl" + }, + { + "signature": "imagesUrl : io.quarkiverse.roq.frontmatter.runtime.model.RoqUrl" + }, + { + "signature": "data : io.vertx.core.json.JsonObject" + }, + { + "signature": "pages : java.util.List" + }, + { + "signature": "collections : io.quarkiverse.roq.frontmatter.runtime.model.RoqCollections" + } + ], + "methods": [ + { + "signature": "title() : java.lang.String" + }, + { + "signature": "description() : java.lang.String" + }, + { + "signature": "img() : io.quarkiverse.roq.frontmatter.runtime.model.RoqUrl" + }, + { + "signature": "url(path : java.lang.Object) : io.quarkiverse.roq.frontmatter.runtime.model.RoqUrl" + }, + { + "signature": "url(path : java.lang.Object, others : java.lang.Object...) : io.quarkiverse.roq.frontmatter.runtime.model.RoqUrl" + }, + { + "signature": "page(id : java.lang.String) : io.quarkiverse.roq.frontmatter.runtime.model.NormalPage" + }, + { + "signature": "document(id : java.lang.String) : io.quarkiverse.roq.frontmatter.runtime.model.DocumentPage" + }, + { + "signature": "toString() : java.lang.String" + }, + { + "signature": "hashCode() : int" + }, + { + "signature": "equals(o : java.lang.Object) : boolean" + }, + { + "signature": "url() : io.quarkiverse.roq.frontmatter.runtime.model.RoqUrl" + }, + { + "signature": "imagesUrl() : io.quarkiverse.roq.frontmatter.runtime.model.RoqUrl" + }, + { + "signature": "data() : io.vertx.core.json.JsonObject" + }, + { + "signature": "pages() : java.util.List" + }, + { + "signature": "collections() : io.quarkiverse.roq.frontmatter.runtime.model.RoqCollections" + } + ], + "binary": true, + "templateDataAnnotations": [ + {} + ], + "typeKind": 0, + "invalidMethods": {} +} \ No newline at end of file diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/completions/roq/RoqCompletionsTest.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/completions/roq/RoqCompletionsTest.java new file mode 100644 index 000000000..aaa4d2613 --- /dev/null +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/completions/roq/RoqCompletionsTest.java @@ -0,0 +1,118 @@ +/******************************************************************************* +* Copyright (c) 2022 Red Hat Inc. and others. +* All rights reserved. This program and the accompanying materials +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v20.html +* +* SPDX-License-Identifier: EPL-2.0 +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ +package com.redhat.qute.services.completions.roq; + +import static com.redhat.qute.QuteAssert.c; +import static com.redhat.qute.QuteAssert.r; + +import org.eclipse.lsp4j.CompletionItem; +import org.junit.jupiter.api.Test; + +import com.redhat.qute.QuteAssert; +import com.redhat.qute.project.roq.RoqProject; + +/** + * Tests for Qute completion in expression. + * + * @author Angelo ZERR + * + */ +public class RoqCompletionsTest { + + @Test + public void site() throws Exception { + String template = "{@io.quarkiverse.roq.frontmatter.runtime.model.Site site}\r\n" + // + "{site.|}"; + testCompletionFor(template, // + c("or(base : T, arg : Object) : T", "or(arg)", r(1, 6, 1, 6)), // + c("img() : RoqUrl", "img", r(1, 6, 1, 6)), // + c("toString() : String", "toString", r(1, 6, 1, 6)), // + c("hashCode() : int", "hashCode", r(1, 6, 1, 6)), // + c("imagesUrl : RoqUrl", "imagesUrl", r(1, 6, 1, 6)), // + c("url() : RoqUrl", "url", r(1, 6, 1, 6)), // + c("collections : RoqCollections", "collections", r(1, 6, 1, 6)), // + c("collections() : RoqCollections", "collections", r(1, 6, 1, 6)), // + c("document(id : String) : DocumentPage", "document(id)", r(1, 6, 1, 6)), // + c("pages : List", "pages", r(1, 6, 1, 6)), // + c("pages() : List", "pages", r(1, 6, 1, 6)), // + c("data() : JsonObject", "data", r(1, 6, 1, 6)), // + c("orEmpty(base : T) : List", "orEmpty", r(1, 6, 1, 6)), // + c("page(id : String) : NormalPage", "page(id)", r(1, 6, 1, 6)), // + c("safe(base : Object) : RawString", "safe", r(1, 6, 1, 6)), // + c("title() : String", "title", r(1, 6, 1, 6)), // + c("url(path : Object, others : Object...) : RoqUrl", "url(path, others)", r(1, 6, 1, 6)), // + c("title() : String", "title", r(1, 6, 1, 6))); + } + + // org.opentest4j.AssertionFailedError: resolvePrevPage(page : DocumentPage) : + // DocumentPage,collections() : Map,equals(o : Object) : + // boolean,get(name : String) : RoqCollection,safe(base : Object) : + // RawString,resolvePreviousPage(page : DocumentPage) : + // DocumentPage,ifTruthy(base : T, arg : Object) : T,toString() : String,or(base + // : T, arg : Object) : T,hashCode() : int,resolveNextPage(page : DocumentPage) + // : DocumentPage,orEmpty(base : T) : List,raw(base : Object) : RawString ==> + // expected: <1> but was: <0> + + @Test + public void site_collections() throws Exception { + String template = "{@io.quarkiverse.roq.frontmatter.runtime.model.Site site}\r\n" + // + "{site.collections.|}"; + testCompletionFor(template, // + c("or(base : T, arg : Object) : T", "or(arg)", r(1, 18, 1, 18)), // + c("collections : Map", "collections", r(1, 18, 1, 18)), // + c("resolveCollection(page : DocumentPage) : RoqCollection", "resolveCollection(page)", r(1, 18, 1, 18)), // + c("hashCode() : int", "hashCode", r(1, 18, 1, 18)), // + c("get(name : String) : RoqCollection", "get(name)", r(1, 18, 1, 18))); + } + + @Test + public void site_collections_get() throws Exception { + String template = "{@io.quarkiverse.roq.frontmatter.runtime.model.Site site}\r\n" + // + "{site.collections.get('posts').|}"; + testCompletionFor(template, // + c("or(base : T, arg : Object) : T", "or(arg)", r(1, 31, 1, 31)), // + c("group(keys : String...) : Map>", "group(keys)", r(1, 31, 1, 31)), // + c("resolvePreviousPage(page : DocumentPage) : DocumentPage", "resolvePreviousPage(page)", + r(1, 31, 1, 31)), // + c("paginated(paginator : Paginator) : List", "paginated(paginator)", r(1, 31, 1, 31))); + } + + @Test + public void site_collections_get_useTemlateExtension() throws Exception { + String template = "{@io.quarkiverse.roq.frontmatter.runtime.model.Site site}\r\n" + // + "{site.collections.posts.|}"; + testCompletionFor(template, // + c("or(base : T, arg : Object) : T", "or(arg)", r(1, 24, 1, 24)), // + c("group(keys : String...) : Map>", "group(keys)", r(1, 24, 1, 24)), // + c("resolvePreviousPage(page : DocumentPage) : DocumentPage", "resolvePreviousPage(page)", + r(1, 24, 1, 24)), // + c("paginated(paginator : Paginator) : List", "paginated(paginator)", r(1, 24, 1, 24))); + } + + @Test + public void collection() throws Exception { + String template = "{@io.quarkiverse.roq.frontmatter.runtime.model.Site site}\r\n" + // + "{#for post in site.collections.posts.paginated(page.paginator)}\r\n" + // + "{#if post.|}"; + testCompletionFor(template, // + c("item", "item", r(1, 13, 1, 13))); + } + + public static void testCompletionFor(String value, + CompletionItem... expectedItems) throws Exception { + QuteAssert.testCompletionFor(value, false, QuteAssert.FILE_URI, null, RoqProject.PROJECT_URI, + QuteAssert.TEMPLATE_BASE_DIR, + null, + expectedItems); + } + +} \ No newline at end of file