From 1fd888b32a2ba9f94205a2a094aad243093f1c9d Mon Sep 17 00:00:00 2001 From: LakshanWeerasinghe Date: Thu, 16 Jan 2025 00:57:25 +0530 Subject: [PATCH] Refactor code --- .../core/model/node/FunctionCall.java | 205 +++++------- .../core/model/node/MethodCall.java | 302 +++++++----------- .../model/node/RemoteActionCallBuilder.java | 4 +- .../model/node/ResourceActionCallBuilder.java | 4 +- .../core/utils/CommonUtils.java | 17 + .../core/utils/FlowNodeUtil.java | 41 +++ .../config/function_call-user.json | 2 +- .../config/method_call_user.json | 2 +- 8 files changed, 266 insertions(+), 311 deletions(-) create mode 100644 flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/utils/FlowNodeUtil.java diff --git a/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/FunctionCall.java b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/FunctionCall.java index 23fa1e287..bc76f562f 100644 --- a/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/FunctionCall.java +++ b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/FunctionCall.java @@ -38,6 +38,7 @@ import io.ballerina.flowmodelgenerator.core.model.Property; import io.ballerina.flowmodelgenerator.core.model.SourceBuilder; import io.ballerina.flowmodelgenerator.core.utils.CommonUtils; +import io.ballerina.flowmodelgenerator.core.utils.FlowNodeUtil; import io.ballerina.flowmodelgenerator.core.utils.ParamUtils; import io.ballerina.projects.PackageDescriptor; import io.ballerina.projects.Project; @@ -47,12 +48,17 @@ import org.eclipse.lsp4j.TextEdit; import java.nio.file.Path; -import java.util.LinkedHashMap; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +/** + * Represents a function call node. + * + * @since 2.0.0 + */ public class FunctionCall extends NodeBuilder { @Override @@ -63,101 +69,14 @@ public void setConcreteConstData() { @Override public void setConcreteTemplateData(TemplateContext context) { Codedata codedata = context.codedata(); - if (isLocalFunction(context.workspaceManager(), context.filePath(), codedata)) { - WorkspaceManager workspaceManager = context.workspaceManager(); - - try { - Project project = workspaceManager.loadProject(context.filePath()); - this.moduleInfo = ModuleInfo.from(project.currentPackage().getDefaultModule().descriptor()); - } catch (WorkspaceDocumentException | EventSyncException e) { - throw new RuntimeException("Error loading project: " + e.getMessage()); - } - SemanticModel semanticModel = workspaceManager.semanticModel(context.filePath()).orElseThrow(); - Optional outSymbol = semanticModel.moduleSymbols().stream() - .filter(symbol -> symbol.kind() == SymbolKind.FUNCTION && symbol.nameEquals(codedata.symbol())) - .findFirst(); - if (outSymbol.isEmpty()) { - throw new RuntimeException("Function not found: " + codedata.symbol()); - } - - FunctionSymbol functionSymbol = (FunctionSymbol) outSymbol.get(); - FunctionTypeSymbol functionTypeSymbol = functionSymbol.typeDescriptor(); - - metadata().label(codedata.symbol()); - codedata() - .node(NodeKind.FUNCTION_CALL) - .symbol(codedata.symbol()); - - LinkedHashMap stringParameterResultLinkedHashMap = - ParamUtils.buildFunctionParamResultMap(functionSymbol, semanticModel); - boolean hasOnlyRestParams = stringParameterResultLinkedHashMap.size() == 1; - for (ParameterResult paramResult : stringParameterResultLinkedHashMap.values()) { - if (paramResult.kind().equals(Parameter.Kind.PARAM_FOR_TYPE_INFER) - || paramResult.kind().equals(Parameter.Kind.INCLUDED_RECORD)) { - continue; - } - - String unescapedParamName = ParamUtils.removeLeadingSingleQuote(paramResult.name()); - Property.Builder> customPropBuilder = properties().custom(); - customPropBuilder - .metadata() - .label(unescapedParamName) - .description(paramResult.description()) - .stepOut() - .codedata() - .kind(paramResult.kind().name()) - .originalName(paramResult.name()) - .importStatements(paramResult.importStatements()) - .stepOut() - .placeholder(paramResult.defaultValue()) - .typeConstraint(paramResult.type()) - .editable() - .defaultable(paramResult.optional() == 1); - - if (paramResult.kind() == Parameter.Kind.INCLUDED_RECORD_REST) { - if (hasOnlyRestParams) { - customPropBuilder.defaultable(false); - } - unescapedParamName = "additionalValues"; - customPropBuilder.type(Property.ValueType.MAPPING_EXPRESSION_SET); - } else if (paramResult.kind() == Parameter.Kind.REST_PARAMETER) { - if (hasOnlyRestParams) { - customPropBuilder.defaultable(false); - } - customPropBuilder.type(Property.ValueType.EXPRESSION_SET); - } else if (paramResult.kind() == Parameter.Kind.REQUIRED) { - customPropBuilder.type(Property.ValueType.EXPRESSION).value(paramResult.defaultValue()); - } else { - customPropBuilder.type(Property.ValueType.EXPRESSION); - } - customPropBuilder - .stepOut() - .addProperty(unescapedParamName); - } - - functionTypeSymbol.returnTypeDescriptor().ifPresent(returnType -> { - String returnTypeName = CommonUtils.getTypeSignature(semanticModel, returnType, true, moduleInfo); - boolean editable = true; - if (returnTypeName.contains(RemoteActionCallBuilder.TARGET_TYPE_KEY)) { - returnTypeName = returnTypeName.replace(RemoteActionCallBuilder.TARGET_TYPE_KEY, "json"); - editable = true; - } - properties() - .type(returnTypeName, editable) - .data(returnTypeName, context.getAllVisibleSymbolNames(), Property.VARIABLE_NAME); - }); - TypeSymbol errorTypeSymbol = semanticModel.types().ERROR; - int returnError = functionTypeSymbol.returnTypeDescriptor() - .map(returnTypeDesc -> - CommonUtils.subTypeOf(returnTypeDesc, errorTypeSymbol) ? 1 : 0).orElse(0); - if (returnError == 1 && CommonUtils.withinDoClause(context.workspaceManager(), - context.filePath(), context.codedata().lineRange())) { - properties().checkError(true); - } - return; + handleLocalFunction(context, codedata); + } else { + handleImportedFunction(context, codedata); } + } + private void handleImportedFunction(TemplateContext context, Codedata codedata) { DatabaseManager dbManager = DatabaseManager.getInstance(); Optional functionResult = dbManager.getFunction(codedata.org(), codedata.module(), codedata.symbol(), @@ -179,27 +98,74 @@ public void setConcreteTemplateData(TemplateContext context) { .version(codedata.version()) .symbol(codedata.symbol()); - List functionParameters = dbManager.getFunctionParameters(function.functionId()); + setCustomProperties(dbManager.getFunctionParameters(function.functionId())); + + String returnTypeName = function.returnType(); + if (CommonUtils.hasReturn(function.returnType())) { + setReturnTypeProperties(returnTypeName, context); + } + + if (function.returnError() == 1) { + properties().checkError(true); + } + } + + private void handleLocalFunction(TemplateContext context, Codedata codedata) { + WorkspaceManager workspaceManager = context.workspaceManager(); + Project project = CommonUtils.loadProject(workspaceManager, context.filePath()); + this.moduleInfo = ModuleInfo.from(project.currentPackage().getDefaultModule().descriptor()); + + SemanticModel semanticModel = workspaceManager.semanticModel(context.filePath()).orElseThrow(); + Optional outSymbol = semanticModel.moduleSymbols().stream() + .filter(symbol -> symbol.kind() == SymbolKind.FUNCTION && symbol.nameEquals(codedata.symbol())) + .findFirst(); + if (outSymbol.isEmpty()) { + throw new RuntimeException("Function not found: " + codedata.symbol()); + } + + FunctionSymbol functionSymbol = (FunctionSymbol) outSymbol.get(); + FunctionTypeSymbol functionTypeSymbol = functionSymbol.typeDescriptor(); + + metadata().label(codedata.symbol()); + codedata() + .node(NodeKind.FUNCTION_CALL) + .symbol(codedata.symbol()); + + setCustomProperties(ParamUtils.buildFunctionParamResultMap(functionSymbol, semanticModel).values()); + functionTypeSymbol.returnTypeDescriptor().ifPresent(returnType -> { + String returnTypeName = CommonUtils.getTypeSignature(semanticModel, returnType, true, moduleInfo); + setReturnTypeProperties(returnTypeName, context); + }); + TypeSymbol errorTypeSymbol = semanticModel.types().ERROR; + int returnError = functionTypeSymbol.returnTypeDescriptor() + .map(returnTypeDesc -> + CommonUtils.subTypeOf(returnTypeDesc, errorTypeSymbol) ? 1 : 0).orElse(0); + if (returnError == 1 && CommonUtils.withinDoClause(context.workspaceManager(), + context.filePath(), context.codedata().lineRange())) { + properties().checkError(true); + } + } + + private void setCustomProperties(Collection functionParameters) { boolean hasOnlyRestParams = functionParameters.size() == 1; - for (ParameterResult paramResult : functionParameters) { + for (ParameterResult paramResult :functionParameters) { if (paramResult.kind().equals(Parameter.Kind.PARAM_FOR_TYPE_INFER) || paramResult.kind().equals(Parameter.Kind.INCLUDED_RECORD)) { continue; } String unescapedParamName = ParamUtils.removeLeadingSingleQuote(paramResult.name()); - Property.Builder> customPropBuilder = properties().custom(); customPropBuilder .metadata() - .label(unescapedParamName) - .description(paramResult.description()) - .stepOut() + .label(unescapedParamName) + .description(paramResult.description()) + .stepOut() .codedata() - .kind(paramResult.kind().name()) - .originalName(paramResult.name()) - .importStatements(paramResult.importStatements()) - .stepOut() + .kind(paramResult.kind().name()) + .originalName(paramResult.name()) + .importStatements(paramResult.importStatements()) + .stepOut() .placeholder(paramResult.defaultValue()) .typeConstraint(paramResult.type()) .editable() @@ -225,31 +191,15 @@ public void setConcreteTemplateData(TemplateContext context) { .stepOut() .addProperty(unescapedParamName); } - - String returnTypeName = function.returnType(); - if (CommonUtils.hasReturn(function.returnType())) { - boolean editable = false; - if (returnTypeName.contains(RemoteActionCallBuilder.TARGET_TYPE_KEY)) { - returnTypeName = returnTypeName.replace(RemoteActionCallBuilder.TARGET_TYPE_KEY, "json"); - editable = true; - } - properties() - .type(returnTypeName, editable) - .data(function.returnType(), context.getAllVisibleSymbolNames(), Property.VARIABLE_NAME); - } - - if (function.returnError() == 1) { - properties().checkError(true); - } } + @Override public Map> toSource(SourceBuilder sourceBuilder) { sourceBuilder.newVariable(); FlowNode flowNode = sourceBuilder.flowNode; - if (flowNode.properties().containsKey(Property.CHECK_ERROR_KEY) && - flowNode.properties().get(Property.CHECK_ERROR_KEY).value().equals(true)) { + if (FlowNodeUtil.hasCheckKeyFlagSet(flowNode)) { sourceBuilder.token().keyword(SyntaxKind.CHECK_KEYWORD); } @@ -278,7 +228,18 @@ public Map> toSource(SourceBuilder sourceBuilder) { .build(); } - public boolean isLocalFunction(WorkspaceManager workspaceManager, Path filePath, Codedata codedata) { + private void setReturnTypeProperties(String returnTypeName, TemplateContext context) { + boolean editable = false; + if (returnTypeName.contains(RemoteActionCallBuilder.TARGET_TYPE_KEY)) { + returnTypeName = returnTypeName.replace(RemoteActionCallBuilder.TARGET_TYPE_KEY, "json"); + editable = true; + } + properties() + .type(returnTypeName, editable) + .data(returnTypeName, context.getAllVisibleSymbolNames(), Property.VARIABLE_NAME); + } + + public static boolean isLocalFunction(WorkspaceManager workspaceManager, Path filePath, Codedata codedata) { if (codedata.org() == null || codedata.module() == null || codedata.version() == null) { return true; } diff --git a/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/MethodCall.java b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/MethodCall.java index 52c926046..1ef427891 100644 --- a/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/MethodCall.java +++ b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/MethodCall.java @@ -39,18 +39,17 @@ import io.ballerina.flowmodelgenerator.core.model.Property; import io.ballerina.flowmodelgenerator.core.model.SourceBuilder; import io.ballerina.flowmodelgenerator.core.utils.CommonUtils; +import io.ballerina.flowmodelgenerator.core.utils.FlowNodeUtil; import io.ballerina.flowmodelgenerator.core.utils.ParamUtils; import io.ballerina.projects.Document; -import io.ballerina.projects.PackageDescriptor; import io.ballerina.projects.Project; +import io.ballerina.tools.text.LinePosition; import org.ballerinalang.langserver.common.utils.CommonUtil; -import org.ballerinalang.langserver.commons.eventsync.exceptions.EventSyncException; -import org.ballerinalang.langserver.commons.workspace.WorkspaceDocumentException; import org.ballerinalang.langserver.commons.workspace.WorkspaceManager; import org.eclipse.lsp4j.TextEdit; import java.nio.file.Path; -import java.util.LinkedHashMap; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; @@ -69,132 +68,45 @@ public void setConcreteConstData() { } @Override - public void setConcreteTemplateData(TemplateContext context) { - Codedata codedata = context.codedata(); - - if (isLocalFunction(context.workspaceManager(), context.filePath(), codedata)) { - WorkspaceManager workspaceManager = context.workspaceManager(); - - try { - Project project = workspaceManager.loadProject(context.filePath()); - this.moduleInfo = ModuleInfo.from(project.currentPackage().getDefaultModule().descriptor()); - } catch (WorkspaceDocumentException | EventSyncException e) { - throw new RuntimeException("Error loading project: " + e.getMessage()); - } - SemanticModel semanticModel = workspaceManager.semanticModel(context.filePath()).orElseThrow(); - Optional document = workspaceManager.document(context.filePath()); - if (document.isEmpty()) { - throw new RuntimeException("Document not found: " + context.filePath()); - } - - Optional varSymbol = semanticModel.visibleSymbols(document.get(), context.position()) - .stream() - .filter(symbol -> symbol.getName().orElse("").equals(codedata.parentSymbol())) - .filter(symbol -> symbol.kind() == SymbolKind.VARIABLE) - .map(symbol -> (VariableSymbol) symbol) - .findFirst(); - - if (varSymbol.isEmpty()) { - throw new RuntimeException("Variable not found: " + codedata.parentSymbol()); - } - TypeSymbol rawType = CommonUtil.getRawType(varSymbol.get().typeDescriptor()); - if (!(rawType instanceof ObjectTypeSymbol objectTypeSymbol)) { - throw new RuntimeException("Invalid object type: " + rawType); - } - MethodSymbol methodSymbol = objectTypeSymbol.methods().get(codedata.symbol()); - if (methodSymbol == null) { - throw new RuntimeException("Method not found: " + codedata.symbol()); - } - FunctionTypeSymbol functionTypeSymbol = methodSymbol.typeDescriptor(); - - metadata().label(codedata.symbol()); - codedata() - .node(NodeKind.METHOD_CALL) - .symbol(codedata.symbol()); - properties() - .custom() - .metadata() - .label(Property.CONNECTION_LABEL) - .description(Property.CONNECTION_KEY) - .stepOut() - .value(codedata.parentSymbol()) - .type(Property.ValueType.IDENTIFIER) - .stepOut() - .addProperty(Property.CONNECTION_KEY); + public Map> toSource(SourceBuilder sourceBuilder) { + sourceBuilder.newVariable(); + FlowNode flowNode = sourceBuilder.flowNode; - LinkedHashMap stringParameterResultLinkedHashMap = - ParamUtils.buildFunctionParamResultMap(methodSymbol, semanticModel); - boolean hasOnlyRestParams = stringParameterResultLinkedHashMap.size() == 1; - for (ParameterResult paramResult : stringParameterResultLinkedHashMap.values()) { - if (paramResult.kind().equals(Parameter.Kind.PARAM_FOR_TYPE_INFER) - || paramResult.kind().equals(Parameter.Kind.INCLUDED_RECORD)) { - continue; - } + if (FlowNodeUtil.hasCheckKeyFlagSet(flowNode)) { + sourceBuilder.token().keyword(SyntaxKind.CHECK_KEYWORD); + } - String unescapedParamName = ParamUtils.removeLeadingSingleQuote(paramResult.name()); - Property.Builder> customPropBuilder = properties().custom(); - customPropBuilder - .metadata() - .label(unescapedParamName) - .description(paramResult.description()) - .stepOut() - .codedata() - .kind(paramResult.kind().name()) - .originalName(paramResult.name()) - .importStatements(paramResult.importStatements()) - .stepOut() - .placeholder(paramResult.defaultValue()) - .typeConstraint(paramResult.type()) - .editable() - .defaultable(paramResult.optional() == 1); + Optional connection = flowNode.getProperty(Property.CONNECTION_KEY); + if (connection.isEmpty()) { + throw new IllegalStateException("Object must be defined for a method call node"); + } - if (paramResult.kind() == Parameter.Kind.INCLUDED_RECORD_REST) { - if (hasOnlyRestParams) { - customPropBuilder.defaultable(false); - } - unescapedParamName = "additionalValues"; - customPropBuilder.type(Property.ValueType.MAPPING_EXPRESSION_SET); - } else if (paramResult.kind() == Parameter.Kind.REST_PARAMETER) { - if (hasOnlyRestParams) { - customPropBuilder.defaultable(false); - } - customPropBuilder.type(Property.ValueType.EXPRESSION_SET); - } else if (paramResult.kind() == Parameter.Kind.REQUIRED) { - customPropBuilder.type(Property.ValueType.EXPRESSION).value(paramResult.defaultValue()); - } else { - customPropBuilder.type(Property.ValueType.EXPRESSION); - } - customPropBuilder - .stepOut() - .addProperty(unescapedParamName); - } + return sourceBuilder.token() + .name(connection.get().toSourceCode()) + .keyword(SyntaxKind.DOT_TOKEN) + .name(flowNode.metadata().label()) + .stepOut() + .functionParameters(flowNode, Set.of(Property.CONNECTION_KEY, Property.VARIABLE_KEY, Property.TYPE_KEY, + Property.CHECK_ERROR_KEY, "view")) + .textEdit(false) + .acceptImport(sourceBuilder.filePath) + .build(); + } - functionTypeSymbol.returnTypeDescriptor().ifPresent(returnType -> { - String returnTypeName = CommonUtils.getTypeSignature(semanticModel, returnType, true, moduleInfo); - boolean editable = true; - if (returnTypeName.contains(RemoteActionCallBuilder.TARGET_TYPE_KEY)) { - returnTypeName = returnTypeName.replace(RemoteActionCallBuilder.TARGET_TYPE_KEY, "json"); - editable = true; - } - properties() - .type(returnTypeName, editable) - .data(returnTypeName, context.getAllVisibleSymbolNames(), Property.VARIABLE_NAME); - }); - TypeSymbol errorTypeSymbol = semanticModel.types().ERROR; - int returnError = functionTypeSymbol.returnTypeDescriptor() - .map(returnTypeDesc -> - CommonUtils.subTypeOf(returnTypeDesc, errorTypeSymbol) ? 1 : 0).orElse(0); - if (returnError == 1 && CommonUtils.withinDoClause(context.workspaceManager(), - context.filePath(), context.codedata().lineRange())) { - properties().checkError(true); - } - return; + @Override + public void setConcreteTemplateData(TemplateContext context) { + Codedata codedata = context.codedata(); + if (FunctionCall.isLocalFunction(context.workspaceManager(), context.filePath(), codedata)) { + handleLocalObjMethods(context, codedata); + } else { + handleImportedModuleObjMethods(context, codedata); } + } + private void handleImportedModuleObjMethods(TemplateContext context, Codedata codedata) { DatabaseManager dbManager = DatabaseManager.getInstance(); - Optional functionResult = - dbManager.getFunction(codedata.org(), codedata.module(), codedata.symbol(), - DatabaseManager.FunctionKind.FUNCTION); + Optional functionResult = dbManager.getFunction(codedata.org(), codedata.module(), + codedata.symbol(), DatabaseManager.FunctionKind.FUNCTION); if (functionResult.isEmpty()) { throw new RuntimeException("Method not found: " + codedata.symbol()); @@ -212,28 +124,80 @@ public void setConcreteTemplateData(TemplateContext context) { .version(codedata.version()) .id(function.functionId()) .symbol(codedata.symbol()); + setExpressionProperty(codedata); + setCustomProperties(dbManager.getFunctionParameters(function.functionId())); + + String returnTypeName = function.returnType(); + if (CommonUtils.hasReturn(function.returnType())) { + setReturnTypeProperties(returnTypeName, context); + } + + if (function.returnError() == 1) { + properties().checkError(true); + } + } + + private void handleLocalObjMethods(TemplateContext context, Codedata codedata) { + WorkspaceManager workspaceManager = context.workspaceManager(); + Project project = CommonUtils.loadProject(workspaceManager, context.filePath()); + this.moduleInfo = ModuleInfo.from(project.currentPackage().getDefaultModule().descriptor()); + + SemanticModel semanticModel = workspaceManager.semanticModel(context.filePath()).orElseThrow(); + Document document = workspaceManager.document(context.filePath()).orElseThrow(); + + VariableSymbol varSymbol = findVariableSymbol(semanticModel, document, context.position(), + codedata.parentSymbol()); + ObjectTypeSymbol objectTypeSymbol = getObjectTypeSymbol(varSymbol); + + MethodSymbol methodSymbol = objectTypeSymbol.methods().get(codedata.symbol()); + if (methodSymbol == null) { + throw new RuntimeException("Method not found: " + codedata.symbol()); + } + + metadata().label(codedata.symbol()); + codedata() + .node(NodeKind.METHOD_CALL) + .symbol(codedata.symbol()); + setExpressionProperty(codedata); + setCustomProperties(ParamUtils.buildFunctionParamResultMap(methodSymbol, semanticModel).values()); + FunctionTypeSymbol functionTypeSymbol = methodSymbol.typeDescriptor(); + + functionTypeSymbol.returnTypeDescriptor().ifPresent(returnType -> { + String returnTypeName = CommonUtils.getTypeSignature(semanticModel, returnType, true, moduleInfo); + setReturnTypeProperties(returnTypeName, context); + }); + TypeSymbol errorTypeSymbol = semanticModel.types().ERROR; + int returnError = functionTypeSymbol.returnTypeDescriptor() + .map(returnTypeDesc -> CommonUtils.subTypeOf(returnTypeDesc, errorTypeSymbol) ? 1 : 0).orElse(0); + if (returnError == 1 && CommonUtils.withinDoClause(context.workspaceManager(), + context.filePath(), context.codedata().lineRange())) { + properties().checkError(true); + } + } + + private void setExpressionProperty(Codedata codedata) { properties() .custom() .metadata() - .label(Property.CONNECTION_LABEL) - .description(Property.CONNECTION_KEY) - .stepOut() + .label(Property.CONNECTION_LABEL) + .description(Property.CONNECTION_KEY) + .stepOut() .value(codedata.parentSymbol()) .type(Property.ValueType.IDENTIFIER) .stepOut() .addProperty(Property.CONNECTION_KEY); + } - List functionParameters = dbManager.getFunctionParameters(function.functionId()); + private void setCustomProperties(Collection functionParameters) { boolean hasOnlyRestParams = functionParameters.size() == 1; - for (ParameterResult paramResult : functionParameters) { + for (ParameterResult paramResult :functionParameters) { if (paramResult.kind().equals(Parameter.Kind.PARAM_FOR_TYPE_INFER) || paramResult.kind().equals(Parameter.Kind.INCLUDED_RECORD)) { continue; } String unescapedParamName = ParamUtils.removeLeadingSingleQuote(paramResult.name()); - Property.Builder> customPropBuilder = properties().custom(); customPropBuilder .metadata() @@ -270,68 +234,40 @@ public void setConcreteTemplateData(TemplateContext context) { .stepOut() .addProperty(unescapedParamName); } - - String returnTypeName = function.returnType(); - if (CommonUtils.hasReturn(function.returnType())) { - boolean editable = false; - if (returnTypeName.contains(RemoteActionCallBuilder.TARGET_TYPE_KEY)) { - returnTypeName = returnTypeName.replace(RemoteActionCallBuilder.TARGET_TYPE_KEY, "json"); - editable = true; - } - properties() - .type(returnTypeName, editable) - .data(function.returnType(), context.getAllVisibleSymbolNames(), Property.VARIABLE_NAME); - } - - if (function.returnError() == 1) { - properties().checkError(true); - } } - @Override - public Map> toSource(SourceBuilder sourceBuilder) { - sourceBuilder.newVariable(); - FlowNode flowNode = sourceBuilder.flowNode; - - if (flowNode.properties().containsKey(Property.CHECK_ERROR_KEY) && - flowNode.properties().get(Property.CHECK_ERROR_KEY).value().equals(true)) { - sourceBuilder.token().keyword(SyntaxKind.CHECK_KEYWORD); + private void setReturnTypeProperties(String returnTypeName, TemplateContext context) { + boolean editable = false; + if (returnTypeName.contains(RemoteActionCallBuilder.TARGET_TYPE_KEY)) { + returnTypeName = returnTypeName.replace(RemoteActionCallBuilder.TARGET_TYPE_KEY, "json"); + editable = true; } + properties() + .type(returnTypeName, editable) + .data(returnTypeName, context.getAllVisibleSymbolNames(), Property.VARIABLE_NAME); + } - Optional connection = flowNode.getProperty(Property.CONNECTION_KEY); - if (connection.isEmpty()) { - throw new IllegalStateException("Client must be defined for an action call node"); + private ObjectTypeSymbol getObjectTypeSymbol(VariableSymbol varSymbol) { + TypeSymbol rawType = CommonUtil.getRawType(varSymbol.typeDescriptor()); + if (!(rawType instanceof ObjectTypeSymbol objectTypeSymbol)) { + throw new RuntimeException("Invalid object type: " + rawType); } - - String methodCall = flowNode.metadata().label(); - return sourceBuilder.token() - .name(connection.get().toSourceCode()) - .keyword(SyntaxKind.DOT_TOKEN) - .name(methodCall) - .stepOut() - .functionParameters(flowNode, Set.of(Property.CONNECTION_KEY, Property.VARIABLE_KEY, Property.TYPE_KEY, - Property.CHECK_ERROR_KEY, "view")) - .textEdit(false) - .acceptImport(sourceBuilder.filePath) - .build(); + return objectTypeSymbol; } - public boolean isLocalFunction(WorkspaceManager workspaceManager, Path filePath, Codedata codedata) { - if (codedata.org() == null || codedata.module() == null || codedata.version() == null) { - return true; - } - try { - Project project = workspaceManager.loadProject(filePath); - PackageDescriptor descriptor = project.currentPackage().descriptor(); - String packageOrg = descriptor.org().value(); - String packageName = descriptor.name().value(); - String packageVersion = descriptor.version().value().toString(); + private VariableSymbol findVariableSymbol(SemanticModel semanticModel, Document document, + LinePosition position, String exprSymbol) { + + Optional varSymbol = semanticModel.visibleSymbols(document, position) + .stream() + .filter(symbol -> symbol.getName().orElse("").equals(exprSymbol)) + .filter(symbol -> symbol.kind() == SymbolKind.VARIABLE) + .map(symbol -> (VariableSymbol) symbol) + .findFirst(); - return packageOrg.equals(codedata.org()) - && packageName.equals(codedata.module()) - && packageVersion.equals(codedata.version()); - } catch (WorkspaceDocumentException | EventSyncException e) { - return false; + if (varSymbol.isEmpty()) { + throw new RuntimeException("Variable not found: " + exprSymbol); } + return varSymbol.get(); } } diff --git a/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/RemoteActionCallBuilder.java b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/RemoteActionCallBuilder.java index 12d5b6ae6..c16ec8c38 100644 --- a/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/RemoteActionCallBuilder.java +++ b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/RemoteActionCallBuilder.java @@ -31,6 +31,7 @@ import io.ballerina.flowmodelgenerator.core.model.Property; import io.ballerina.flowmodelgenerator.core.model.SourceBuilder; import io.ballerina.flowmodelgenerator.core.utils.CommonUtils; +import io.ballerina.flowmodelgenerator.core.utils.FlowNodeUtil; import io.ballerina.flowmodelgenerator.core.utils.ParamUtils; import org.eclipse.lsp4j.TextEdit; @@ -59,8 +60,7 @@ public Map> toSource(SourceBuilder sourceBuilder) { sourceBuilder.newVariable(); FlowNode flowNode = sourceBuilder.flowNode; - if (flowNode.properties().containsKey(Property.CHECK_ERROR_KEY) && - flowNode.properties().get(Property.CHECK_ERROR_KEY).value().equals(true)) { + if (FlowNodeUtil.hasCheckKeyFlagSet(flowNode)) { sourceBuilder.token().keyword(SyntaxKind.CHECK_KEYWORD); } diff --git a/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/ResourceActionCallBuilder.java b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/ResourceActionCallBuilder.java index 366758ab7..8daa4898d 100644 --- a/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/ResourceActionCallBuilder.java +++ b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/ResourceActionCallBuilder.java @@ -32,6 +32,7 @@ import io.ballerina.flowmodelgenerator.core.model.PropertyCodedata; import io.ballerina.flowmodelgenerator.core.model.SourceBuilder; import io.ballerina.flowmodelgenerator.core.utils.CommonUtils; +import io.ballerina.flowmodelgenerator.core.utils.FlowNodeUtil; import io.ballerina.flowmodelgenerator.core.utils.ParamUtils; import org.eclipse.lsp4j.TextEdit; @@ -62,8 +63,7 @@ public Map> toSource(SourceBuilder sourceBuilder) { sourceBuilder.newVariable(); FlowNode flowNode = sourceBuilder.flowNode; - if (flowNode.properties().containsKey(Property.CHECK_ERROR_KEY) && - flowNode.properties().get(Property.CHECK_ERROR_KEY).value().equals(true)) { + if (FlowNodeUtil.hasCheckKeyFlagSet(flowNode)) { sourceBuilder.token().keyword(SyntaxKind.CHECK_KEYWORD); } diff --git a/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/utils/CommonUtils.java b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/utils/CommonUtils.java index d1dc84d20..1ad9717fb 100644 --- a/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/utils/CommonUtils.java +++ b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/utils/CommonUtils.java @@ -58,6 +58,8 @@ import io.ballerina.tools.text.LineRange; import io.ballerina.tools.text.TextRange; import org.ballerinalang.langserver.common.utils.CommonUtil; +import org.ballerinalang.langserver.commons.eventsync.exceptions.EventSyncException; +import org.ballerinalang.langserver.commons.workspace.WorkspaceDocumentException; import org.ballerinalang.langserver.commons.workspace.WorkspaceManager; import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4j.DiagnosticSeverity; @@ -734,4 +736,19 @@ public static boolean isValueLangLibFunction(FunctionSymbol functionSymbol) { ModuleID id = module.get().id(); return id.orgName().equals(BALLERINA_ORG_NAME) && id.packageName().equals(VALUE_LANG_LIB); } + + /** + * Load the project from the given file path. + * + * @param workspaceManager the workspace manager + * @param filePath the file path + * @return the loaded project + */ + public static Project loadProject(WorkspaceManager workspaceManager, Path filePath) { + try { + return workspaceManager.loadProject(filePath); + } catch (WorkspaceDocumentException | EventSyncException e) { + throw new RuntimeException("Error loading project: " + e.getMessage()); + } + } } diff --git a/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/utils/FlowNodeUtil.java b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/utils/FlowNodeUtil.java new file mode 100644 index 000000000..5fc281e7c --- /dev/null +++ b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/utils/FlowNodeUtil.java @@ -0,0 +1,41 @@ +/* + * 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.utils; + +import io.ballerina.flowmodelgenerator.core.model.FlowNode; +import io.ballerina.flowmodelgenerator.core.model.Property; + +/** + * Utility class for flow node and properties related operations. + * + * @since 2.0.0 + */ +public class FlowNodeUtil { + + /** + * Check whether the given flow node has the check key flag set. + * + * @param flowNode flow node to check + * @return true if the check key flag is set, false otherwise + */ + public static boolean hasCheckKeyFlagSet(FlowNode flowNode) { + return flowNode.properties().containsKey(Property.CHECK_ERROR_KEY) && + flowNode.properties().get(Property.CHECK_ERROR_KEY).value().equals(true); + } +} diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/node_template/config/function_call-user.json b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/node_template/config/function_call-user.json index 87a08f5cc..4c6261d53 100644 --- a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/node_template/config/function_call-user.json +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/node_template/config/function_call-user.json @@ -45,7 +45,7 @@ "value": "int", "placeholder": "var", "optional": false, - "editable": true, + "editable": false, "advanced": false }, "variable": { diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/node_template/config/method_call_user.json b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/node_template/config/method_call_user.json index 21c465f8d..dc9360892 100644 --- a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/node_template/config/method_call_user.json +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/node_template/config/method_call_user.json @@ -57,7 +57,7 @@ "value": "string", "placeholder": "var", "optional": false, - "editable": true, + "editable": false, "advanced": false }, "variable": {