diff --git a/core/pom.xml b/core/pom.xml index 92c0c7ac..e4d21995 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -12,7 +12,7 @@ org.opencds.cqf.cql.ls cql-ls - 4.1.2 + 4.1.2-SNAPSHOT ../pom.xml diff --git a/debug/server/pom.xml b/debug/server/pom.xml index a36a533a..3a57a691 100644 --- a/debug/server/pom.xml +++ b/debug/server/pom.xml @@ -12,7 +12,7 @@ org.opencds.cqf.cql.ls cql-ls - 4.1.2 + 4.1.2-SNAPSHOT ../../pom.xml diff --git a/debug/service/pom.xml b/debug/service/pom.xml index cfdfe579..5a4b775d 100644 --- a/debug/service/pom.xml +++ b/debug/service/pom.xml @@ -12,7 +12,7 @@ org.opencds.cqf.cql.ls cql-ls - 4.1.2 + 4.1.2-SNAPSHOT ../../pom.xml diff --git a/ls/server/pom.xml b/ls/server/pom.xml index 63d4c58b..b3282ec1 100644 --- a/ls/server/pom.xml +++ b/ls/server/pom.xml @@ -12,7 +12,7 @@ org.opencds.cqf.cql.ls cql-ls - 4.1.2 + 4.1.2-SNAPSHOT ../../pom.xml diff --git a/ls/server/src/main/java/org/opencds/cqf/cql/ls/server/command/ViewElmCommandContribution.java b/ls/server/src/main/java/org/opencds/cqf/cql/ls/server/command/ViewElmCommandContribution.java index 73ceb49d..f682b816 100644 --- a/ls/server/src/main/java/org/opencds/cqf/cql/ls/server/command/ViewElmCommandContribution.java +++ b/ls/server/src/main/java/org/opencds/cqf/cql/ls/server/command/ViewElmCommandContribution.java @@ -4,9 +4,11 @@ import java.io.IOException; import java.net.URI; import java.util.Collections; +import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; import org.cqframework.cql.cql2elm.CqlCompiler; +import org.cqframework.cql.elm.serializing.ElmJsonLibraryWriter; import org.cqframework.cql.elm.serializing.ElmXmlLibraryWriter; import org.eclipse.lsp4j.ExecuteCommandParams; import org.hl7.elm.r1.Library; @@ -43,17 +45,37 @@ public CompletableFuture executeCommand(ExecuteCommandParams params) { // command // is XML and display it accordingly. private CompletableFuture viewElm(ExecuteCommandParams params) { - String uriString = ((JsonElement) params.getArguments().get(0)).getAsString(); - try { + List args = params.getArguments(); + + // Defensive check: ensure we have at least the URI + if (args == null || args.isEmpty()) { + return CompletableFuture.completedFuture(null); + } + + String uriString = ((JsonElement) args.get(0)).getAsString(); + + // Handle missing or null elmType by defaulting to "xml" + String elmType = "xml"; + if (args.size() > 1 && args.get(1) != null) { + elmType = ((JsonElement) args.get(1)).getAsString(); + } + try { URI uri = Uris.parseOrNull(uriString); CqlCompiler compiler = this.cqlCompilationManager.compile(uri); + if (compiler != null) { - return CompletableFuture.completedFuture(convertToXml(compiler.getLibrary())); + // Use .equalsIgnoreCase for better robustness + if ("xml".equalsIgnoreCase(elmType)) { + return CompletableFuture.completedFuture(convertToXml(compiler.getLibrary())); + } else { + return CompletableFuture.completedFuture(convertToJson(compiler.getLibrary())); + } } return CompletableFuture.completedFuture(null); } catch (Exception e) { + // Log the error here if possible to avoid "silent" failures return CompletableFuture.completedFuture(null); } } @@ -62,4 +84,9 @@ private static String convertToXml(Library library) throws IOException { ElmXmlLibraryWriter writer = new ElmXmlLibraryWriter(); return writer.writeAsString(library); } + + private static String convertToJson(Library library) throws IOException { + ElmJsonLibraryWriter writer = new ElmJsonLibraryWriter(); + return writer.writeAsString(library); + } } diff --git a/ls/server/src/test/java/org/opencds/cqf/cql/ls/server/command/ViewElmCommandContributionTest.java b/ls/server/src/test/java/org/opencds/cqf/cql/ls/server/command/ViewElmCommandContributionTest.java index af10508a..71adf71b 100644 --- a/ls/server/src/test/java/org/opencds/cqf/cql/ls/server/command/ViewElmCommandContributionTest.java +++ b/ls/server/src/test/java/org/opencds/cqf/cql/ls/server/command/ViewElmCommandContributionTest.java @@ -7,6 +7,8 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; import org.eclipse.lsp4j.ExecuteCommandParams; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -19,6 +21,7 @@ class ViewElmCommandContributionTest { private static ViewElmCommandContribution viewElmCommandContribution; + private Object expectedJson; @BeforeAll static void beforeAll() { @@ -42,15 +45,71 @@ void executeCommand() { params.setCommand("org.opencds.cqf.cql.ls.viewElm"); params.setArguments(Collections.singletonList( JsonParser.parseString("\"\\/org\\/opencds\\/cqf\\/cql\\/ls\\/server\\/One.cql\""))); - viewElmCommandContribution.executeCommand(params).thenAccept(result -> { - try { - String expectedXml = new String(Files.readAllBytes(Paths.get("src/test/resources/One.xml"))) - .trim() - .replaceAll("\\s+", ""); - assertEquals(expectedXml, result.toString().trim().replaceAll("\\s+", "")); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); + CompletableFuture future = viewElmCommandContribution + .executeCommand(params) + .thenAccept(result -> { + try { + String expectedXml = new String(Files.readAllBytes( + Paths.get("src/test/resources/org/opencds/cqf/cql/ls/server/One.xml"))) + .trim() + .replaceAll("\\s+", ""); + assertEquals(expectedXml, result.toString().trim().replaceAll("\\s+", "")); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + + // This ensures the test waits and fails if an exception occurs + future.join(); + } + + @Test + void executeCommandWithXmlElmType() { + ExecuteCommandParams params = new ExecuteCommandParams(); + params.setCommand("org.opencds.cqf.cql.ls.viewElm"); + params.setArguments(List.of( + JsonParser.parseString("\"\\/org\\/opencds\\/cqf\\/cql\\/ls\\/server\\/One.cql\""), + JsonParser.parseString("\"xml\""))); + CompletableFuture future = viewElmCommandContribution + .executeCommand(params) + .thenAccept(result -> { + try { + String expectedXml = new String(Files.readAllBytes( + Paths.get("src/test/resources/org/opencds/cqf/cql/ls/server/One.xml"))) + .trim() + .replaceAll("\\s+", ""); + assertEquals(expectedXml, result.toString().trim().replaceAll("\\s+", "")); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + + // This ensures the test waits and fails if an exception occurs + future.join(); + } + + @Test + void executeCommandWithJsonElmType() { + ExecuteCommandParams params = new ExecuteCommandParams(); + params.setCommand("org.opencds.cqf.cql.ls.viewElm"); + params.setArguments(List.of( + JsonParser.parseString("\"\\/org\\/opencds\\/cqf\\/cql\\/ls\\/server\\/One.cql\""), + JsonParser.parseString("\"json\""))); + CompletableFuture future = viewElmCommandContribution + .executeCommand(params) + .thenAccept(result -> { + try { + String expectedJson = new String(Files.readAllBytes( + Paths.get("src/test/resources/org/opencds/cqf/cql/ls/server/One.json"))) + .trim() + .replaceAll("\\s+", ""); + assertEquals(expectedJson, result.toString().trim().replaceAll("\\s+", "")); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + + // This ensures the test waits and fails if an exception occurs + future.join(); } } diff --git a/ls/server/src/test/resources/org/opencds/cqf/cql/ls/server/One.json b/ls/server/src/test/resources/org/opencds/cqf/cql/ls/server/One.json new file mode 100644 index 00000000..03a39373 --- /dev/null +++ b/ls/server/src/test/resources/org/opencds/cqf/cql/ls/server/One.json @@ -0,0 +1,87 @@ +{ + "library": { + "localId": "0", + "annotation": [ + { + "type": "CqlToElmInfo", + "translatorVersion": "4.1.0", + "translatorOptions": "EnableAnnotations,EnableLocators,DisableListDemotion,DisableListPromotion,EnableResultTypes", + "signatureLevel": "All" + }, + { + "type": "Annotation", + "t": [], + "s": { + "r": "208", + "s": [ + { + "value": [ + "", + "library One" + ] + } + ] + } + } + ], + "identifier": { + "id": "One" + }, + "schemaIdentifier": { + "id": "urn:hl7-org:elm", + "version": "r1" + }, + "usings": { + "def": [ + { + "localId": "1", + "localIdentifier": "System", + "uri": "urn:hl7-org:elm-types:r1", + "annotation": [] + } + ] + }, + "statements": { + "def": [ + { + "localId": "208", + "locator": "3:1-4:5", + "resultTypeName": "{urn:hl7-org:elm-types:r1}Integer", + "name": "One", + "context": "Unfiltered", + "accessLevel": "Public", + "annotation": [ + { + "type": "Annotation", + "t": [], + "s": { + "r": "208", + "s": [ + { + "r": "209", + "value": [ + "", + "define ", + "\"One\"", + ":\n ", + "1" + ] + } + ] + } + } + ], + "expression": { + "type": "Literal", + "localId": "209", + "locator": "4:5", + "resultTypeName": "{urn:hl7-org:elm-types:r1}Integer", + "valueType": "{urn:hl7-org:elm-types:r1}Integer", + "value": "1", + "annotation": [] + } + } + ] + } + } +} \ No newline at end of file diff --git a/ls/server/src/test/resources/org/opencds/cqf/cql/ls/server/One.xml b/ls/server/src/test/resources/org/opencds/cqf/cql/ls/server/One.xml index c5fe2a4e..2ccd488a 100644 --- a/ls/server/src/test/resources/org/opencds/cqf/cql/ls/server/One.xml +++ b/ls/server/src/test/resources/org/opencds/cqf/cql/ls/server/One.xml @@ -1,25 +1,28 @@ - - + + - + library One - + - + - - define "One": + + define "One": 1 - + \ No newline at end of file diff --git a/ls/service/pom.xml b/ls/service/pom.xml index 6b5134e8..55196c2b 100644 --- a/ls/service/pom.xml +++ b/ls/service/pom.xml @@ -11,7 +11,7 @@ org.opencds.cqf.cql.ls cql-ls - 4.1.2 + 4.1.2-SNAPSHOT ../../pom.xml diff --git a/plugin/debug/pom.xml b/plugin/debug/pom.xml index fe54770c..a71a9a33 100644 --- a/plugin/debug/pom.xml +++ b/plugin/debug/pom.xml @@ -11,7 +11,7 @@ org.opencds.cqf.cql.ls cql-ls - 4.1.2 + 4.1.2-SNAPSHOT ../../pom.xml diff --git a/pom.xml b/pom.xml index 28318d87..5fffd863 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.opencds.cqf.cql.ls cql-ls pom - 4.1.2 + 4.1.2-SNAPSHOT CQL Language Server A Language Server for CQL implementing the LSP