Skip to content

Commit 65511b3

Browse files
Fix check error handling and output formatting
1 parent 585575d commit 65511b3

File tree

7 files changed

+264
-47
lines changed

7 files changed

+264
-47
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
@@ -121,7 +121,7 @@ export interface ProjectImports {
121121
// Data-mapper related interfaces
122122
export interface MetadataWithAttachments {
123123
metadata: ExtendedDataMapperMetadata;
124-
attachments?: Attachment[];
124+
attachments: Attachment[];
125125
}
126126

127127
export interface InlineMappingsSourceResult {

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import { PackageInfo, TypesGenerationResult } from "./service/datamapper/types";
3333
import { URI } from "vscode-uri";
3434
import { getAllDataMapperSource } from "./service/datamapper/datamapper";
3535
import { StateMachine } from "../../stateMachine";
36+
import { CopilotEventHandler } from "./service/event";
3637

3738
// Set to false to include mappings with default values
3839
const OMIT_DEFAULT_MAPPINGS_ENABLED = true;
@@ -473,13 +474,15 @@ export async function createTempFileAndGenerateMetadata(params: CreateTempFileRe
473474

474475
export async function generateMappings(
475476
metadataWithAttachments: MetadataWithAttachments,
476-
context: any
477+
context: any,
478+
eventHandler: CopilotEventHandler
477479
): Promise<AllDataMapperSourceRequest> {
478480
const targetFilePath = metadataWithAttachments.metadata.codeData.lineRange.fileName || context.documentUri;
479481

480482
const generatedMappings = await generateMappingExpressionsFromModel(
481483
metadataWithAttachments.metadata.mappingsModel as DMModel,
482-
metadataWithAttachments.attachments || []
484+
metadataWithAttachments.attachments || [],
485+
eventHandler
483486
);
484487

485488
const customFunctionMappings = generatedMappings.filter(mapping => mapping.isFunctionCall);
@@ -1060,6 +1063,7 @@ export async function generateInlineMappingsSource(
10601063
inlineMappingRequest: MetadataWithAttachments,
10611064
langClient: ExtendedLangClient,
10621065
context: any,
1066+
eventHandler: CopilotEventHandler
10631067
): Promise<InlineMappingsSourceResult> {
10641068
if (!inlineMappingRequest) {
10651069
throw new Error("Inline mapping request is required");
@@ -1096,16 +1100,18 @@ export async function generateInlineMappingsSource(
10961100

10971101
// Prepare mapping request payload
10981102
const mappingRequestPayload: MetadataWithAttachments = {
1099-
metadata: tempFileMetadata
1103+
metadata: tempFileMetadata,
1104+
attachments: []
11001105
};
1101-
if (inlineMappingRequest.attachments && inlineMappingRequest.attachments.length > 0) {
1106+
if (inlineMappingRequest.attachments.length > 0) {
11021107
mappingRequestPayload.attachments = inlineMappingRequest.attachments;
11031108
}
11041109

11051110
// Generate mappings and source code
11061111
const allMappingsRequest = await generateMappings(
11071112
mappingRequestPayload,
1108-
context
1113+
context,
1114+
eventHandler
11091115
);
11101116

11111117
const generatedSourceResponse = await getAllDataMapperSource(allMappingsRequest);

workspaces/ballerina/ballerina-extension/src/features/ai/service/datamapper/datamapper.ts

Lines changed: 130 additions & 39 deletions
Large diffs are not rendered by default.

workspaces/ballerina/ballerina-extension/src/features/ai/service/datamapper/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ export interface RepairedFiles {
5353
repairedFiles: SourceFile[];
5454
}
5555

56+
export interface CodeRepairResult {
57+
finalContent: string;
58+
customFunctionsContent: string;
59+
}
60+
5661
// =============================================================================
5762
// MAPPING HINTS
5863
// =============================================================================

workspaces/ballerina/ballerina-extension/src/rpc-managers/ai-panel/repair-utils.ts

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,3 +330,98 @@ export async function addMissingRequiredFields(
330330

331331
return projectModified;
332332
}
333+
334+
export async function addCheckExpressionErrors(
335+
diagnosticsResult: Diagnostics[],
336+
langClient: ExtendedLangClient
337+
): Promise<boolean> {
338+
let projectModified = false;
339+
340+
for (const diag of diagnosticsResult) {
341+
const fileUri = diag.uri;
342+
const diagnostics = diag.diagnostics;
343+
344+
// Filter BCE3032 diagnostics (check expression errors)
345+
const checkExprDiagnostics = diagnostics.filter(d => d.code === "BCE3032");
346+
if (!checkExprDiagnostics.length) {
347+
continue;
348+
}
349+
350+
const astModifications: STModification[] = [];
351+
352+
// Process each diagnostic individually
353+
for (const diagnostic of checkExprDiagnostics) {
354+
try {
355+
// Get code actions for the diagnostic
356+
const codeActions = await langClient.codeAction({
357+
textDocument: { uri: fileUri },
358+
range: {
359+
start: diagnostic.range.start,
360+
end: diagnostic.range.end
361+
},
362+
context: {
363+
diagnostics: [diagnostic],
364+
only: ['quickfix'],
365+
triggerKind: 1
366+
}
367+
});
368+
369+
if (!codeActions?.length) {
370+
console.warn(`No code actions returned for ${fileUri} at line ${diagnostic.range.start.line}`);
371+
continue;
372+
}
373+
374+
// Find the action that adds error to return type
375+
// The language server typically provides actions like "Change return type to ..."
376+
const action = codeActions.find(
377+
action => action.title && (
378+
action.title.toLowerCase().includes("change") &&
379+
action.title.toLowerCase().includes("return") &&
380+
action.title.toLowerCase().includes("error")
381+
)
382+
);
383+
384+
if (!action?.edit?.documentChanges?.length) {
385+
continue;
386+
}
387+
388+
const docEdit = action.edit.documentChanges[0] as TextDocumentEdit;
389+
390+
// Process all edits from the code action
391+
for (const edit of docEdit.edits) {
392+
astModifications.push({
393+
startLine: edit.range.start.line,
394+
startColumn: edit.range.start.character,
395+
endLine: edit.range.end.line,
396+
endColumn: edit.range.end.character,
397+
type: "INSERT",
398+
isImport: false,
399+
config: { STATEMENT: edit.newText }
400+
});
401+
}
402+
} catch (err) {
403+
console.warn(`Could not apply code action for ${fileUri} at line ${diagnostic.range.start.line}:`, err);
404+
}
405+
}
406+
407+
// Apply modifications to syntax tree
408+
if (astModifications.length > 0) {
409+
const syntaxTree = await langClient.stModify({
410+
documentIdentifier: { uri: fileUri },
411+
astModifications: astModifications
412+
});
413+
414+
// Update file content
415+
const { source } = syntaxTree as SyntaxTree;
416+
if (!source) {
417+
// Handle the case where source is undefined, when compiler issue occurs
418+
return false;
419+
}
420+
const absolutePath = fileURLToPath(fileUri);
421+
writeBallerinaFileDidOpenTemp(absolutePath, source);
422+
projectModified = true;
423+
}
424+
}
425+
426+
return projectModified;
427+
}

workspaces/ballerina/ballerina-extension/src/rpc-managers/ai-panel/rpc-manager.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,23 @@ export class AiPanelRpcManager implements AIPanelAPI {
673673
throw new Error("Not a Ballerina project.");
674674
}
675675
await addToIntegration(projectPath, params.fileChanges);
676-
updateView();
676+
677+
const context = StateMachine.context();
678+
const dataMapperMetadata = context.dataMapperMetadata;
679+
if (!dataMapperMetadata || !dataMapperMetadata.codeData) {
680+
updateView();
681+
return true;
682+
}
683+
684+
// Refresh data mapper with the updated code
685+
let filePath = dataMapperMetadata.codeData.lineRange?.fileName;
686+
const varName = dataMapperMetadata.name;
687+
if (!filePath || !varName) {
688+
updateView();
689+
return true;
690+
}
691+
692+
await refreshDataMapper(filePath, dataMapperMetadata.codeData, varName);
677693
return true;
678694
} catch (error) {
679695
console.error(">>> Failed to add files to the project", error);

workspaces/ballerina/ballerina-extension/src/rpc-managers/ai-panel/utils.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { getAskResponse } from "../../../src/features/ai/service/ask/ask";
2828
import { MappingFileRecord} from "./types";
2929
import { generateAutoMappings, generateRepairCode } from "../../../src/features/ai/service/datamapper/datamapper";
3030
import { ArtifactNotificationHandler, ArtifactsUpdated } from "../../utils/project-artifacts-handler";
31+
import { CopilotEventHandler } from "../../../src/features/ai/service/event";
3132

3233
// const BACKEND_BASE_URL = BACKEND_URL.replace(/\/v2\.0$/, "");
3334
//TODO: Temp workaround as custom domain seem to block file uploads
@@ -154,15 +155,18 @@ async function convertAttachmentToFileData(attachment: Attachment): Promise<File
154155
// Processes data mapper model and optional mapping instruction files to generate mapping expressions
155156
export async function generateMappingExpressionsFromModel(
156157
dataMapperModel: DMModel,
157-
mappingInstructionFiles: Attachment[] = []
158+
mappingInstructionFiles: Attachment[] = [],
159+
eventHandler: CopilotEventHandler
158160
): Promise<Mapping[]> {
159161
let dataMapperResponse: DataMapperModelResponse = {
160162
mappingsModel: dataMapperModel as DMModel
161163
};
162164
if (mappingInstructionFiles.length > 0) {
165+
eventHandler({ type: "content_block", content: "\n<progress>Processing mapping hints from attachments...</progress>" });
163166
const enhancedResponse = await enrichModelWithMappingInstructions(mappingInstructionFiles, dataMapperResponse);
164167
dataMapperResponse = enhancedResponse as DataMapperModelResponse;
165168
}
169+
eventHandler({ type: "content_block", content: "\n<progress>Generating data mappings...</progress>" });
166170

167171
const generatedMappings = await generateAutoMappings(dataMapperResponse);
168172
return generatedMappings.map(mapping => ({

0 commit comments

Comments
 (0)