From d56a57705d1075e9aa4acecb28e6d94e4d8f057f Mon Sep 17 00:00:00 2001 From: pasindufernando1 Date: Wed, 28 Jan 2026 16:56:19 +0530 Subject: [PATCH 1/5] Distinguish enums from unions --- .../models/connector/ReferenceType.java | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/misc/diagram-util/src/main/java/org/ballerinalang/diagramutil/connector/models/connector/ReferenceType.java b/misc/diagram-util/src/main/java/org/ballerinalang/diagramutil/connector/models/connector/ReferenceType.java index e96d465fbc..7094862621 100644 --- a/misc/diagram-util/src/main/java/org/ballerinalang/diagramutil/connector/models/connector/ReferenceType.java +++ b/misc/diagram-util/src/main/java/org/ballerinalang/diagramutil/connector/models/connector/ReferenceType.java @@ -225,6 +225,24 @@ public static RefType fromSemanticSymbol(TypeSymbol symbol, String name, ModuleI String soleTypeName = soleTypeSymbol.getName().orElse(soleTypeSymbol.signature()) + "?"; return fromSemanticSymbol(soleTypeSymbol, soleTypeName, soleModuleId, typeDefSymbols); } + + // Check if all members are singletons - if so, treat as enum + boolean allSingletons = !typeSymbols.isEmpty() && typeSymbols.stream() + .allMatch(member -> member.typeKind() == TypeDescKind.SINGLETON); + if (allSingletons) { + List enumMembers = new ArrayList<>(); + for (TypeSymbol memberTypeSymbol : typeSymbols) { + String memberTypeName = memberTypeSymbol.getName().orElse(""); + ModuleID memberModuleId = getModuleID(memberTypeSymbol, moduleID); + RefType memberType = fromSemanticSymbol(memberTypeSymbol, memberTypeName, + memberModuleId, typeDefSymbols); + enumMembers.add(memberType); + } + RefEnumType enumType = createEnumType(name, enumMembers, typeHash, typeKey, moduleID); + visitedTypeMap.put(typeKey, enumType); + return enumType; + } + RefUnionType unionType = new RefUnionType(name); unionType.hashCode = typeHash; unionType.key = typeKey; @@ -466,19 +484,24 @@ private static ModuleID getModuleID(TypeSymbol typeSymbol, ModuleID fallbackModu } private static RefType getEnumType(EnumSymbol enumSymbol, List typeDefSymbols) { - RefType type; - List fields = new ArrayList<>(); + List members = new ArrayList<>(); enumSymbol.members().forEach(member -> { String name = member.getName().orElse(""); ModuleID moduleId = getModuleID(member); RefType semanticSymbol = fromSemanticSymbol(member.typeDescriptor(), name, moduleId, typeDefSymbols); - fields.add(semanticSymbol); - + members.add(semanticSymbol); }); - type = new RefEnumType(enumSymbol.getName().orElse(""), fields); ModuleID moduleId = getModuleID(enumSymbol); - type.moduleInfo = moduleId != null ? createTypeInfo(moduleId) : null; - return type; + return createEnumType(enumSymbol.getName().orElse(""), members, null, null, moduleId); + } + + private static RefEnumType createEnumType(String name, List members, + String typeHash, String typeKey, ModuleID moduleID) { + RefEnumType enumType = new RefEnumType(name, members); + enumType.hashCode = typeHash; + enumType.key = typeKey; + enumType.moduleInfo = moduleID != null ? createTypeInfo(moduleID) : null; + return enumType; } private static void validateDependentTypes(RefType type, List typeDefSymbols) { From af009814397765f1f9637ef02c9bf0553536e3aa Mon Sep 17 00:00:00 2001 From: pasindufernando1 Date: Wed, 28 Jan 2026 16:56:48 +0530 Subject: [PATCH 2/5] Update RefType test cases --- .../config/enum_member.json | 70 ++++++++++++ .../source/proj4/Ballerina.toml | 6 + .../source/proj4/functions.bal | 0 .../source/proj4/main.bal | 14 +++ .../RefTypeTest/BalProject7/main.bal | 12 ++ .../RefTypeTest/TestData/enumSample1.json | 8 +- .../RefTypeTest/TestData/enumSample2.json | 106 ++++++++++++++++++ 7 files changed, 212 insertions(+), 4 deletions(-) create mode 100644 flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_custom_function/config/enum_member.json create mode 100644 flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_custom_function/source/proj4/Ballerina.toml create mode 100644 flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_custom_function/source/proj4/functions.bal create mode 100644 flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_custom_function/source/proj4/main.bal create mode 100644 misc/diagram-util/src/test/resources/RefTypeTest/TestData/enumSample2.json diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_custom_function/config/enum_member.json b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_custom_function/config/enum_member.json new file mode 100644 index 0000000000..98c906589c --- /dev/null +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_custom_function/config/enum_member.json @@ -0,0 +1,70 @@ +{ + "source": "proj4/main.bal", + "description": "Sample diagram node", + "codedata": { + "node": "VARIABLE", + "lineRange": { + "fileName": "proj4/main.bal", + "startLine": { + "line": 9, + "offset": 0 + }, + "endLine": { + "line": 12, + "offset": 2 + } + } + }, + "mapping": { + "output": "transformTest.gender", + "expression": "patient.gender" + }, + "functionMetadata": { + "returnType": { + "type": "unknown|male|female|other", + "kind": "union" + }, + "parameters": [ + { + "name": "gender", + "type": "string?", + "isOptional": true, + "isNullable": false, + "kind": "string" + } + ] + }, + "targetField": "transformTest", + "output": { + "proj4/main.bal": [ + { + "range": { + "start": { + "line": 11, + "character": 12 + }, + "end": { + "line": 11, + "character": 12 + } + }, + "newText": ", gender: mapStringToUnion1(patient.gender)" + } + ], + "proj4/functions.bal": [ + { + "range": { + "start": { + "line": 0, + "character": 0 + }, + "end": { + "line": 0, + "character": 0 + } + }, + "newText": "\nfunction mapStringToUnion1(string? gender) returns unknown|male|female|other {}" + } + ] + } +} diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_custom_function/source/proj4/Ballerina.toml b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_custom_function/source/proj4/Ballerina.toml new file mode 100644 index 0000000000..b8ae73d3ad --- /dev/null +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_custom_function/source/proj4/Ballerina.toml @@ -0,0 +1,6 @@ +[package] +org = "org" +name = "name" +version = "0.1.0" +distribution = "2201.9.2" + diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_custom_function/source/proj4/functions.bal b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_custom_function/source/proj4/functions.bal new file mode 100644 index 0000000000..e69de29bb2 diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_custom_function/source/proj4/main.bal b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_custom_function/source/proj4/main.bal new file mode 100644 index 0000000000..94841d8d06 --- /dev/null +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_custom_function/source/proj4/main.bal @@ -0,0 +1,14 @@ +import ballerinax/health.fhir.r4.uscore311; + +public type PatientDataOptionalized record {| + string id?; + string? name?; + string? gender?; + string? birthDate?; +|}; + +function transformTest(PatientDataOptionalized patient) returns uscore311:USCorePatientProfile => { + identifier: [], + name: [] +}; + diff --git a/misc/diagram-util/src/test/resources/RefTypeTest/BalProject7/main.bal b/misc/diagram-util/src/test/resources/RefTypeTest/BalProject7/main.bal index ba7c64e1ae..9e36eafb4e 100644 --- a/misc/diagram-util/src/test/resources/RefTypeTest/BalProject7/main.bal +++ b/misc/diagram-util/src/test/resources/RefTypeTest/BalProject7/main.bal @@ -11,3 +11,15 @@ public type RecordWithStream record {| string id; SimpleStream data; |}; + +enum Color { + RED, + GREEN, + BLUE +} + +public type Person2 record { + string name; + int age; + Color favoriteColor; +}; diff --git a/misc/diagram-util/src/test/resources/RefTypeTest/TestData/enumSample1.json b/misc/diagram-util/src/test/resources/RefTypeTest/TestData/enumSample1.json index f0c39a2974..984500f1de 100644 --- a/misc/diagram-util/src/test/resources/RefTypeTest/TestData/enumSample1.json +++ b/misc/diagram-util/src/test/resources/RefTypeTest/TestData/enumSample1.json @@ -17,7 +17,7 @@ { "fieldName": "code", "type": { - "memberTypes": [ + "members": [ { "dependentTypeKeys": [], "name": "FINANCE" @@ -35,7 +35,7 @@ "hashCode": "-959561237", "key": "-1253237511", "name": "DepartmentCode", - "typeName": "union", + "typeName": "enum", "moduleInfo": { "orgName": "ballerinax", "moduleName": "health.ccda.r1", @@ -57,7 +57,7 @@ "typeName": "record", "dependentTypes": { "-1253237511": { - "memberTypes": [ + "members": [ { "dependentTypeKeys": [], "name": "FINANCE" @@ -75,7 +75,7 @@ "hashCode": "-959561237", "key": "-1253237511", "name": "DepartmentCode", - "typeName": "union", + "typeName": "enum", "moduleInfo": { "orgName": "ballerinax", "moduleName": "health.ccda.r1", diff --git a/misc/diagram-util/src/test/resources/RefTypeTest/TestData/enumSample2.json b/misc/diagram-util/src/test/resources/RefTypeTest/TestData/enumSample2.json new file mode 100644 index 0000000000..5a0edfb3e1 --- /dev/null +++ b/misc/diagram-util/src/test/resources/RefTypeTest/TestData/enumSample2.json @@ -0,0 +1,106 @@ +{ + "description": "A simple example of a reference-based type", + "source": "RefTypeTest/BalProject7", + "typeSymbolName": "Person2", + "refType": { + "fields": [ + { + "fieldName": "name", + "type": { + "dependentTypeKeys": [], + "name": "string", + "typeName": "string" + }, + "optional": false, + "defaultValue": "" + }, + { + "fieldName": "age", + "type": { + "dependentTypeKeys": [], + "name": "int", + "typeName": "int" + }, + "optional": false, + "defaultValue": "" + }, + { + "fieldName": "favoriteColor", + "type": { + "members": [ + { + "dependentTypeKeys": [], + "name": "BLUE" + }, + { + "dependentTypeKeys": [], + "name": "GREEN" + }, + { + "dependentTypeKeys": [], + "name": "RED" + } + ], + "dependentTypeKeys": [], + "hashCode": "1321203991", + "key": "-955095486", + "name": "Color", + "typeName": "enum", + "moduleInfo": { + "orgName": "ballerinax", + "moduleName": "test.streams", + "packageName": "test.streams", + "version": "0.1.0", + "modulePrefix": "streams" + } + }, + "optional": false, + "defaultValue": "" + } + ], + "dependentTypeKeys": [ + "-955095486" + ], + "hashCode": "1975722613", + "key": "-351745380", + "name": "Person2", + "typeName": "record", + "dependentTypes": { + "-955095486": { + "members": [ + { + "dependentTypeKeys": [], + "name": "BLUE" + }, + { + "dependentTypeKeys": [], + "name": "GREEN" + }, + { + "dependentTypeKeys": [], + "name": "RED" + } + ], + "dependentTypeKeys": [], + "hashCode": "1321203991", + "key": "-955095486", + "name": "Color", + "typeName": "enum", + "moduleInfo": { + "orgName": "ballerinax", + "moduleName": "test.streams", + "packageName": "test.streams", + "version": "0.1.0", + "modulePrefix": "streams" + } + } + }, + "moduleInfo": { + "orgName": "ballerinax", + "moduleName": "test.streams", + "packageName": "test.streams", + "version": "0.1.0", + "modulePrefix": "streams" + } + } +} \ No newline at end of file From 48f0df8eb13ea8dd81f6c5bfcb7f1c77a0e62c90 Mon Sep 17 00:00:00 2001 From: pasindufernando1 Date: Wed, 28 Jan 2026 17:03:24 +0530 Subject: [PATCH 3/5] Update datamapping model tests --- .../data_mapper_model/config/enum.json | 18 +++++++++--------- .../data_mapper_model/config/enum2.json | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_model/config/enum.json b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_model/config/enum.json index 69ae922319..3594a3344d 100644 --- a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_model/config/enum.json +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_model/config/enum.json @@ -94,28 +94,28 @@ { "members": [ { - "name": "code", - "displayName": "code", + "name": "DepartmentCode.FINANCE", + "displayName": "FINANCE", "typeName": "FINANCE", "kind": "FINANCE" }, { - "name": "code", - "displayName": "code", + "name": "DepartmentCode.IT", + "displayName": "IT", "typeName": "IT", "kind": "IT" }, { - "name": "code", - "displayName": "code", + "name": "DepartmentCode.HR", + "displayName": "HR", "typeName": "HR", "kind": "HR" } ], "name": "code", - "displayName": "code", - "typeName": "FINANCE|IT|HR", - "kind": "union", + "displayName": "DepartmentCode", + "typeName": "DepartmentCode", + "kind": "enum", "optional": false, "ref": "-1735710389" } diff --git a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_model/config/enum2.json b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_model/config/enum2.json index 54ca0702fc..fad935c8fe 100644 --- a/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_model/config/enum2.json +++ b/flow-model-generator/modules/flow-model-generator-ls-extension/src/test/resources/data_mapper_model/config/enum2.json @@ -103,28 +103,28 @@ { "members": [ { - "name": "code", - "displayName": "code", + "name": "DepartmentCode.FINANCE", + "displayName": "FINANCE", "typeName": "FINANCE", "kind": "FINANCE" }, { - "name": "code", - "displayName": "code", + "name": "DepartmentCode.IT", + "displayName": "IT", "typeName": "IT", "kind": "IT" }, { - "name": "code", - "displayName": "code", + "name": "DepartmentCode.HR", + "displayName": "HR", "typeName": "HR", "kind": "HR" } ], "name": "code", - "displayName": "code", - "typeName": "FINANCE|IT|HR", - "kind": "union", + "displayName": "DepartmentCode", + "typeName": "DepartmentCode", + "kind": "enum", "optional": false, "ref": "-1735710389" } From be9376ec0634dad65453313664bd718c16fc8808 Mon Sep 17 00:00:00 2001 From: pasindufernando1 Date: Wed, 28 Jan 2026 17:11:21 +0530 Subject: [PATCH 4/5] Add newline at EOF --- .../src/test/resources/RefTypeTest/TestData/enumSample2.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/diagram-util/src/test/resources/RefTypeTest/TestData/enumSample2.json b/misc/diagram-util/src/test/resources/RefTypeTest/TestData/enumSample2.json index 5a0edfb3e1..dc50a430b0 100644 --- a/misc/diagram-util/src/test/resources/RefTypeTest/TestData/enumSample2.json +++ b/misc/diagram-util/src/test/resources/RefTypeTest/TestData/enumSample2.json @@ -103,4 +103,4 @@ "modulePrefix": "streams" } } -} \ No newline at end of file +} From 362c89cf37624d905a9ff06c51088c9c5178c35e Mon Sep 17 00:00:00 2001 From: pasindufernando1 Date: Fri, 30 Jan 2026 10:54:53 +0530 Subject: [PATCH 5/5] Address PR suggestions --- .../models/connector/ReferenceType.java | 16 ++++----- .../RefTypeTest/BalProject7/main.bal | 4 +++ .../TestData/singletonUnionSample1.json | 33 +++++++++++++++++++ 3 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 misc/diagram-util/src/test/resources/RefTypeTest/TestData/singletonUnionSample1.json diff --git a/misc/diagram-util/src/main/java/org/ballerinalang/diagramutil/connector/models/connector/ReferenceType.java b/misc/diagram-util/src/main/java/org/ballerinalang/diagramutil/connector/models/connector/ReferenceType.java index 7094862621..752dfc2915 100644 --- a/misc/diagram-util/src/main/java/org/ballerinalang/diagramutil/connector/models/connector/ReferenceType.java +++ b/misc/diagram-util/src/main/java/org/ballerinalang/diagramutil/connector/models/connector/ReferenceType.java @@ -52,6 +52,7 @@ import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; public class ReferenceType { private static final Map visitedTypeMap = new ConcurrentHashMap<>(); @@ -230,14 +231,13 @@ public static RefType fromSemanticSymbol(TypeSymbol symbol, String name, ModuleI boolean allSingletons = !typeSymbols.isEmpty() && typeSymbols.stream() .allMatch(member -> member.typeKind() == TypeDescKind.SINGLETON); if (allSingletons) { - List enumMembers = new ArrayList<>(); - for (TypeSymbol memberTypeSymbol : typeSymbols) { - String memberTypeName = memberTypeSymbol.getName().orElse(""); - ModuleID memberModuleId = getModuleID(memberTypeSymbol, moduleID); - RefType memberType = fromSemanticSymbol(memberTypeSymbol, memberTypeName, - memberModuleId, typeDefSymbols); - enumMembers.add(memberType); - } + List enumMembers = typeSymbols.stream() + .map(memberSymbol -> { + String memberTypeName = memberSymbol.getName().orElse(""); + ModuleID memberModuleId = getModuleID(memberSymbol, moduleID); + return fromSemanticSymbol(memberSymbol, memberTypeName, memberModuleId, typeDefSymbols); + }) + .collect(Collectors.toList()); RefEnumType enumType = createEnumType(name, enumMembers, typeHash, typeKey, moduleID); visitedTypeMap.put(typeKey, enumType); return enumType; diff --git a/misc/diagram-util/src/test/resources/RefTypeTest/BalProject7/main.bal b/misc/diagram-util/src/test/resources/RefTypeTest/BalProject7/main.bal index 9e36eafb4e..b2f7c82f90 100644 --- a/misc/diagram-util/src/test/resources/RefTypeTest/BalProject7/main.bal +++ b/misc/diagram-util/src/test/resources/RefTypeTest/BalProject7/main.bal @@ -23,3 +23,7 @@ public type Person2 record { int age; Color favoriteColor; }; + +// Union of singleton string values (not a named enum) +type Status "active"|"inactive"|"pending"; + diff --git a/misc/diagram-util/src/test/resources/RefTypeTest/TestData/singletonUnionSample1.json b/misc/diagram-util/src/test/resources/RefTypeTest/TestData/singletonUnionSample1.json new file mode 100644 index 0000000000..d835d34d79 --- /dev/null +++ b/misc/diagram-util/src/test/resources/RefTypeTest/TestData/singletonUnionSample1.json @@ -0,0 +1,33 @@ +{ + "description": "Union of singleton string values treated as enum", + "source": "RefTypeTest/BalProject7", + "typeSymbolName": "Status", + "refType": { + "members": [ + { + "dependentTypeKeys": [], + "name": "active" + }, + { + "dependentTypeKeys": [], + "name": "inactive" + }, + { + "dependentTypeKeys": [], + "name": "pending" + } + ], + "dependentTypeKeys": [], + "hashCode": "-732348210", + "key": "919172339", + "name": "Status", + "typeName": "enum", + "moduleInfo": { + "orgName": "ballerinax", + "moduleName": "test.streams", + "packageName": "test.streams", + "version": "0.1.0", + "modulePrefix": "streams" + } + } +} \ No newline at end of file