diff --git a/legend-engine-config/legend-engine-repl/legend-engine-repl-client/src/main/java/org/finos/legend/engine/repl/client/Client.java b/legend-engine-config/legend-engine-repl/legend-engine-repl-client/src/main/java/org/finos/legend/engine/repl/client/Client.java index 39ae7f10cf0..53011f092d7 100644 --- a/legend-engine-config/legend-engine-repl/legend-engine-repl-client/src/main/java/org/finos/legend/engine/repl/client/Client.java +++ b/legend-engine-config/legend-engine-repl/legend-engine-repl-client/src/main/java/org/finos/legend/engine/repl/client/Client.java @@ -89,63 +89,63 @@ public Client(MutableList replExtensions, MutableList replExtensions, MutableList completerExtensions, PlanExecutor planExecutor, Path homeDirectory) throws Exception { - this.replExtensions = replExtensions; - this.completerExtensions = completerExtensions; - this.planExecutor = planExecutor; - this.state = new ModelState(this.legendInterface, this.replExtensions); - this.terminal = TerminalBuilder.terminal(); - this.homeDirectory = homeDirectory; - this.documentation = DocumentationGeneration.buildDocumentation(); - - this.initialize(); - replExtensions.forEach(e -> e.initialize(this)); - - this.printDebug("[DEV] Legend REPL v" + DeploymentStateAndVersions.sdlc.buildVersion + " (" + DeploymentStateAndVersions.sdlc.commitIdAbbreviated + ")"); - if (System.getProperty("legend.repl.initializationMessage") != null) - { - this.printDebug(StringEscapeUtils.unescapeJava(System.getProperty("legend.repl.initializationMessage"))); - } - this.printDebug("Press 'Enter' or type 'help' to see the list of available commands."); - this.println("\n" + Logos.logos.get((int) (Logos.logos.size() * Math.random())) + "\n"); - - // NOTE: the order here matters, the default command 'help' should always go first - // and "catch-all" command 'execute' should always go last - this.commands = replExtensions - .flatCollect(ReplExtension::getExtraCommands) - .withAll( - Lists.mutable.with( - new Ext(this), - new Debug(this), - new Doc(this), - new Graph(this), - new Execute(this) - ) - ); - this.commands.add(0, new Help(this, this.commands)); - this.reader = LineReaderBuilder.builder() - .terminal(terminal) - // Configure history file - // See https://github.com/jline/jline3/wiki/History - .variable(LineReader.HISTORY_FILE, this.getHomeDir().resolve("history")) - .variable(LineReader.HISTORY_FILE_SIZE, 1_000) - .variable(LineReader.HISTORY_IGNORE, ": *") // make sure empty space(s) are not persisted - // Disable cursor jumping to opening brace when typing closing brace - // See https://github.com/jline/jline3/issues/216 - .variable(BLINK_MATCHING_PAREN, false) - // Make sure hitting at the beginning of line will insert a tab instead of triggering a completion - // which will cause error since the completer doesn't handle such case - // See https://github.com/jline/jline3/wiki/Completion - .option(LineReader.Option.INSERT_TAB, true) - // Make sure word navigation works properly with Alt + (left/right) arrow key - .variable(LineReader.WORDCHARS, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-$") - // Make sure to not break the completer when exclamation sign is present - // Do this by disabling history expansion - // See https://github.com/jline/jline3/issues/246 - .option(LineReader.Option.DISABLE_EVENT_EXPANSION, true) - .highlighter(new JLine3Highlighter()) - .parser(new JLine3Parser()) - .completer(new JLine3Completer(this.commands)) - .build(); + this.replExtensions = replExtensions; + this.completerExtensions = completerExtensions; + this.planExecutor = planExecutor; + this.state = new ModelState(this.legendInterface, this.replExtensions); + this.terminal = TerminalBuilder.terminal(); + this.homeDirectory = homeDirectory; + this.documentation = DocumentationGeneration.buildDocumentation(); + + this.initialize(); + replExtensions.forEach(e -> e.initialize(this)); + + this.printDebug("[DEV] Legend REPL v" + DeploymentStateAndVersions.sdlc.buildVersion + " (" + DeploymentStateAndVersions.sdlc.commitIdAbbreviated + ")"); + if (System.getProperty("legend.repl.initializationMessage") != null) + { + this.printDebug(StringEscapeUtils.unescapeJava(System.getProperty("legend.repl.initializationMessage"))); + } + this.printDebug("Press 'Enter' or type 'help' to see the list of available commands."); + this.println("\n" + Logos.logos.get((int) (Logos.logos.size() * Math.random())) + "\n"); + + // NOTE: the order here matters, the default command 'help' should always go first + // and "catch-all" command 'execute' should always go last + this.commands = replExtensions + .flatCollect(ReplExtension::getExtraCommands) + .withAll( + Lists.mutable.with( + new Ext(this), + new Debug(this), + new Doc(this), + new Graph(this), + new Execute(this) + ) + ); + this.commands.add(0, new Help(this, this.commands)); + this.reader = LineReaderBuilder.builder() + .terminal(terminal) + // Configure history file + // See https://github.com/jline/jline3/wiki/History + .variable(LineReader.HISTORY_FILE, this.getHomeDir().resolve("history")) + .variable(LineReader.HISTORY_FILE_SIZE, 1_000) + .variable(LineReader.HISTORY_IGNORE, ": *") // make sure empty space(s) are not persisted + // Disable cursor jumping to opening brace when typing closing brace + // See https://github.com/jline/jline3/issues/216 + .variable(BLINK_MATCHING_PAREN, false) + // Make sure hitting at the beginning of line will insert a tab instead of triggering a completion + // which will cause error since the completer doesn't handle such case + // See https://github.com/jline/jline3/wiki/Completion + .option(LineReader.Option.INSERT_TAB, true) + // Make sure word navigation works properly with Alt + (left/right) arrow key + .variable(LineReader.WORDCHARS, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-$") + // Make sure to not break the completer when exclamation sign is present + // Do this by disabling history expansion + // See https://github.com/jline/jline3/issues/246 + .option(LineReader.Option.DISABLE_EVENT_EXPANSION, true) + .highlighter(new JLine3Highlighter()) + .parser(new JLine3Parser()) + .completer(new JLine3Completer(this.commands)) + .build(); try { diff --git a/legend-engine-config/legend-engine-repl/legend-engine-repl-client/src/main/java/org/finos/legend/engine/repl/core/commands/Doc.java b/legend-engine-config/legend-engine-repl/legend-engine-repl-client/src/main/java/org/finos/legend/engine/repl/core/commands/Doc.java index 93e966f4bb7..b28f244d3f9 100644 --- a/legend-engine-config/legend-engine-repl/legend-engine-repl-client/src/main/java/org/finos/legend/engine/repl/core/commands/Doc.java +++ b/legend-engine-config/legend-engine-repl/legend-engine-repl-client/src/main/java/org/finos/legend/engine/repl/core/commands/Doc.java @@ -14,9 +14,13 @@ package org.finos.legend.engine.repl.core.commands; +import org.eclipse.collections.api.factory.Maps; +import org.eclipse.collections.api.factory.Sets; import org.eclipse.collections.api.list.MutableList; +import org.eclipse.collections.impl.factory.Lists; import org.eclipse.collections.impl.utility.ListIterate; import org.finos.legend.engine.repl.client.Client; +import org.finos.legend.engine.repl.client.jline3.JLine3Parser; import org.finos.legend.engine.repl.core.Command; import org.finos.legend.engine.repl.shared.DocumentationHelper; import org.finos.legend.pure.m3.pct.aggregate.model.FunctionDocumentation; @@ -24,34 +28,52 @@ import org.jline.reader.LineReader; import org.jline.reader.ParsedLine; +import java.util.List; +import java.util.Map; + public class Doc implements Command { private final Client client; + private final DocGroupCompleter completer; + private final Map functionDocIndex = Maps.mutable.empty(); public Doc(Client client) { this.client = client; + this.client.getDocumentedFunctions().forEach(key -> + { + FunctionDocumentation doc = this.client.getFunctionDocumentation(key); + String path = doc.functionDefinition.sourceId.substring(doc.reportScope.filePath.length(), doc.functionDefinition.sourceId.lastIndexOf(".pure")); + functionDocIndex.put(path, doc); + }); + this.completer = new DocGroupCompleter(functionDocIndex); } @Override public String documentation() { - return "doc "; + return "doc () | docFn "; } @Override public String description() { - return "show documentation of the specified Pure function"; + return "'doc' command supports browsing all supported Pure functions\n" + + "'docFn' command shows documentation of the specified Pure function"; } @Override public boolean process(String line) throws Exception { - if (line.startsWith("doc")) + if (line.startsWith("docFn")) { String[] tokens = line.split(" "); - String path = tokens[1]; + String path = tokens.length > 1 ? tokens[1] : ""; + if (path.isEmpty()) + { + client.printError("Function path is required"); + return true; + } FunctionDocumentation functionDocumentation = this.client.getFunctionDocumentation(path); if (functionDocumentation != null) { @@ -63,16 +85,84 @@ public boolean process(String line) throws Exception } return true; } + else if (line.startsWith("doc")) + { + String[] tokens = line.split(" "); + String path = tokens.length > 1 ? tokens[1] : ""; + if (path.isEmpty()) + { + client.printError("Function path is required"); + return true; + } + FunctionDocumentation functionDocumentation = this.functionDocIndex.get(path); + if (functionDocumentation != null) + { + client.println(DocumentationHelper.generateANSIFunctionDocumentation(functionDocumentation, client.getDocumentationAdapterKeys())); + } + else + { + client.printError("No documentation found for function: " + path); + } + return true; + } return false; } @Override public MutableList complete(String inScope, LineReader lineReader, ParsedLine parsedLine) { - if (inScope.startsWith("doc")) + if (inScope.startsWith("docFn")) { return ListIterate.collect(client.getDocumentedFunctions(), Candidate::new); } + else if (inScope.startsWith("doc")) + { + MutableList words = Lists.mutable.withAll(parsedLine.words()).drop(2); + String path = words.makeString(""); + MutableList list = Lists.mutable.empty(); + completer.complete(lineReader, new JLine3Parser.MyParsedLine(new JLine3Parser.ParserResult(parsedLine.line(), Lists.mutable.with("doc", " ", path))), list); + return list; + } return null; } + + private static class DocGroupCompleter implements org.jline.reader.Completer + { + private final Map functionDocIndex; + + public DocGroupCompleter(Map functionDocIndex) + { + this.functionDocIndex = functionDocIndex; + } + + public void complete(LineReader reader, ParsedLine commandLine, final List candidates) + { + String buffer = commandLine.word().substring(0, commandLine.wordCursor()); + String current; + String sep = "/"; + int lastSep = buffer.lastIndexOf(sep); + try + { + current = lastSep >= 0 ? buffer.substring(0, lastSep + 1) : ""; + Sets.mutable.withAll(functionDocIndex.keySet()) + .select(path -> path.startsWith(current)) + .collect(path -> + { + String childNode = path.substring(current.length()); + return current + childNode.substring(0, !childNode.contains(sep) ? childNode.length() : childNode.indexOf(sep) + 1); + }) + .toSortedList() + .forEach(value -> + { + candidates.add(value.endsWith(sep) + ? new Candidate(value, sep + value, null, null, "/", null, false) + : new Candidate(value, value, null, null, null, null, true)); + }); + } + catch (Exception e) + { + // Ignore + } + } + } } diff --git a/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/commands/DataCubeWalkthrough.java b/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/commands/DataCubeWalkthrough.java index 6f5a1125edf..4e34d065cc7 100644 --- a/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/commands/DataCubeWalkthrough.java +++ b/legend-engine-config/legend-engine-repl/legend-engine-repl-data-cube/src/main/java/org/finos/legend/engine/repl/dataCube/commands/DataCubeWalkthrough.java @@ -304,11 +304,11 @@ protected MutableList> getSteps() "history with ArrowUp/Down key, etc."))); this.println(""); this.println(wrap("The function documentation lookup tool can be quite helpful, for example, to view documentation and " + - "usages for 'filter', use the following command:")); - this.printCommand("doc meta::pure::functions::relation::filter"); + "usages for function 'filter', use the following command:")); + this.printCommand("doc collection/iteration/filter"); this.println(ansiDim(printRule(null))); this.println(DocumentationHelper.generateANSIFunctionDocumentation(this.client.getFunctionDocumentation("meta::pure::functions::relation::filter"), this.client.getDocumentationAdapterKeys())); - this.client.addCommandToHistory("doc meta::pure::functions::relation::filter"); + this.client.addCommandToHistory("doc collection/iteration/filter"); this.println(ansiDim(printRule(null))); this.println(""); this.println(wrap("Also, don't forget to hit the 'Tab' key while typing up an expression, the compiler can help validate " + diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/api/concept/Concept.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/api/concept/Concept.java index a61df113675..64c391fe083 100644 --- a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/api/concept/Concept.java +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/api/concept/Concept.java @@ -16,12 +16,13 @@ import io.swagger.annotations.Api; import org.finos.legend.engine.ide.session.PureSession; -import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.ConcreteFunctionDefinition; import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.property.QualifiedPropertyInstance; import org.finos.legend.pure.m3.navigation.Instance; import org.finos.legend.pure.m3.navigation.M3Paths; import org.finos.legend.pure.m3.navigation.M3Properties; import org.finos.legend.pure.m3.navigation.PackageableElement.PackageableElement; +import org.finos.legend.pure.m3.navigation.function.Function; +import org.finos.legend.pure.m3.pct.shared.PCTTools; import org.finos.legend.pure.m3.serialization.runtime.PureRuntime; import org.finos.legend.pure.m3.serialization.runtime.Source; import org.finos.legend.pure.m4.coreinstance.CoreInstance; @@ -77,24 +78,32 @@ public Response getConceptInfo(@Context HttpServletRequest request, @Context Htt CoreInstance found = src.navigate(Integer.parseInt(line), Integer.parseInt(column), session.getPureRuntime().getProcessorSupport()); if (found != null) { + String doc = PCTTools.getDoc(found, pureRuntime.getProcessorSupport()); if (Instance.instanceOf(found, M3Paths.AbstractProperty, session.getPureRuntime().getProcessorSupport())) { String path = PackageableElement.getUserPathForPackageableElement(found); CoreInstance owner = Instance.getValueForMetaPropertyToOneResolved(found, M3Properties.owner, session.getPureRuntime().getProcessorSupport()); String ownerPath = PackageableElement.getUserPathForPackageableElement(owner); - outputStream.write(("{\"path\":\"" + path + "\",\"pureName\":\"" + found.getValueForMetaPropertyToOne(M3Properties.name).getName() + "\",\"owner\":\"" + ownerPath + "\",\"pureType\":\"" + (found instanceof QualifiedPropertyInstance ? "QualifiedProperty" : "Property") + "\"}").getBytes()); + outputStream.write(("{\"path\":\"" + path + "\",\"pureName\":\"" + found.getValueForMetaPropertyToOne(M3Properties.name).getName() + "\",\"owner\":\"" + ownerPath + "\",\"pureType\":\"" + (found instanceof QualifiedPropertyInstance ? "QualifiedProperty" : "Property") + "\",\"doc\":" + (doc != null ? ("\"" + doc + "\"") : null) + "}").getBytes()); } else if (Instance.instanceOf(found, M3Paths.Enum, session.getPureRuntime().getProcessorSupport())) { String path = PackageableElement.getUserPathForPackageableElement(found); CoreInstance owner = found.getClassifier(); String ownerPath = PackageableElement.getUserPathForPackageableElement(owner); - outputStream.write(("{\"path\":\"" + path + "\",\"pureName\":\"" + found.getName() + "\",\"owner\":\"" + ownerPath + "\",\"pureType\":\"Enum\"}").getBytes()); + outputStream.write(("{\"path\":\"" + path + "\",\"pureName\":\"" + found.getName() + "\",\"owner\":\"" + ownerPath + "\",\"pureType\":\"Enum\",\"doc\":" + (doc != null ? ("\"" + doc + "\"") : null) + "}").getBytes()); + } + else if (Instance.instanceOf(found, M3Paths.ConcreteFunctionDefinition, session.getPureRuntime().getProcessorSupport()) || Instance.instanceOf(found, M3Paths.NativeFunction, session.getPureRuntime().getProcessorSupport())) + { + String path = PackageableElement.getUserPathForPackageableElement(found); + String grammarDoc = PCTTools.getGrammarDoc(found, pureRuntime.getProcessorSupport()); + String grammarChars = PCTTools.getGrammarCharacters(found, pureRuntime.getProcessorSupport()); + outputStream.write(("{\"path\":\"" + path + "\",\"pureName\":\"" + found.getValueForMetaPropertyToOne(M3Properties.functionName).getName() + "\",\"pureType\":\"" + found.getValueForMetaPropertyToOne(M3Properties.classifierGenericType).getValueForMetaPropertyToOne(M3Properties.rawType).getName() + "\",\"test\":" + (PCTTools.isPCTTest(found, pureRuntime.getProcessorSupport()) || PCTTools.isTest(found, pureRuntime.getProcessorSupport())) + ",\"pct\":" + PCTTools.isPCTTest(found, pureRuntime.getProcessorSupport()) + ",\"doc\":" + (doc != null ? ("\"" + doc + "\"") : null) + ",\"grammarDoc\":" + (grammarDoc != null ? ("\"" + grammarDoc + "\"") : null) + ",\"grammarChars\":" + (grammarChars != null ? ("\"" + grammarChars + "\"") : null) + ",\"signature\":\"" + Function.prettyPrint(found, pureRuntime.getProcessorSupport()) + "\"}").getBytes()); } else { String path = PackageableElement.getUserPathForPackageableElement(found); - outputStream.write(("{\"path\":\"" + path + "\",\"pureName\":\"" + (found instanceof ConcreteFunctionDefinition ? found.getValueForMetaPropertyToOne(M3Properties.functionName).getName() : found.getName()) + "\",\"pureType\":\"" + found.getValueForMetaPropertyToOne(M3Properties.classifierGenericType).getValueForMetaPropertyToOne(M3Properties.rawType).getName() + "\"}").getBytes()); + outputStream.write(("{\"path\":\"" + path + "\",\"pureName\":\"" + found.getName() + "\",\"pureType\":\"" + found.getValueForMetaPropertyToOne(M3Properties.classifierGenericType).getValueForMetaPropertyToOne(M3Properties.rawType).getName() + "\",\"doc\":" + (doc != null ? ("\"" + doc + "\"") : null) + "}").getBytes()); } } else diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/api/execution/test/TestRun.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/api/execution/test/TestRun.java index accf2a319a9..c10d6f76681 100644 --- a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/api/execution/test/TestRun.java +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/api/execution/test/TestRun.java @@ -36,6 +36,7 @@ import org.finos.legend.pure.m3.navigation.M3Properties; import org.finos.legend.pure.m3.navigation.PackageableElement.PackageableElement; import org.finos.legend.pure.m3.navigation.ProcessorSupport; +import org.finos.legend.pure.m3.pct.shared.PCTTools; import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.CodeStorageNode; import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.composite.CompositeCodeStorage; import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.vcs.MutableVersionControlledCodeStorage; @@ -71,10 +72,22 @@ public void run(PureSession pureSession, JSONObject extraParams, JSONArray modif String path = getPath(extraParams); String[] filterPaths = getFilterPaths(extraParams); boolean relevantTestsOnly = getRelevantTestsOnly(extraParams); + String pctAdapter = (String) extraParams.get("pctAdapter"); Predicate filterPredicate = getFilterPredicate(runtime, relevantTestsOnly); + if (pctAdapter != null) + { + filterPredicate = Predicates.and(filterPredicate, new Predicate() + { + @Override + public boolean accept(CoreInstance test) + { + return PCTTools.isPCTTest(test, runtime.getProcessorSupport()); + } + }); + } TestCollection collection = getTestCollection(pureSession, path, filterPaths, filterPredicate); - TestRunner runner = pureSession.newTestRunner(newId, collection); + TestRunner runner = pureSession.newTestRunner(newId, collection, pctAdapter); this.executorService.execute(runner); @@ -98,6 +111,7 @@ public void run(PureSession pureSession, JSONObject extraParams, JSONArray modif outputStream.write((",\"path\":\"" + path + "\"").getBytes()); outputStream.write((",\"filterPaths\":" + (filterPaths.length == 0 ? "[]" : ArrayIterate.makeString(filterPaths, "[\"", "\",\"", "\"]"))).getBytes()); outputStream.write((",\"relevantTestsOnly\":" + relevantTestsOnly).getBytes()); + outputStream.write((",\"pctAdapter\":\"" + pctAdapter + "\"").getBytes()); outputStream.write(",\"count\":".getBytes()); outputStream.write(Integer.toString(tests.size()).getBytes()); outputStream.write(",\"tests\":".getBytes()); @@ -116,13 +130,13 @@ public String valueOf(TestNode testNode) private String getPath(JSONObject extraParams) { - String path = (String)extraParams.get("path"); + String path = (String) extraParams.get("path"); return StringIterate.isEmpty(path) ? "::" : path; } private String[] getFilterPaths(JSONObject extraParams) { - JSONArray filterPaths = (JSONArray)extraParams.get("filterPaths"); + JSONArray filterPaths = (JSONArray) extraParams.get("filterPaths"); if (filterPaths != null) { String[] paths = new String[filterPaths.size()]; @@ -134,7 +148,7 @@ private String[] getFilterPaths(JSONObject extraParams) private boolean getRelevantTestsOnly(JSONObject extraParams) { - Boolean relevantTestsOnly = (Boolean)extraParams.get("relevantTestsOnly"); + Boolean relevantTestsOnly = (Boolean) extraParams.get("relevantTestsOnly"); return (relevantTestsOnly == null) ? false : relevantTestsOnly; } @@ -142,10 +156,10 @@ private Predicate getFilterPredicate(PureRuntime runtime, { if (!relevantTestsOnly) { - return null; + return Predicates.alwaysTrue(); } - final MutableVersionControlledCodeStorage codeStorage = (MutableVersionControlledCodeStorage)runtime.getCodeStorage(); + final MutableVersionControlledCodeStorage codeStorage = (MutableVersionControlledCodeStorage) runtime.getCodeStorage(); RichIterable modifiedUserFiles = codeStorage.getModifiedUserFiles(); if (modifiedUserFiles.isEmpty()) { diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/api/find/FindInSources.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/api/find/FindInSources.java index 476a0e7b913..e43c0490d11 100644 --- a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/api/find/FindInSources.java +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/api/find/FindInSources.java @@ -130,13 +130,13 @@ private int writeResultsJSON(OutputStream stream, RichIterable limit) + if (count >= limit) { break; } } stream.write("]}".getBytes()); - if (count > limit) + if (count >= limit) { break; } diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/session/PureSession.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/session/PureSession.java index d84b6253553..4fe72148b92 100644 --- a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/session/PureSession.java +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-http-server/src/main/java/org/finos/legend/engine/ide/session/PureSession.java @@ -140,9 +140,9 @@ public void setPureRuntimeOption(String optionName, boolean value) this.pureRuntimeOptions.put(optionName, value); } - public TestRunner newTestRunner(int testRunId, TestCollection collection) + public TestRunner newTestRunner(int testRunId, TestCollection collection, String pctAdapter) { - TestRunnerWrapper testRunnerWrapper = new TestRunnerWrapper(collection, this.getPureRuntime().executedTestTracker); + TestRunnerWrapper testRunnerWrapper = new TestRunnerWrapper(collection, this.getPureRuntime().executedTestTracker, pctAdapter); this.testRunnersById.put(testRunId, testRunnerWrapper); return testRunnerWrapper.testRunner; } @@ -328,9 +328,9 @@ private class TestRunnerWrapper private TestRunner testRunner; private final CallBack callBack; - private TestRunnerWrapper(TestCollection collection, CallBack callBack, final ExecutedTestTracker executedTestTracker) + private TestRunnerWrapper(TestCollection collection, CallBack callBack, final ExecutedTestTracker executedTestTracker, String pctAdapter) { - this.testRunner = new TestRunner(collection, false, PureSession.this.getFunctionExecution(), callBack) + this.testRunner = new TestRunner(collection, false, PureSession.this.getFunctionExecution(), callBack, pctAdapter) { @Override public void run() @@ -346,9 +346,9 @@ public void run() this.callBack = callBack; } - private TestRunnerWrapper(TestCollection collection, ExecutedTestTracker executedTestTracker) + private TestRunnerWrapper(TestCollection collection, ExecutedTestTracker executedTestTracker, String pctAdapter) { - this(collection, new CallBack(), executedTestTracker); + this(collection, new CallBack(), executedTestTracker, pctAdapter); } void stopAndClear() diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-pure/src/main/resources/pure_ide/concepts.pure b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-pure/src/main/resources/pure_ide/concepts.pure index b194a1c5e13..ecdbd8f57c7 100644 --- a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-pure/src/main/resources/pure_ide/concepts.pure +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-pure/src/main/resources/pure_ide/concepts.pure @@ -158,7 +158,7 @@ function <> meta::pure::ide::display_ide(elem:Any[1]):String[1] |'"/ide/pure/icons/play.png"', |'"/ide/pure/icons/modelElements/function.png"' ); - '{"li_attr":' + display_ide_attr($f) + ', "id":"'+$p->buildKey()+ '","text":"' + printFunctionSignature($f) + '", "icon":'+$icon+'}';, + '{"li_attr":' + display_ide_attr($f) + ', "id":"'+$p->buildKey()+ '","text":"' + printFunctionSignature($f) + '", "icon":'+$icon+', "test":'+ toString(meta::pure::ide::testing::isTest($f)) + ', "pct":' + toString(meta::pure::ide::testing::isPCT($f)) + '}';, f:NativeFunction[1] | '{"li_attr":' + display_ide_attr($f) + ', "id":"'+$p->buildKey()+ '","text":"' + printFunctionSignature($f) + '", "icon":"/ide/pure/icons/modelElements/function_parenthesis.png"}', e:Enumeration[1] | '{"li_attr":' + display_ide_attr($e) + ', "id":"'+$p->buildKey()+ '","text":"' + $e->id() + '", "icon":"/ide/pure/icons/modelElements/enumeration.gif"}', p:PrimitiveType[1] | '{"li_attr":' + display_ide_attr($p) + ', "id":"'+$p->buildKey()+ '","text":"' + $p->id() + '", "icon":"/ide/pure/icons/modelElements/primitive.png"}', @@ -230,5 +230,3 @@ function <> meta::pure::ide::tacticalDeprecated(element:Package[ ($model->isNotEmpty() && $element.package == $model && !$element.name->in(['domain', 'producers', 'external', 'consumers'])) ; } - - diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-pure/src/main/resources/pure_ide/testing.pure b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-pure/src/main/resources/pure_ide/testing.pure new file mode 100644 index 00000000000..4d5ab99fff8 --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-pure/src/main/resources/pure_ide/testing.pure @@ -0,0 +1,31 @@ +// Copyright 2024 Goldman Sachs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +function meta::pure::ide::testing::getPCTAdapters():Pair[*] +{ + meta::pure::test::pct::PCT->stereotype('adapter').modelElements->map(fn| + let name = $fn.taggedValues->filter(t|$t.tag.value == 'adapterName')->first().value; + if($name->isEmpty(),|'',|$name->toOne())->pair($fn->cast(@PackageableElement)->elementToPath()); + ) +} + +function meta::pure::ide::testing::isTest(f:FunctionDefinition[1]):Boolean[1] +{ + !$f->cast(@AnnotatedElement).stereotypes->filter(st|$st == test->stereotype('Test') || $st == meta::pure::test::pct::PCT->stereotype('test'))->isEmpty(); +} + +function meta::pure::ide::testing::isPCT(f:FunctionDefinition[1]):Boolean[1] +{ + !$f->cast(@AnnotatedElement).stereotypes->filter(st|$st == meta::pure::test::pct::PCT->stereotype('test'))->isEmpty(); +} \ No newline at end of file diff --git a/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding/legendJavaPlatformBinding/pct_java.pure b/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding/legendJavaPlatformBinding/pct_java.pure index a046d7d58db..00b0b0056f9 100644 --- a/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding/legendJavaPlatformBinding/pct_java.pure +++ b/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding/legendJavaPlatformBinding/pct_java.pure @@ -18,7 +18,7 @@ import meta::pure::executionPlan::platformBinding::localBinding::*; import meta::pure::executionPlan::platformBinding::*; import meta::pure::test::pct::*; -function <> meta::pure::executionPlan::platformBinding::legendJava::pct::testAdapterForJavaBindingExecution(f:Function<{->X[o]}>[1]):X[o] +function <> {PCT.adapterName='Java Platform Binding'} meta::pure::executionPlan::platformBinding::legendJava::pct::testAdapterForJavaBindingExecution(f:Function<{->X[o]}>[1]):X[o] { let debug = noDebug(); diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-PCT/legend-engine-pure-functions-relationalStore-PCT-pure/src/main/resources/core_external_test_connection/pct_relational.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-PCT/legend-engine-pure-functions-relationalStore-PCT-pure/src/main/resources/core_external_test_connection/pct_relational.pure index 595fe717a18..6564e970383 100644 --- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-PCT/legend-engine-pure-functions-relationalStore-PCT-pure/src/main/resources/core_external_test_connection/pct_relational.pure +++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-PCT/legend-engine-pure-functions-relationalStore-PCT-pure/src/main/resources/core_external_test_connection/pct_relational.pure @@ -29,7 +29,7 @@ import meta::pure::metamodel::relation::*; import meta::relational::tests::pct::process::*; import meta::pure::test::pct::*; -function <> meta::relational::tests::pct::testAdapterForRelationalWithH2Execution(f:Function<{->X[o]}>[1]):X[o] +function <> {PCT.adapterName='H2'} meta::relational::tests::pct::testAdapterForRelationalWithH2Execution(f:Function<{->X[o]}>[1]):X[o] { meta::relational::tests::pct::testAdapterForRelationalExecution( $f, @@ -37,7 +37,7 @@ function <> meta::relational::tests::pct::testAdapterForRelationalW ) } -function <> meta::relational::tests::pct::testAdapterForRelationalWithDuckDBExecution(f:Function<{->X[o]}>[1]):X[o] +function <> {PCT.adapterName='DuckDB'} meta::relational::tests::pct::testAdapterForRelationalWithDuckDBExecution(f:Function<{->X[o]}>[1]):X[o] { meta::relational::tests::pct::testAdapterForRelationalExecution( $f, @@ -45,7 +45,7 @@ function <> meta::relational::tests::pct::testAdapterForRelationalW ) } -function <> meta::relational::tests::pct::testAdapterForRelationalWithPostgresExecution(f:Function<{->X[o]}>[1]):X[o] +function <> {PCT.adapterName='PostgreSQL'} meta::relational::tests::pct::testAdapterForRelationalWithPostgresExecution(f:Function<{->X[o]}>[1]):X[o] { meta::relational::tests::pct::testAdapterForRelationalExecution( $f, @@ -53,7 +53,7 @@ function <> meta::relational::tests::pct::testAdapterForRelationalW ) } -function <> meta::relational::tests::pct::testAdapterForRelationalWithSnowflakeExecution(f:Function<{->X[o]}>[1]):X[o] +function <> {PCT.adapterName='Snowflake'} meta::relational::tests::pct::testAdapterForRelationalWithSnowflakeExecution(f:Function<{->X[o]}>[1]):X[o] { meta::relational::tests::pct::testAdapterForRelationalExecution( $f, diff --git a/pom.xml b/pom.xml index d8818857c94..2c703b437c0 100644 --- a/pom.xml +++ b/pom.xml @@ -107,9 +107,9 @@ - 5.21.0 + 5.21.1 0.25.7 - 12.54.0 + 12.59.0 legend-engine