From edcdc35165f4d076cafb62d94ebb5bff30c8413c Mon Sep 17 00:00:00 2001 From: nipunayf Date: Fri, 24 Oct 2025 20:13:45 +0530 Subject: [PATCH 1/4] Update the source builder to consider local modules --- .../core/model/SourceBuilder.java | 56 ++++++++++++++++--- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/SourceBuilder.java b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/SourceBuilder.java index 3db5c59b92..e953621909 100644 --- a/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/SourceBuilder.java +++ b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/SourceBuilder.java @@ -20,6 +20,8 @@ import io.ballerina.compiler.api.SemanticModel; import io.ballerina.compiler.api.symbols.RecordTypeSymbol; +import io.ballerina.compiler.api.symbols.Symbol; +import io.ballerina.compiler.api.symbols.TypeDefinitionSymbol; import io.ballerina.compiler.api.symbols.TypeDescKind; import io.ballerina.compiler.api.symbols.TypeReferenceTypeSymbol; import io.ballerina.compiler.api.symbols.TypeSymbol; @@ -39,6 +41,8 @@ import io.ballerina.projects.Document; import io.ballerina.projects.Module; import io.ballerina.projects.ModuleDescriptor; +import io.ballerina.projects.ModuleId; +import io.ballerina.projects.Project; import io.ballerina.tools.text.LinePosition; import io.ballerina.tools.text.LineRange; import org.ballerinalang.formatter.core.FormattingTreeModifier; @@ -58,12 +62,14 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; public class SourceBuilder { @@ -274,26 +280,62 @@ public SourceBuilder acceptImport(String org, String module, boolean defaultName } public Optional getExpressionBodyText(String typeName, Map imports) { - PackageUtil.loadProject(workspaceManager, filePath); + Project project = PackageUtil.loadProject(workspaceManager, filePath); Document document = FileSystemUtils.getDocument(workspaceManager, filePath); + // Fetch the module ids of the project and create both list and mapping + List subModuleIds = new ArrayList<>(); + Map subModuleIdMap = new HashMap<>(); + project.currentPackage().moduleIds().forEach(moduleId -> { + String subModuleId = moduleId.moduleName(); + subModuleIds.add(subModuleId); + subModuleIdMap.put(subModuleId, moduleId); + }); + // Obtain the symbols of the imports Map packageMap = new HashMap<>(); if (imports != null) { imports.values().forEach(moduleId -> { ModuleInfo moduleInfo = ModuleInfo.from(moduleId); - PackageUtil.pullModuleAndNotify(lsClientLogger, moduleInfo).ifPresent(pkg -> - packageMap.put(CommonUtils.getDefaultModulePrefix(pkg.packageName().value()), - PackageUtil.getCompilation(pkg).defaultModuleBLangPackage()) - ); + if (!subModuleIds.contains(moduleInfo.packageName())) { + PackageUtil.pullModuleAndNotify(lsClientLogger, moduleInfo).ifPresent(pkg -> + packageMap.put(CommonUtils.getDefaultModulePrefix(pkg.packageName().value()), + PackageUtil.getCompilation(pkg).defaultModuleBLangPackage()) + ); + } }); } - SemanticModel semanticModel = FileSystemUtils.getSemanticModel(workspaceManager, filePath); Optional optionalType = BallerinaCompilerApi.getInstance().getType(semanticModel.types(), document, typeName, packageMap); if (optionalType.isEmpty()) { - return Optional.empty(); + // Failover mechanism: check if the type belongs to a local submodule + String[] typeNameParts = typeName.split(":"); + if (typeNameParts.length == 2) { + String packageName = project.currentPackage().packageName().value(); + String fullModuleName = packageName + "." + typeNameParts[0]; + if (subModuleIdMap.containsKey(fullModuleName)) { + ModuleId moduleId = subModuleIdMap.get(fullModuleName); + SemanticModel localModuleSemanticModel = + project.currentPackage().getCompilation().getSemanticModel(moduleId); + Optional moduleSymbol = localModuleSemanticModel.moduleSymbols() + .stream().filter(symbol -> symbol.nameEquals(typeNameParts[1])).findFirst(); + if (moduleSymbol.isEmpty()) { + return Optional.empty(); + } + if (moduleSymbol.get() instanceof TypeSymbol typeSymbol) { + optionalType = Optional.of(typeSymbol); + } else if (moduleSymbol.get() instanceof TypeDefinitionSymbol typeDefinitionSymbol) { + optionalType = Optional.of(typeDefinitionSymbol.typeDescriptor()); + } else { + return Optional.empty(); + } + } else { + return Optional.empty(); + } + } else { + return Optional.empty(); + } } TypeSymbol typeSymbol = optionalType.get(); From ca2e3370f720df4d7ed5d9511a729275e9e120dc Mon Sep 17 00:00:00 2001 From: nipunayf Date: Fri, 24 Oct 2025 20:47:38 +0530 Subject: [PATCH 2/4] Add test cases for the data mapper definition --- .../config/data_mapper_definition11.json | 243 ++++++++++++++++++ .../config/data_mapper_definition12.json | 170 ++++++++++++ .../config/data_mapper_definition13.json | 167 ++++++++++++ .../config/data_mapper_definition14.json | 190 ++++++++++++++ .../config/data_mapper_definition15.json | 231 +++++++++++++++++ .../to_source/source/nested/Ballerina.toml | 5 + .../to_source/source/nested/data_mappings.bal | 0 .../source/nested/modules/mod/types.bal | 24 ++ .../to_source/source/nested/types.bal | 5 + .../source/nested_editing/Ballerina.toml | 5 + .../source/nested_editing/data_mappings.bal | 7 + .../nested_editing/modules/mod/types.bal | 24 ++ .../to_source/source/nested_editing/types.bal | 5 + 13 files changed, 1076 insertions(+) create mode 100644 flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition11.json create mode 100644 flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition12.json create mode 100644 flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition13.json create mode 100644 flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition14.json create mode 100644 flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition15.json create mode 100644 flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested/Ballerina.toml create mode 100644 flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested/data_mappings.bal create mode 100644 flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested/modules/mod/types.bal create mode 100644 flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested/types.bal create mode 100644 flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested_editing/Ballerina.toml create mode 100644 flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested_editing/data_mappings.bal create mode 100644 flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested_editing/modules/mod/types.bal create mode 100644 flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested_editing/types.bal diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition11.json b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition11.json new file mode 100644 index 0000000000..c03fe7ed8c --- /dev/null +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition11.json @@ -0,0 +1,243 @@ +{ + "source": "nested/data_mappings.bal", + "description": "Test basic local module type usage - function returning local module type", + "diagram": { + "id": "99311", + "metadata": { + "label": "Data Mapper", + "description": "Define a data mapper with local module type" + }, + "codedata": { + "node": "DATA_MAPPER_DEFINITION", + "isNew": true + }, + "returning": false, + "properties": { + "functionName": { + "metadata": { + "label": "Name", + "description": "Name of the function" + }, + "valueType": "IDENTIFIER", + "valueTypeConstraint": "Global", + "value": "createPerson", + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + }, + "type": { + "metadata": { + "label": "Return Type", + "description": "Type of the return value" + }, + "valueType": "TYPE", + "valueTypeConstraint": "record", + "value": "mod:Person", + "imports": { + "mod": "wso2/nested.mod:0.1.0" + }, + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + }, + "parameters": { + "metadata": { + "label": "Inputs", + "description": "Input variables of the data mapper function" + }, + "valueType": "REPEATABLE_PROPERTY", + "valueTypeConstraint": { + "metadata": { + "label": "Parameter", + "description": "Function parameter" + }, + "valueType": "FIXED_PROPERTY", + "value": { + "type": { + "metadata": { + "label": "Type", + "description": "Type of the parameter" + }, + "valueType": "TYPE", + "valueTypeConstraint": "json", + "value": "", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + }, + "variable": { + "metadata": { + "label": "Name", + "description": "Name of the parameter" + }, + "valueType": "IDENTIFIER", + "value": "", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + } + }, + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + }, + "value": { + "name": { + "metadata": { + "label": "Parameter", + "description": "Function parameter" + }, + "valueType": "FIXED_PROPERTY", + "value": { + "type": { + "metadata": { + "label": "Type", + "description": "Type of the parameter" + }, + "valueType": "TYPE", + "valueTypeConstraint": "json", + "value": "string", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + }, + "variable": { + "metadata": { + "label": "Name", + "description": "Name of the parameter" + }, + "valueType": "IDENTIFIER", + "value": "name", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + } + }, + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + }, + "age": { + "metadata": { + "label": "Parameter", + "description": "Function parameter" + }, + "valueType": "FIXED_PROPERTY", + "value": { + "type": { + "metadata": { + "label": "Type", + "description": "Type of the parameter" + }, + "valueType": "TYPE", + "valueTypeConstraint": "json", + "value": "int", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + }, + "variable": { + "metadata": { + "label": "Name", + "description": "Name of the parameter" + }, + "valueType": "IDENTIFIER", + "value": "age", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + } + }, + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + }, + "email": { + "metadata": { + "label": "Parameter", + "description": "Function parameter" + }, + "valueType": "FIXED_PROPERTY", + "value": { + "type": { + "metadata": { + "label": "Type", + "description": "Type of the parameter" + }, + "valueType": "TYPE", + "valueTypeConstraint": "json", + "value": "string", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + }, + "variable": { + "metadata": { + "label": "Name", + "description": "Name of the parameter" + }, + "valueType": "IDENTIFIER", + "value": "email", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + } + }, + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + } + }, + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + } + }, + "flags": 0 + }, + "output": { + "nested/data_mappings.bal": [ + { + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import nested.mod;" + }, + { + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "function createPerson(string name, int age, string email) returns mod:Person => {\n name: \"\",\n age: 0,\n email: \"\"\n};" + } + ] + } +} diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition12.json b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition12.json new file mode 100644 index 0000000000..eb407ce032 --- /dev/null +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition12.json @@ -0,0 +1,170 @@ +{ + "source": "nested/data_mappings.bal", + "description": "Test local module parameter and return type - both param and return use local module types", + "diagram": { + "id": "99313", + "metadata": { + "label": "Data Mapper", + "description": "Define a data mapper with local module types in parameters and return" + }, + "codedata": { + "node": "DATA_MAPPER_DEFINITION", + "isNew": true + }, + "returning": false, + "properties": { + "functionName": { + "metadata": { + "label": "Name", + "description": "Name of the function" + }, + "valueType": "IDENTIFIER", + "valueTypeConstraint": "Global", + "value": "transformToEmployee", + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + }, + "type": { + "metadata": { + "label": "Return Type", + "description": "T ype of the return value" + }, + "valueType": "TYPE", + "valueTypeConstraint": "record", + "value": "mod:Employee", + "imports": { + "mod": "wso2/nested.mod:0.1.0" + }, + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + }, + "parameters": { + "metadata": { + "label": "Inputs", + "description": "Input variables of the data mapper function" + }, + "valueType": "REPEATABLE_PROPERTY", + "valueTypeConstraint": { + "metadata": { + "label": "Parameter", + "description": "Function parameter" + }, + "valueType": "FIXED_PROPERTY", + "value": { + "type": { + "metadata": { + "label": "Type", + "description": "Type of the parameter" + }, + "valueType": "TYPE", + "valueTypeConstraint": "json", + "value": "", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + }, + "variable": { + "metadata": { + "label": "Name", + "description": "Name of the parameter" + }, + "valueType": "IDENTIFIER", + "value": "", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + } + }, + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + }, + "value": { + "person": { + "metadata": { + "label": "Parameter", + "description": "Function parameter" + }, + "valueType": "FIXED_PROPERTY", + "value": { + "type": { + "metadata": { + "label": "Type", + "description": "Type of the parameter" + }, + "valueType": "TYPE", + "valueTypeConstraint": "record", + "value": "mod:Person", + "imports": { + "mod": "wso2/nested.mod:0.1.0" + }, + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + }, + "variable": { + "metadata": { + "label": "Name", + "description": "Name of the parameter" + }, + "valueType": "IDENTIFIER", + "value": "person", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + } + }, + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + } + }, + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + } + }, + "flags": 0 + }, + "output": { + "nested/data_mappings.bal": [ + { + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import nested.mod;" + }, + { + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "function transformToEmployee(mod:Person person) returns mod:Employee => {\n name: \"\",\n age: 0\n};" + } + ] + } +} diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition13.json b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition13.json new file mode 100644 index 0000000000..dd3c300e03 --- /dev/null +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition13.json @@ -0,0 +1,167 @@ +{ + "source": "nested/data_mappings.bal", + "description": "Test union type with local modules - return type is union of local module types", + "diagram": { + "id": "99314", + "metadata": { + "label": "Data Mapper", + "description": "Define a data mapper with union of local module types" + }, + "codedata": { + "node": "DATA_MAPPER_DEFINITION", + "isNew": true + }, + "returning": false, + "properties": { + "functionName": { + "metadata": { + "label": "Name", + "description": "Name of the function" + }, + "valueType": "IDENTIFIER", + "valueTypeConstraint": "Global", + "value": "getPersonOrEmployee", + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + }, + "type": { + "metadata": { + "label": "Return Type", + "description": "Type of the return value" + }, + "valueType": "TYPE", + "valueTypeConstraint": "json", + "value": "mod:Person|mod:Employee", + "imports": { + "mod": "wso2/nested.mod:0.1.0" + }, + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + }, + "parameters": { + "metadata": { + "label": "Inputs", + "description": "Input variables of the data mapper function" + }, + "valueType": "REPEATABLE_PROPERTY", + "valueTypeConstraint": { + "metadata": { + "label": "Parameter", + "description": "Function parameter" + }, + "valueType": "FIXED_PROPERTY", + "value": { + "type": { + "metadata": { + "label": "Type", + "description": "Type of the parameter" + }, + "valueType": "TYPE", + "valueTypeConstraint": "json", + "value": "", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + }, + "variable": { + "metadata": { + "label": "Name", + "description": "Name of the parameter" + }, + "valueType": "IDENTIFIER", + "value": "", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + } + }, + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + }, + "value": { + "isEmployee": { + "metadata": { + "label": "Parameter", + "description": "Function parameter" + }, + "valueType": "FIXED_PROPERTY", + "value": { + "type": { + "metadata": { + "label": "Type", + "description": "Type of the parameter" + }, + "valueType": "TYPE", + "valueTypeConstraint": "json", + "value": "boolean", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + }, + "variable": { + "metadata": { + "label": "Name", + "description": "Name of the parameter" + }, + "valueType": "IDENTIFIER", + "value": "isEmployee", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + } + }, + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + } + }, + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + } + }, + "flags": 0 + }, + "output": { + "nested/main.bal": [ + { + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "import nested.mod;\n" + }, + { + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "function getPersonOrEmployee(boolean isEmployee) returns mod:Person|mod:Employee => {\n name: \"\",\n age: 0\n};\n" + } + ] + } +} \ No newline at end of file diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition14.json b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition14.json new file mode 100644 index 0000000000..e4bd6b9a79 --- /dev/null +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition14.json @@ -0,0 +1,190 @@ +{ + "source": "nested_editing/data_mappings.bal", + "description": "Edit existing function with local module - change return type from mod:Person to mod:Employee", + "diagram": { + "id": "99315", + "metadata": { + "label": "Data Mapper", + "description": "Edit data mapper with local module return type" + }, + "codedata": { + "node": "DATA_MAPPER_DEFINITION", + "lineRange": { + "fileName": "data_mappings.bal", + "startLine": { + "line": 3, + "offset": 0 + }, + "endLine": { + "line": 7, + "offset": 2 + } + } + }, + "returning": false, + "properties": { + "functionName": { + "metadata": { + "label": "Name", + "description": "Name of the function" + }, + "valueType": "IDENTIFIER", + "valueTypeConstraint": "Global", + "value": "transform", + "optional": false, + "editable": false, + "advanced": false, + "hidden": false, + "codedata": { + "lineRange": { + "fileName": "data_mappings.bal", + "startLine": { + "line": 3, + "offset": 9 + }, + "endLine": { + "line": 3, + "offset": 18 + } + } + } + }, + "type": { + "metadata": { + "label": "Return Type", + "description": "Type of the return value" + }, + "valueType": "TYPE", + "valueTypeConstraint": "record", + "value": "mod:Employee", + "imports": { + "mod": "wso2/nested_editing.mod:0.1.0" + }, + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + }, + "parameters": { + "metadata": { + "label": "Inputs", + "description": "Input variables of the data mapper function" + }, + "valueType": "REPEATABLE_PROPERTY", + "valueTypeConstraint": { + "metadata": { + "label": "Parameter", + "description": "Function parameter" + }, + "valueType": "FIXED_PROPERTY", + "value": { + "type": { + "metadata": { + "label": "Type", + "description": "Type of the parameter" + }, + "valueType": "TYPE", + "valueTypeConstraint": "json", + "value": "", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + }, + "variable": { + "metadata": { + "label": "Name", + "description": "Name of the parameter" + }, + "valueType": "IDENTIFIER", + "value": "", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + } + }, + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + }, + "value": { + "username": { + "metadata": { + "label": "Parameter", + "description": "Function parameter" + }, + "valueType": "FIXED_PROPERTY", + "value": { + "type": { + "metadata": { + "label": "Type", + "description": "Type of the parameter" + }, + "valueType": "TYPE", + "valueTypeConstraint": "json", + "value": "string", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + }, + "variable": { + "metadata": { + "label": "Name", + "description": "Name of the parameter" + }, + "valueType": "IDENTIFIER", + "value": "username", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false, + "codedata": { + "lineRange": { + "fileName": "data_mappings.bal", + "startLine": { + "line": 3, + "offset": 26 + }, + "endLine": { + "line": 3, + "offset": 34 + } + } + } + } + }, + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + } + }, + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + } + }, + "flags": 0 + }, + "output": { + "nested_editing/data_mappings.bal": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 7, + "character": 2 + } + }, + "newText": "function transform( string username) returns mod:Employee" + } + ] + } +} diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition15.json b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition15.json new file mode 100644 index 0000000000..00322dc13d --- /dev/null +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition15.json @@ -0,0 +1,231 @@ +{ + "source": "nested_editing/data_mappings.bal", + "description": "Edit existing function with local module - add local module type parameter (mod:Address)", + "diagram": { + "id": "99316", + "metadata": { + "label": "Data Mapper", + "description": "Edit data mapper to add local module parameter" + }, + "codedata": { + "node": "DATA_MAPPER_DEFINITION", + "lineRange": { + "fileName": "data_mappings.bal", + "startLine": { + "line": 3, + "offset": 0 + }, + "endLine": { + "line": 7, + "offset": 2 + } + } + }, + "returning": false, + "properties": { + "functionName": { + "metadata": { + "label": "Name", + "description": "Name of the function" + }, + "valueType": "IDENTIFIER", + "valueTypeConstraint": "Global", + "value": "transform", + "optional": false, + "editable": false, + "advanced": false, + "hidden": false, + "codedata": { + "lineRange": { + "fileName": "data_mappings.bal", + "startLine": { + "line": 3, + "offset": 9 + }, + "endLine": { + "line": 3, + "offset": 18 + } + } + } + }, + "type": { + "metadata": { + "label": "Return Type", + "description": "Type of the return value" + }, + "valueType": "TYPE", + "valueTypeConstraint": "record", + "value": "mod:Person", + "imports": { + "mod": "wso2/nested_editing.mod:0.1.0" + }, + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + }, + "parameters": { + "metadata": { + "label": "Inputs", + "description": "Input variables of the data mapper function" + }, + "valueType": "REPEATABLE_PROPERTY", + "valueTypeConstraint": { + "metadata": { + "label": "Parameter", + "description": "Function parameter" + }, + "valueType": "FIXED_PROPERTY", + "value": { + "type": { + "metadata": { + "label": "Type", + "description": "Type of the parameter" + }, + "valueType": "TYPE", + "valueTypeConstraint": "json", + "value": "", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + }, + "variable": { + "metadata": { + "label": "Name", + "description": "Name of the parameter" + }, + "valueType": "IDENTIFIER", + "value": "", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + } + }, + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + }, + "value": { + "username": { + "metadata": { + "label": "Parameter", + "description": "Function parameter" + }, + "valueType": "FIXED_PROPERTY", + "value": { + "type": { + "metadata": { + "label": "Type", + "description": "Type of the parameter" + }, + "valueType": "TYPE", + "valueTypeConstraint": "json", + "value": "string", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + }, + "variable": { + "metadata": { + "label": "Name", + "description": "Name of the parameter" + }, + "valueType": "IDENTIFIER", + "value": "username", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false, + "codedata": { + "lineRange": { + "fileName": "data_mappings.bal", + "startLine": { + "line": 3, + "offset": 26 + }, + "endLine": { + "line": 3, + "offset": 34 + } + } + } + } + }, + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + }, + "address": { + "metadata": { + "label": "Parameter", + "description": "Function parameter" + }, + "valueType": "FIXED_PROPERTY", + "value": { + "type": { + "metadata": { + "label": "Type", + "description": "Type of the parameter" + }, + "valueType": "TYPE", + "valueTypeConstraint": "record", + "value": "mod:Address", + "imports": { + "mod": "wso2/nested_editing.mod:0.1.0" + }, + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + }, + "variable": { + "metadata": { + "label": "Name", + "description": "Name of the parameter" + }, + "valueType": "IDENTIFIER", + "value": "address", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + } + }, + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + } + }, + "optional": false, + "editable": false, + "advanced": false, + "hidden": false + } + }, + "flags": 0 + }, + "output": { + "nested_editing/data_mappings.bal": [ + { + "range": { + "start": { + "line": 3, + "character": 0 + }, + "end": { + "line": 7, + "character": 2 + } + }, + "newText": "function transform( string username, mod:Address address) returns mod:Person" + } + ] + } +} diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested/Ballerina.toml b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested/Ballerina.toml new file mode 100644 index 0000000000..1ebfccb85a --- /dev/null +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested/Ballerina.toml @@ -0,0 +1,5 @@ +[package] +org = "wso2" +name = "nested" +version = "0.1.0" +distribution = "2201.12.8" diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested/data_mappings.bal b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested/data_mappings.bal new file mode 100644 index 0000000000..e69de29bb2 diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested/modules/mod/types.bal b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested/modules/mod/types.bal new file mode 100644 index 0000000000..22224cd239 --- /dev/null +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested/modules/mod/types.bal @@ -0,0 +1,24 @@ +public type Person record { + string name; + int age; + string email; +}; + +public type Employee record { + string name; + int age; + string department?; + decimal salary?; +}; + +public type Address record { + string street; + string city; + string country; +}; + +public type Company record { + string name; + Address headquarters; + Employee[] employees; +}; diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested/types.bal b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested/types.bal new file mode 100644 index 0000000000..5b614cf87d --- /dev/null +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested/types.bal @@ -0,0 +1,5 @@ +public type Company record { + string name; + Address headquarters; + Employee[] employees; +}; diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested_editing/Ballerina.toml b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested_editing/Ballerina.toml new file mode 100644 index 0000000000..44e8da167f --- /dev/null +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested_editing/Ballerina.toml @@ -0,0 +1,5 @@ +[package] +org = "wso2" +name = "nested_editing" +version = "0.1.0" +distribution = "2201.12.8" diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested_editing/data_mappings.bal b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested_editing/data_mappings.bal new file mode 100644 index 0000000000..8a8e7435e9 --- /dev/null +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested_editing/data_mappings.bal @@ -0,0 +1,7 @@ +import nested_editing.mod; + +function transform(string username) returns mod:Person => { + name: "", + age: 0, + email: "" +}; diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested_editing/modules/mod/types.bal b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested_editing/modules/mod/types.bal new file mode 100644 index 0000000000..22224cd239 --- /dev/null +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested_editing/modules/mod/types.bal @@ -0,0 +1,24 @@ +public type Person record { + string name; + int age; + string email; +}; + +public type Employee record { + string name; + int age; + string department?; + decimal salary?; +}; + +public type Address record { + string street; + string city; + string country; +}; + +public type Company record { + string name; + Address headquarters; + Employee[] employees; +}; diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested_editing/types.bal b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested_editing/types.bal new file mode 100644 index 0000000000..5b614cf87d --- /dev/null +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/source/nested_editing/types.bal @@ -0,0 +1,5 @@ +public type Company record { + string name; + Address headquarters; + Employee[] employees; +}; From 4be7417b9dfb7daf767c88d42eed5af2dc175b09 Mon Sep 17 00:00:00 2001 From: nipunayf Date: Fri, 24 Oct 2025 20:47:53 +0530 Subject: [PATCH 3/4] Format the data mapper definition --- .../core/model/SourceBuilder.java | 66 +++++++++++-------- .../node/DataMapperDefinitionBuilder.java | 3 +- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/SourceBuilder.java b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/SourceBuilder.java index e953621909..f8f4df2701 100644 --- a/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/SourceBuilder.java +++ b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/SourceBuilder.java @@ -283,11 +283,15 @@ public Optional getExpressionBodyText(String typeName, Map subModuleIds = new ArrayList<>(); + // Fetch the module ids of the project + String packageName = project.currentPackage().packageName().value(); + Set subModuleIds = new HashSet<>(); Map subModuleIdMap = new HashMap<>(); project.currentPackage().moduleIds().forEach(moduleId -> { String subModuleId = moduleId.moduleName(); + if (subModuleId.equals(packageName)) { + return; + } subModuleIds.add(subModuleId); subModuleIdMap.put(subModuleId, moduleId); }); @@ -305,39 +309,49 @@ public Optional getExpressionBodyText(String typeName, Map optionalType = BallerinaCompilerApi.getInstance().getType(semanticModel.types(), document, typeName, packageMap); - if (optionalType.isEmpty()) { + TypeSymbol typeSymbol; + if (optionalType.isPresent()) { + typeSymbol = optionalType.get(); + } else { // Failover mechanism: check if the type belongs to a local submodule + // TODO: The following implementation is a temporary workaround. We need to explore ways to enhance the + // semantic APIs to properly account for submodules as well. String[] typeNameParts = typeName.split(":"); - if (typeNameParts.length == 2) { - String packageName = project.currentPackage().packageName().value(); - String fullModuleName = packageName + "." + typeNameParts[0]; - if (subModuleIdMap.containsKey(fullModuleName)) { - ModuleId moduleId = subModuleIdMap.get(fullModuleName); - SemanticModel localModuleSemanticModel = - project.currentPackage().getCompilation().getSemanticModel(moduleId); - Optional moduleSymbol = localModuleSemanticModel.moduleSymbols() - .stream().filter(symbol -> symbol.nameEquals(typeNameParts[1])).findFirst(); - if (moduleSymbol.isEmpty()) { - return Optional.empty(); - } - if (moduleSymbol.get() instanceof TypeSymbol typeSymbol) { - optionalType = Optional.of(typeSymbol); - } else if (moduleSymbol.get() instanceof TypeDefinitionSymbol typeDefinitionSymbol) { - optionalType = Optional.of(typeDefinitionSymbol.typeDescriptor()); - } else { - return Optional.empty(); - } - } else { - return Optional.empty(); - } + if (typeNameParts.length != 2) { + return Optional.empty(); + } + + String fullModuleName = packageName + "." + typeNameParts[0]; + ModuleId moduleId = subModuleIdMap.get(fullModuleName); + if (moduleId == null) { + return Optional.empty(); + } + + SemanticModel localModuleSemanticModel = + project.currentPackage().getCompilation().getSemanticModel(moduleId); + Optional moduleSymbol = localModuleSemanticModel.moduleSymbols() + .stream() + .filter(symbol -> symbol.nameEquals(typeNameParts[1])) + .findFirst(); + + if (moduleSymbol.isEmpty()) { + return Optional.empty(); + } + + Symbol symbol = moduleSymbol.get(); + if (symbol instanceof TypeSymbol tSymbol) { + typeSymbol = tSymbol; + } + else if (symbol instanceof TypeDefinitionSymbol typeDefinitionSymbol) { + typeSymbol = typeDefinitionSymbol.typeDescriptor(); } else { return Optional.empty(); } } - TypeSymbol typeSymbol = optionalType.get(); if (typeSymbol.typeKind() == TypeDescKind.TYPE_REFERENCE) { TypeReferenceTypeSymbol typeDefinitionSymbol = (TypeReferenceTypeSymbol) typeSymbol; diff --git a/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/DataMapperDefinitionBuilder.java b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/DataMapperDefinitionBuilder.java index 5794f34cdc..c96ae3ebd9 100644 --- a/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/DataMapperDefinitionBuilder.java +++ b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/node/DataMapperDefinitionBuilder.java @@ -168,8 +168,7 @@ public Map> toSource(SourceBuilder sourceBuilder) { .token().skipFormatting().stepOut() .textEdit(); } - return sourceBuilder - .build(); + return sourceBuilder.build(); } private static class ParameterSchemaHolder { From ab8f2f86a41d9d899968777eb33c2772f1bc6936 Mon Sep 17 00:00:00 2001 From: nipunayf Date: Sat, 25 Oct 2025 08:14:34 +0530 Subject: [PATCH 4/4] Fix checkstyle errors --- .../core/model/SourceBuilder.java | 5 +- .../config/data_mapper_definition13.json | 89 ++++--- .../config/data_mapper_definition14.json | 51 +++- .../config/data_mapper_definition15.json | 231 ------------------ 4 files changed, 103 insertions(+), 273 deletions(-) delete mode 100644 flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition15.json diff --git a/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/SourceBuilder.java b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/SourceBuilder.java index f8f4df2701..d8128e460a 100644 --- a/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/SourceBuilder.java +++ b/flow-model-generator/modules/flow-model-generator-core/src/main/java/io/ballerina/flowmodelgenerator/core/model/SourceBuilder.java @@ -62,14 +62,12 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; -import java.util.stream.Stream; public class SourceBuilder { @@ -345,8 +343,7 @@ public Optional getExpressionBodyText(String typeName, Map {\n name: \"\",\n age: 0\n};\n" + "newText": "function transform( string username) returns mod:Employee" } ] } -} \ No newline at end of file +} diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition14.json b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition14.json index e4bd6b9a79..00322dc13d 100644 --- a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition14.json +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition14.json @@ -1,11 +1,11 @@ { "source": "nested_editing/data_mappings.bal", - "description": "Edit existing function with local module - change return type from mod:Person to mod:Employee", + "description": "Edit existing function with local module - add local module type parameter (mod:Address)", "diagram": { - "id": "99315", + "id": "99316", "metadata": { "label": "Data Mapper", - "description": "Edit data mapper with local module return type" + "description": "Edit data mapper to add local module parameter" }, "codedata": { "node": "DATA_MAPPER_DEFINITION", @@ -56,7 +56,7 @@ }, "valueType": "TYPE", "valueTypeConstraint": "record", - "value": "mod:Employee", + "value": "mod:Person", "imports": { "mod": "wso2/nested_editing.mod:0.1.0" }, @@ -160,6 +160,47 @@ "editable": false, "advanced": false, "hidden": false + }, + "address": { + "metadata": { + "label": "Parameter", + "description": "Function parameter" + }, + "valueType": "FIXED_PROPERTY", + "value": { + "type": { + "metadata": { + "label": "Type", + "description": "Type of the parameter" + }, + "valueType": "TYPE", + "valueTypeConstraint": "record", + "value": "mod:Address", + "imports": { + "mod": "wso2/nested_editing.mod:0.1.0" + }, + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + }, + "variable": { + "metadata": { + "label": "Name", + "description": "Name of the parameter" + }, + "valueType": "IDENTIFIER", + "value": "address", + "optional": false, + "editable": true, + "advanced": false, + "hidden": false + } + }, + "optional": false, + "editable": false, + "advanced": false, + "hidden": false } }, "optional": false, @@ -183,7 +224,7 @@ "character": 2 } }, - "newText": "function transform( string username) returns mod:Employee" + "newText": "function transform( string username, mod:Address address) returns mod:Person" } ] } diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition15.json b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition15.json deleted file mode 100644 index 00322dc13d..0000000000 --- a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/to_source/config/data_mapper_definition15.json +++ /dev/null @@ -1,231 +0,0 @@ -{ - "source": "nested_editing/data_mappings.bal", - "description": "Edit existing function with local module - add local module type parameter (mod:Address)", - "diagram": { - "id": "99316", - "metadata": { - "label": "Data Mapper", - "description": "Edit data mapper to add local module parameter" - }, - "codedata": { - "node": "DATA_MAPPER_DEFINITION", - "lineRange": { - "fileName": "data_mappings.bal", - "startLine": { - "line": 3, - "offset": 0 - }, - "endLine": { - "line": 7, - "offset": 2 - } - } - }, - "returning": false, - "properties": { - "functionName": { - "metadata": { - "label": "Name", - "description": "Name of the function" - }, - "valueType": "IDENTIFIER", - "valueTypeConstraint": "Global", - "value": "transform", - "optional": false, - "editable": false, - "advanced": false, - "hidden": false, - "codedata": { - "lineRange": { - "fileName": "data_mappings.bal", - "startLine": { - "line": 3, - "offset": 9 - }, - "endLine": { - "line": 3, - "offset": 18 - } - } - } - }, - "type": { - "metadata": { - "label": "Return Type", - "description": "Type of the return value" - }, - "valueType": "TYPE", - "valueTypeConstraint": "record", - "value": "mod:Person", - "imports": { - "mod": "wso2/nested_editing.mod:0.1.0" - }, - "optional": false, - "editable": true, - "advanced": false, - "hidden": false - }, - "parameters": { - "metadata": { - "label": "Inputs", - "description": "Input variables of the data mapper function" - }, - "valueType": "REPEATABLE_PROPERTY", - "valueTypeConstraint": { - "metadata": { - "label": "Parameter", - "description": "Function parameter" - }, - "valueType": "FIXED_PROPERTY", - "value": { - "type": { - "metadata": { - "label": "Type", - "description": "Type of the parameter" - }, - "valueType": "TYPE", - "valueTypeConstraint": "json", - "value": "", - "optional": false, - "editable": true, - "advanced": false, - "hidden": false - }, - "variable": { - "metadata": { - "label": "Name", - "description": "Name of the parameter" - }, - "valueType": "IDENTIFIER", - "value": "", - "optional": false, - "editable": true, - "advanced": false, - "hidden": false - } - }, - "optional": false, - "editable": false, - "advanced": false, - "hidden": false - }, - "value": { - "username": { - "metadata": { - "label": "Parameter", - "description": "Function parameter" - }, - "valueType": "FIXED_PROPERTY", - "value": { - "type": { - "metadata": { - "label": "Type", - "description": "Type of the parameter" - }, - "valueType": "TYPE", - "valueTypeConstraint": "json", - "value": "string", - "optional": false, - "editable": true, - "advanced": false, - "hidden": false - }, - "variable": { - "metadata": { - "label": "Name", - "description": "Name of the parameter" - }, - "valueType": "IDENTIFIER", - "value": "username", - "optional": false, - "editable": true, - "advanced": false, - "hidden": false, - "codedata": { - "lineRange": { - "fileName": "data_mappings.bal", - "startLine": { - "line": 3, - "offset": 26 - }, - "endLine": { - "line": 3, - "offset": 34 - } - } - } - } - }, - "optional": false, - "editable": false, - "advanced": false, - "hidden": false - }, - "address": { - "metadata": { - "label": "Parameter", - "description": "Function parameter" - }, - "valueType": "FIXED_PROPERTY", - "value": { - "type": { - "metadata": { - "label": "Type", - "description": "Type of the parameter" - }, - "valueType": "TYPE", - "valueTypeConstraint": "record", - "value": "mod:Address", - "imports": { - "mod": "wso2/nested_editing.mod:0.1.0" - }, - "optional": false, - "editable": true, - "advanced": false, - "hidden": false - }, - "variable": { - "metadata": { - "label": "Name", - "description": "Name of the parameter" - }, - "valueType": "IDENTIFIER", - "value": "address", - "optional": false, - "editable": true, - "advanced": false, - "hidden": false - } - }, - "optional": false, - "editable": false, - "advanced": false, - "hidden": false - } - }, - "optional": false, - "editable": false, - "advanced": false, - "hidden": false - } - }, - "flags": 0 - }, - "output": { - "nested_editing/data_mappings.bal": [ - { - "range": { - "start": { - "line": 3, - "character": 0 - }, - "end": { - "line": 7, - "character": 2 - } - }, - "newText": "function transform( string username, mod:Address address) returns mod:Person" - } - ] - } -}