Skip to content

Commit

Permalink
Merge pull request #514 from LakshanWeerasinghe/fix-#456
Browse files Browse the repository at this point in the history
Add api to get enclosed function def range
  • Loading branch information
LakshanWeerasinghe authored Dec 5, 2024
2 parents fb1b3d1 + 2be1a0e commit 5c85982
Show file tree
Hide file tree
Showing 12 changed files with 343 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com)
*
* WSO2 LLC. licenses this file to you 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.
*/

package io.ballerina.flowmodelgenerator.core;

import io.ballerina.compiler.syntax.tree.ModulePartNode;
import io.ballerina.compiler.syntax.tree.NonTerminalNode;
import io.ballerina.compiler.syntax.tree.SyntaxKind;
import io.ballerina.projects.Document;
import io.ballerina.tools.text.LinePosition;
import io.ballerina.tools.text.LineRange;
import io.ballerina.tools.text.TextRange;
import org.ballerinalang.langserver.common.utils.PositionUtil;

/**
* Enclosed node finder.
*
* @since 2.0.0
*/
public class EnclosedNodeFinder {

private final Document document;
private final LinePosition position;

public EnclosedNodeFinder(Document document, LinePosition position) {
this.document = document;
this.position = position;
}

public LineRange findEnclosedNode() {
ModulePartNode modulePartNode = document.syntaxTree().rootNode();
int positionOffset = PositionUtil.getPositionOffset(PositionUtil.toPosition(position), document.syntaxTree());
TextRange textRange = TextRange.from(positionOffset, 1);
NonTerminalNode nonTerminalNode = modulePartNode.findNode(textRange);
while (nonTerminalNode != null && nonTerminalNode.kind() != SyntaxKind.FUNCTION_DEFINITION) {
nonTerminalNode = nonTerminalNode.parent();
}
if (nonTerminalNode == null) {
throw new RuntimeException("No enclosed node found");
}
return nonTerminalNode.lineRange();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import io.ballerina.flowmodelgenerator.core.ConnectorGenerator;
import io.ballerina.flowmodelgenerator.core.CopilotContextGenerator;
import io.ballerina.flowmodelgenerator.core.DeleteNodeHandler;
import io.ballerina.flowmodelgenerator.core.EnclosedNodeFinder;
import io.ballerina.flowmodelgenerator.core.ErrorHandlerGenerator;
import io.ballerina.flowmodelgenerator.core.FunctionGenerator;
import io.ballerina.flowmodelgenerator.core.ModelGenerator;
Expand All @@ -36,6 +37,7 @@
import io.ballerina.flowmodelgenerator.core.SuggestedModelGenerator;
import io.ballerina.flowmodelgenerator.extension.request.ComponentDeleteRequest;
import io.ballerina.flowmodelgenerator.extension.request.CopilotContextRequest;
import io.ballerina.flowmodelgenerator.extension.request.EnclosedFuncDefRequest;
import io.ballerina.flowmodelgenerator.extension.request.FilePathRequest;
import io.ballerina.flowmodelgenerator.extension.request.FlowModelAvailableNodesRequest;
import io.ballerina.flowmodelgenerator.extension.request.FlowModelGeneratorRequest;
Expand All @@ -49,6 +51,7 @@
import io.ballerina.flowmodelgenerator.extension.request.SuggestedComponentRequest;
import io.ballerina.flowmodelgenerator.extension.response.ComponentDeleteResponse;
import io.ballerina.flowmodelgenerator.extension.response.CopilotContextResponse;
import io.ballerina.flowmodelgenerator.extension.response.EnclosedFuncDefResponse;
import io.ballerina.flowmodelgenerator.extension.response.FlowModelAvailableNodesResponse;
import io.ballerina.flowmodelgenerator.extension.response.FlowModelGeneratorResponse;
import io.ballerina.flowmodelgenerator.extension.response.FlowModelGetConnectorsResponse;
Expand Down Expand Up @@ -463,6 +466,29 @@ public CompletableFuture<FlowModelSourceGeneratorResponse> addErrorHandler(FileP
});
}

@JsonRequest
public CompletableFuture<EnclosedFuncDefResponse> getEnclosedFunctionDef(EnclosedFuncDefRequest request) {
return CompletableFuture.supplyAsync(() -> {
EnclosedFuncDefResponse response = new EnclosedFuncDefResponse();
try {
Path path = Path.of(request.filePath());
Project project = this.workspaceManager.loadProject(path);
Optional<Document> document = this.workspaceManager.document(path);
if (document.isEmpty()) {
return response;
}
EnclosedNodeFinder enclosedNodeFinder = new EnclosedNodeFinder(document.get(), request.position());
LineRange enclosedRange = enclosedNodeFinder.findEnclosedNode();
response.setFilePath(project.sourceRoot().resolve(enclosedRange.fileName()).toString());
response.setStartLine(enclosedRange.startLine());
response.setEndLine(enclosedRange.endLine());
} catch (Throwable e) {
response.setError(e);
}
return response;
});
}

private static String getRelativePath(Path projectPath, Path filePath) {
if (projectPath == null || filePath == null) {
return "";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com)
*
* WSO2 LLC. licenses this file to you 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.
*/

package io.ballerina.flowmodelgenerator.extension.request;

import io.ballerina.tools.text.LinePosition;

/**
* Represents the request for the flow model getEnclosedFlowDesignModel API.
*
* @param filePath The file path of the source file.
* @param position The position of the source.
*
* @since 2.0.0
*/
public record EnclosedFuncDefRequest(String filePath, LinePosition position) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com)
*
* WSO2 LLC. licenses this file to you 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.
*/

package io.ballerina.flowmodelgenerator.extension.response;

import io.ballerina.tools.text.LinePosition;

/**
* Represents the response for the flow model getEnclosedFlowDesignModel API.
*
* @since 2.0.0
*/
public class EnclosedFuncDefResponse extends AbstractFlowModelResponse {
private String filePath;
private LinePosition startLine;
private LinePosition endLine;

public void setFilePath(String filePath) {
this.filePath = filePath;
}

public void setStartLine(LinePosition startLine) {
this.startLine = startLine;
}

public void setEndLine(LinePosition endLine) {
this.endLine = endLine;
}

public String getFilePath() {
return filePath;
}

public LinePosition getStartLine() {
return startLine;
}

public LinePosition getEndLine() {
return endLine;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com)
*
* WSO2 LLC. licenses this file to you 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.
*/

package io.ballerina.flowmodelgenerator.extension;

import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import io.ballerina.flowmodelgenerator.extension.request.EnclosedFuncDefRequest;
import io.ballerina.tools.text.LinePosition;
import org.testng.Assert;
import org.testng.annotations.Test;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

/**
* Tests for the flow model source generator service.
*
* @since 2.0.0
*/
public class GetEnclosedFunctionDefTest extends AbstractLSTest {

@Override
@Test(dataProvider = "data-provider")
public void test(Path config) throws IOException {
Path configJsonPath = configDir.resolve(config);
TestConfig testConfig = gson.fromJson(Files.newBufferedReader(configJsonPath), TestConfig.class);

String filePath = getSourcePath(testConfig.filePath());
EnclosedFuncDefRequest request = new EnclosedFuncDefRequest(filePath, testConfig.position());
JsonObject response = getResponse(request);
JsonObject acutalJsonObj = testConfig.response();
acutalJsonObj.add("filePath", new JsonPrimitive(
getSourcePath(testConfig.response().get("filePath").getAsString())));
if (!testConfig.response().equals(response)) {
String pathToReplace = response.get("filePath").getAsString()
.replace(sourceDir.toString() + "/", "");
response.addProperty("filePath", pathToReplace);
TestConfig updatedConfig = new TestConfig(testConfig.description(), testConfig.filePath(),
testConfig.position(), response);
// updateConfig(configJsonPath, updatedConfig);
Assert.fail(String.format("Failed test: '%s' (%s)", testConfig.description(), configJsonPath));
}
}

@Override
protected String getResourceDir() {
return "get_enclosed_func_def";
}

@Override
protected Class<? extends AbstractLSTest> clazz() {
return GetEnclosedFunctionDefTest.class;
}

@Override
protected String getApiName() {
return "getEnclosedFunctionDef";
}

/**
* Represents the test configuration for the delete node test.
*
* @param description The description of the test.
* @param filePath The path to the source file that contains the nodes to be deleted.
* @param position The position of the node to be deleted.
* @param response The expected response.
*/
private record TestConfig(String description, String filePath, LinePosition position, JsonObject response) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"description": "current package reference",
"filePath": "proj_1/functions.bal",
"position": {
"line": 3,
"offset": 8
},
"response": {
"filePath" : "proj_1/functions.bal",
"startLine" : {
"line" : 0,
"offset" : 0
},
"endLine" : {
"line" : 6,
"offset" : 1
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"description": "current package reference",
"filePath": "proj_1/functions.bal",
"position": {
"line": 9,
"offset": 0
},
"response": {
"filePath": "proj_1/functions.bal",
"startLine": {
"line": 8,
"offset": 0
},
"endLine": {
"line": 10,
"offset": 1
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"description": "current package reference",
"filePath": "proj_1/functions.bal",
"position": {
"line": 15,
"offset": 4
},
"response": {
"filePath": "proj_1/functions.bal",
"startLine": {
"line": 12,
"offset": 0
},
"endLine": {
"line": 16,
"offset": 1
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
org = "wso2"
name = "proj_1"
version = "0.1.0"

bi = true
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
function foo() returns string {
int i;
for (int i = 0; i < 10; i++) {
i = i + 1;
}
return "Hello " + i.toString();
}

function bar() returns string {
return foo();
}

function baz() returns string {
int a = 1;
int b = 2;
return a + b;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
public function main() returns error? {
foo();
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ under the License.
<class name="io.ballerina.flowmodelgenerator.extension.ConfigVariablesUpdateTest"/>
<class name="io.ballerina.flowmodelgenerator.extension.DataMapManagerTypesTest"/>
<class name="io.ballerina.flowmodelgenerator.extension.ErrorHandlerGeneratorTest"/>
<class name="io.ballerina.flowmodelgenerator.extension.GetEnclosedFunctionDefTest"/>
</classes>
</test>
</suite>

0 comments on commit 5c85982

Please sign in to comment.