import { BaseChunker } from './base';
import { MetadataChunk, Reference } from './types';
export class ApexChunker extends BaseChunker {
chunkMetadata(metadata: any): MetadataChunk[] {
const chunks: MetadataChunk[] = [];
const apexBody = metadata.Body || metadata.body || '';
if (!apexBody) {
return chunks;
}
// Extract class-level information
const classInfo = this.extractClassInfo(apexBody);
// Split by methods
const methods = this.extractMethods(apexBody);
// Create a chunk for class declaration and fields
const classChunk = this.createClassChunk(metadata, classInfo, apexBody);
if (classChunk) {
chunks.push(classChunk);
}
// Create chunks for each method
methods.forEach((method, index) => {
const methodChunk = this.createMethodChunk(metadata, method, index);
if (methodChunk) {
chunks.push(methodChunk);
}
});
return chunks;
}
private extractClassInfo(apexBody: string): any {
const classMatch = apexBody.match(/^[\s\S]*?(public\s+class\s+\w+[\s\S]*?)\s*\{/);
return {
declaration: classMatch ? classMatch[1] : '',
name: this.extractClassName(apexBody)
};
}
private extractClassName(apexBody: string): string {
const match = apexBody.match(/public\s+class\s+(\w+)/);
return match ? match[1] : 'UnknownClass';
}
private extractMethods(apexBody: string): any[] {
const methods: any[] = [];
// Regex to match method signatures with their bodies
const methodRegex = /((?:\/\*[\s\S]*?\*\/\s*)?(?:\/\/.*\n\s*)*\s*(?:@\w+\s*)*(?:global|public|private|protected)?\s*(?:static\s+)?(?:virtual\s+)?(?:override\s+)?(?:\w+\s+)*\w+\s*\([^)]*\)\s*(?:throws\s+\w+\s*)?\s*\{)/g;
let match;
while ((match = methodRegex.exec(apexBody)) !== null) {
const methodStart = match.index;
const methodSignature = match[1];
// Find method body by tracking braces
const methodBody = this.extractMethodBody(apexBody, methodStart);
if (methodBody) {
const methodName = this.extractMethodName(methodSignature);
methods.push({
name: methodName,
signature: methodSignature,
body: methodBody,
startIndex: methodStart
});
}
}
return methods;
}
private extractMethodBody(apexBody: string, startIndex: number): string {
let braceCount = 0;
let inString = false;
let inComment = false;
let i = startIndex;
// Find the opening brace
while (i < apexBody.length && apexBody[i] !== '{') {
i++;
}
if (i >= apexBody.length) return '';
const methodStart = i;
braceCount = 1;
i++;
while (i < apexBody.length && braceCount > 0) {
const char = apexBody[i];
const prevChar = i > 0 ? apexBody[i - 1] : '';
if (!inString && !inComment) {
if (char === '"' && prevChar !== '\\') {
inString = true;
} else if (char === '/' && apexBody[i + 1] === '*') {
inComment = true;
i++; // Skip next char
} else if (char === '{') {
braceCount++;
} else if (char === '}') {
braceCount--;
}
} else if (inString && char === '"' && prevChar !== '\\') {
inString = false;
} else if (inComment && char === '*' && apexBody[i + 1] === '/') {
inComment = false;
i++; // Skip next char
}
i++;
}
return apexBody.substring(startIndex, i);
}
private extractMethodName(signature: string): string {
const match = signature.match(/(\w+)\s*\(/);
return match ? match[1] : 'unknown';
}
private createClassChunk(metadata: any, classInfo: any, fullBody: string): MetadataChunk | null {
if (!classInfo.declaration) return null;
// Extract class declaration, fields, and inner classes
const classContent = this.extractClassDeclaration(fullBody);
const symbols = this.extractBasicSymbols(classContent);
const references = this.extractBasicReferences(classContent);
return this.createBaseChunk(
classInfo.name,
classContent,
'class_declaration',
symbols,
references
);
}
private createMethodChunk(metadata: any, method: any, index: number): MetadataChunk | null {
if (!method.body) return null;
const symbols = this.extractBasicSymbols(method.body);
const references = this.extractBasicReferences(method.body);
// Add method-specific references
references.push({
type: 'method',
name: method.name,
fullName: `${this.extractClassName(this.context.originalMetadata.Body || this.context.originalMetadata.body || '')}.${method.name}`
});
return this.createBaseChunk(
method.name,
method.body,
`method_${index}_${method.name}`,
symbols,
references
);
}
private extractClassDeclaration(apexBody: string): string {
// Extract everything before the first method
const firstMethodMatch = apexBody.match(/((?:@\w+\s*)*(?:global|public|private|protected)\s+(?:static\s+)?(?:virtual\s+)?(?:override\s+)?(?:\w+\s+)*\w+\s*\([^)]*\)\s*\{)/);
if (firstMethodMatch) {
return apexBody.substring(0, firstMethodMatch.index);
}
return apexBody;
}
}