Skip to content

Commit df46593

Browse files
authored
Merge branch 'main' into mi
2 parents 30ecf65 + 9131ef2 commit df46593

File tree

36 files changed

+532
-403
lines changed

36 files changed

+532
-403
lines changed

workspaces/ballerina/ballerina-core/src/rpc-types/ai-panel/interfaces.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ export interface DataMappingRecord {
168168
}
169169

170170
export interface GenerateTypesFromRecordRequest {
171-
attachment?: Attachment[]
171+
attachment: Attachment[]
172172
}
173173

174174
export interface GenerateTypesFromRecordResponse {

workspaces/ballerina/ballerina-core/src/rpc-types/lang-client/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@
1717
*/
1818

1919
import { BallerinaPackagesParams, BallerinaProjectComponents, BallerinaSTParams, ComponentModels, ComponentModelsParams, ExecutorPositions, PartialST, PartialSTParams, ProjectDiagnosticsRequest, ProjectDiagnosticsResponse, STModifyParams, SymbolInfo, SymbolInfoParams, SyntaxTree, SyntaxTreeParams, TypeFromExpressionParams, TypeFromSymbolParams, TypesFromFnDefinitionParams } from "../../interfaces/extended-lang-client";
20-
import { BallerinaVersionResponse, CompletionRequest, CompletionResponse, DiagnosticsResponse, CodeActionRequest, CodeActionResponse, RenameRequest, RenameResponse, DefinitionPositionRequest, UpdateFileContentRequest, UpdateFileContentResponse, DefinitionResponse, ExecutorPositionsRequest, DidCloseRequest, TypesFromExpressionResponse, TypesFromSymbolResponse, DidOpenRequest, DidChangeRequest } from "./interfaces";
20+
import { BallerinaVersionResponse, CompletionRequest, CompletionResponse, DiagnosticsResponse, CodeActionRequest, CodeActionResponse, RenameRequest, RenameResponse, DefinitionPositionRequest, UpdateFileContentRequest, UpdateFileContentResponse, DefinitionResponse, ExecutorPositionsRequest, DidCloseRequest, TypesFromExpressionResponse, TypesFromSymbolResponse, DidOpenRequest, DidChangeRequest, SemanticVersion } from "./interfaces";
2121

2222
export interface LangClientAPI {
2323
getSyntaxTree: () => Promise<SyntaxTree>;
2424
getST: (params: SyntaxTreeParams) => Promise<SyntaxTree>;
2525
getSTByRange: (params: BallerinaSTParams) => Promise<SyntaxTree>;
2626
getBallerinaProjectComponents: (params: BallerinaPackagesParams) => Promise<BallerinaProjectComponents>;
2727
getBallerinaVersion: () => Promise<BallerinaVersionResponse>;
28+
isSupportedSLVersion: (params: SemanticVersion) => Promise<boolean>;
2829
getCompletion: (params: CompletionRequest) => Promise<CompletionResponse>;
2930
getDiagnostics: (params: SyntaxTreeParams) => Promise<DiagnosticsResponse>;
3031
getProjectDiagnostics: (params: ProjectDiagnosticsRequest) => Promise<ProjectDiagnosticsResponse>;

workspaces/ballerina/ballerina-core/src/rpc-types/lang-client/interfaces.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,10 @@ export interface TypesFromSymbolResponse {
163163

164164
export interface ExecutorPositionsResponse {
165165
executorPositions?: ExecutorPosition[];
166-
}
166+
}
167+
168+
export interface SemanticVersion {
169+
major: number;
170+
minor: number;
171+
patch: number;
172+
}

workspaces/ballerina/ballerina-core/src/rpc-types/lang-client/rpc-type.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
* THIS FILE INCLUDES AUTO GENERATED CODE
1919
*/
2020
import { BallerinaPackagesParams, BallerinaProjectComponents, BallerinaSTParams, ComponentModels, ComponentModelsParams, ExecutorPositions, PartialST, PartialSTParams, ProjectDiagnosticsRequest, ProjectDiagnosticsResponse, STModifyParams, SymbolInfo, SymbolInfoParams, SyntaxTree, SyntaxTreeParams, TypeFromExpressionParams, TypeFromSymbolParams, TypesFromFnDefinitionParams } from "../../interfaces/extended-lang-client";
21-
import { BallerinaVersionResponse, CompletionRequest, CompletionResponse, DiagnosticsResponse, CodeActionRequest, CodeActionResponse, RenameRequest, RenameResponse, DefinitionPositionRequest, UpdateFileContentRequest, UpdateFileContentResponse, DefinitionResponse, ExecutorPositionsRequest, DidCloseRequest, TypesFromExpressionResponse, TypesFromSymbolResponse, DidOpenRequest, DidChangeRequest } from "./interfaces";
21+
import { BallerinaVersionResponse, CompletionRequest, CompletionResponse, DiagnosticsResponse, CodeActionRequest, CodeActionResponse, RenameRequest, RenameResponse, DefinitionPositionRequest, UpdateFileContentRequest, UpdateFileContentResponse, DefinitionResponse, ExecutorPositionsRequest, DidCloseRequest, TypesFromExpressionResponse, TypesFromSymbolResponse, DidOpenRequest, DidChangeRequest, SemanticVersion } from "./interfaces";
2222
import { RequestType, NotificationType } from "vscode-messenger-common";
2323

2424
const _preFix = "lang-client";
@@ -27,6 +27,7 @@ export const getST: RequestType<SyntaxTreeParams, SyntaxTree> = { method: `${_pr
2727
export const getSTByRange: RequestType<BallerinaSTParams, SyntaxTree> = { method: `${_preFix}/getSTByRange` };
2828
export const getBallerinaProjectComponents: RequestType<BallerinaPackagesParams, BallerinaProjectComponents> = { method: `${_preFix}/getBallerinaProjectComponents` };
2929
export const getBallerinaVersion: RequestType<void, BallerinaVersionResponse> = { method: `${_preFix}/getBallerinaVersion` };
30+
export const isSupportedSLVersion: RequestType<SemanticVersion, boolean> = { method: `${_preFix}/isSupportedSLVersion` };
3031
export const getCompletion: RequestType<CompletionRequest, CompletionResponse> = { method: `${_preFix}/getCompletion` };
3132
export const getDiagnostics: RequestType<SyntaxTreeParams, DiagnosticsResponse> = { method: `${_preFix}/getDiagnostics` };
3233
export const getProjectDiagnostics: RequestType<ProjectDiagnosticsRequest, ProjectDiagnosticsResponse> = { method: `${_preFix}/getProjectDiagnostics` };

workspaces/ballerina/ballerina-extension/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "ballerina",
33
"displayName": "Ballerina",
44
"description": "Ballerina Language support, debugging, graphical visualization, AI-based data-mapping and many more.",
5-
"version": "5.5.0",
5+
"version": "5.6.0",
66
"publisher": "wso2",
77
"icon": "resources/images/ballerina.png",
88
"homepage": "https://wso2.com/ballerina/vscode/docs",

workspaces/ballerina/ballerina-extension/src/core/extension.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,18 @@ import { exec, spawnSync, execSync } from 'child_process';
3333
import { LanguageClientOptions, State as LS_STATE, RevealOutputChannelOn, ServerOptions } from "vscode-languageclient/node";
3434
import { getServerOptions } from '../utils/server/server';
3535
import { ExtendedLangClient } from './extended-language-client';
36-
import { debug, log, getOutputChannel, outputChannel, isWindows, isWSL, isSupportedVersion, VERSION, isSupportedSLVersion } from '../utils';
36+
import {
37+
debug,
38+
log,
39+
getOutputChannel,
40+
outputChannel,
41+
isWindows,
42+
isWSL,
43+
isSupportedVersion,
44+
VERSION,
45+
isSupportedSLVersion,
46+
createVersionNumber
47+
} from '../utils';
3748
import { AssertionError } from "assert";
3849
import {
3950
BALLERINA_HOME, ENABLE_ALL_CODELENS, ENABLE_TELEMETRY, ENABLE_SEMANTIC_HIGHLIGHTING, OVERRIDE_BALLERINA_HOME,
@@ -142,6 +153,7 @@ export class BallerinaExtension {
142153
public ballerinaVersion: string;
143154
public biSupported: boolean;
144155
public isNPSupported: boolean;
156+
public isWorkspaceSupported: boolean;
145157
public extension: Extension<any>;
146158
private clientOptions: LanguageClientOptions;
147159
public langClient?: ExtendedLangClient;
@@ -172,6 +184,7 @@ export class BallerinaExtension {
172184
this.ballerinaVersion = '';
173185
this.biSupported = false;
174186
this.isNPSupported = false;
187+
this.isWorkspaceSupported = false;
175188
this.isPersist = false;
176189
this.ballerinaUserHomeName = '.ballerina';
177190

@@ -442,9 +455,10 @@ export class BallerinaExtension {
442455
}
443456

444457
try {
445-
this.biSupported = isSupportedSLVersion(this, 2201123); // Minimum supported version for BI
446-
this.isNPSupported = isSupportedSLVersion(this, 2201130) && this.enabledExperimentalFeatures(); // Minimum supported requirements for NP
447-
debug(`[INIT] Feature support calculated - BI: ${this.biSupported}, NP: ${this.isNPSupported}`);
458+
this.biSupported = isSupportedSLVersion(this, createVersionNumber(2201, 12, 3)); // Minimum supported version for BI: 2201.12.3
459+
this.isNPSupported = isSupportedSLVersion(this, createVersionNumber(2201, 13, 0)) && this.enabledExperimentalFeatures(); // Minimum supported requirements for NP: 2201.13.0
460+
this.isWorkspaceSupported = isSupportedSLVersion(this, createVersionNumber(2201, 13, 0)); // Minimum supported requirements for Workspace: 2201.13.0
461+
debug(`[INIT] Feature support calculated - BI: ${this.biSupported}, NP: ${this.isNPSupported}, Workspace: ${this.isWorkspaceSupported}`);
448462
} catch (error) {
449463
debug(`[INIT] Error calculating feature support: ${error}`);
450464
// Don't throw here, we can continue without these features
@@ -464,7 +478,7 @@ export class BallerinaExtension {
464478
debug(`[INIT] Final Ballerina Home: ${this.ballerinaHome}`);
465479
debug(`[INIT] Plugin Dev Mode: ${this.overrideBallerinaHome()}`);
466480
debug(`[INIT] Debug Mode: ${this.enableLSDebug()}`);
467-
debug(`[INIT] Feature flags - Experimental: ${this.enabledExperimentalFeatures()}, BI: ${this.biSupported}, NP: ${this.isNPSupported}`);
481+
debug(`[INIT] Feature flags - Experimental: ${this.enabledExperimentalFeatures()}, BI: ${this.biSupported}, NP: ${this.isNPSupported}, Workspace: ${this.isWorkspaceSupported}`);
468482

469483
// Check version compatibility
470484
try {
@@ -2283,7 +2297,7 @@ export class BallerinaExtension {
22832297
}
22842298

22852299
public enabledLiveReload(): boolean {
2286-
return isSupportedSLVersion(this, 2201100) && workspace.getConfiguration().get(ENABLE_LIVE_RELOAD);
2300+
return isSupportedSLVersion(this, createVersionNumber(2201, 10, 0)) && workspace.getConfiguration().get(ENABLE_LIVE_RELOAD);
22872301
}
22882302

22892303
public enabledPerformanceForecasting(): boolean {

workspaces/ballerina/ballerina-extension/src/features/ai/dataMapping.ts

Lines changed: 74 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -477,11 +477,10 @@ export async function generateMappings(
477477
): Promise<AllDataMapperSourceRequest> {
478478
const targetFilePath = metadataWithAttachments.metadata.codeData.lineRange.fileName || context.documentUri;
479479

480-
const optionalMappingInstructionFile = metadataWithAttachments.attachments && metadataWithAttachments.attachments.length > 0
481-
? metadataWithAttachments.attachments[0]
482-
: undefined;
483-
484-
const generatedMappings = await generateMappingExpressionsFromModel(metadataWithAttachments.metadata.mappingsModel as DMModel, optionalMappingInstructionFile);
480+
const generatedMappings = await generateMappingExpressionsFromModel(
481+
metadataWithAttachments.metadata.mappingsModel as DMModel,
482+
metadataWithAttachments.attachments || []
483+
);
485484

486485
const customFunctionMappings = generatedMappings.filter(mapping => mapping.isFunctionCall);
487486
let customFunctionsFilePath: string | undefined;
@@ -1123,20 +1122,47 @@ export async function generateInlineMappingsSource(
11231122
// processContextTypeCreation - Functions for processing context type creation
11241123
// ================================================================================================
11251124

1126-
// Extract record types from Ballerina code
1127-
export function extractRecordTypes(typesCode: string): { name: string; code: string }[] {
1128-
const recordPattern = /\b(?:public|private)?\s*type\s+(\w+)\s+record\s+(?:{[|]?|[|]?{)[\s\S]*?;?\s*[}|]?;/g;
1129-
const matches = [...typesCode.matchAll(recordPattern)];
1130-
return matches.map((match) => ({
1131-
name: match[1],
1132-
code: match[0].trim(),
1133-
}));
1125+
// Extract record and enum types from syntax tree
1126+
export async function extractRecordTypesFromSyntaxTree(
1127+
langClient: ExtendedLangClient,
1128+
filePath: string
1129+
): Promise<{ records: string[]; enums: string[] }> {
1130+
const st = (await langClient.getSyntaxTree({
1131+
documentIdentifier: {
1132+
uri: Uri.file(filePath).toString(),
1133+
},
1134+
})) as SyntaxTree;
1135+
1136+
if (!st.syntaxTree) {
1137+
throw new Error("Failed to retrieve syntax tree for file: " + filePath);
1138+
}
1139+
1140+
const modulePart = st.syntaxTree as ModulePart;
1141+
const records: string[] = [];
1142+
const enums: string[] = [];
1143+
1144+
for (const member of modulePart.members) {
1145+
if (STKindChecker.isTypeDefinition(member)) {
1146+
const typeName = member.typeName?.value;
1147+
if (typeName) {
1148+
records.push(typeName);
1149+
}
1150+
} else if (STKindChecker.isEnumDeclaration(member)) {
1151+
const enumName = member.identifier?.value;
1152+
if (enumName) {
1153+
enums.push(enumName);
1154+
}
1155+
}
1156+
}
1157+
1158+
return { records, enums };
11341159
}
11351160

11361161
// Generate Ballerina record types from context attachments and validate against existing records
11371162
export async function generateTypesFromContext(
11381163
sourceAttachments: Attachment[],
1139-
projectComponents: ProjectComponentsResponse
1164+
projectComponents: ProjectComponentsResponse,
1165+
langClient: ExtendedLangClient
11401166
): Promise<TypesGenerationResult> {
11411167
if (!sourceAttachments || sourceAttachments.length === 0) {
11421168
throw new Error("Source attachments are required for type generation");
@@ -1163,31 +1189,61 @@ export async function generateTypesFromContext(
11631189
const typeFilePath = baseFilePath + typeComponent.filePath;
11641190
existingRecordTypesMap.set(typeComponent.name, { type: typeComponent.name, isArray: false, filePath: typeFilePath });
11651191
});
1192+
moduleSummary.enums.forEach((enumComponent: ComponentInfo) => {
1193+
const enumFilePath = baseFilePath + enumComponent.filePath;
1194+
existingRecordTypesMap.set(enumComponent.name, { type: enumComponent.name, isArray: false, filePath: enumFilePath });
1195+
});
11661196
});
11671197
});
11681198

1169-
// Generate type definitions from attachments
1199+
// Generate type definitions from all attachments together
11701200
const typeGenerationRequest: GenerateTypesFromRecordRequest = {
11711201
attachment: sourceAttachments
11721202
};
11731203

11741204
const typeGenerationResponse = await generateTypeCreation(typeGenerationRequest);
11751205
const generatedTypesCode = typeGenerationResponse.typesCode;
11761206

1207+
// Create temp directory and file to validate generated types
1208+
const tempDirectory = await createTempBallerinaDir();
1209+
const tempTypesFilePath = path.join(tempDirectory, outputFileName);
1210+
1211+
writeBallerinaFileDidOpenTemp(tempTypesFilePath, generatedTypesCode);
1212+
1213+
// Extract record and enum names from syntax tree
1214+
const { records: generatedRecords, enums: generatedEnums } = await extractRecordTypesFromSyntaxTree(langClient, tempTypesFilePath);
1215+
1216+
// Check for duplicate record names
1217+
for (const recordName of generatedRecords) {
1218+
if (existingRecordTypesMap.has(recordName)) {
1219+
throw new Error(`Record "${recordName}" already exists in the workspace`);
1220+
}
1221+
}
1222+
1223+
// Check for duplicate enum names
1224+
for (const enumName of generatedEnums) {
1225+
if (existingRecordTypesMap.has(enumName)) {
1226+
throw new Error(`Enum "${enumName}" already exists in the workspace`);
1227+
}
1228+
}
1229+
11771230
return {
11781231
typesCode: generatedTypesCode,
11791232
filePath: outputFileName,
11801233
recordMap: existingRecordTypesMap
11811234
};
11821235
}
11831236

1184-
// Generate Ballerina record type definitions from an attachment file
1237+
// Generate Ballerina record type definitions from attachment files
11851238
export async function generateTypeCreation(
11861239
typeGenerationRequest: GenerateTypesFromRecordRequest
11871240
): Promise<GenerateTypesFromRecordResponse> {
1188-
const sourceFile = typeGenerationRequest.attachment?.[0];
1241+
if (typeGenerationRequest.attachment.length === 0) {
1242+
throw new Error('No attachments provided for type generation');
1243+
}
11891244

1190-
const generatedTypeDefinitions = await extractRecordTypeDefinitionsFromFile(sourceFile);
1245+
// Process all attachments together to understand correlations
1246+
const generatedTypeDefinitions = await extractRecordTypeDefinitionsFromFile(typeGenerationRequest.attachment);
11911247
if (typeof generatedTypeDefinitions !== 'string') {
11921248
throw new Error(`Failed to generate types: ${JSON.stringify(generatedTypeDefinitions)}`);
11931249
}

0 commit comments

Comments
 (0)