il2cpp-dump-analyzer-mcp
Version:
Agentic RAG system for analyzing IL2CPP dump.cs files from Unity games
276 lines • 10.4 kB
JavaScript
"use strict";
/**
* Abstract base class for IL2CPP code generators
* Provides common functionality and enforces consistent patterns across all generators
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseGenerator = void 0;
const types_1 = require("./types");
/**
* Abstract base generator class that all specific generators must extend
*/
class BaseGenerator {
/**
* Initialize the generator with context
* @param context Generation context containing request, templates, and utilities
*/
constructor(context) {
this.startTime = 0;
this.metrics = {};
this.context = context;
}
/**
* Main entry point for code generation
* @param request Code generation request
* @returns Promise resolving to generation result
*/
async generate(request) {
this.startTime = Date.now();
const errors = [];
const warnings = [];
try {
// Validate the request
const validationResult = await this.validateRequest(request);
if (!validationResult.isValid) {
errors.push(...validationResult.errors.map(err => ({
type: types_1.GenerationErrorType.VALIDATION_ERROR,
message: err.message,
code: 'VALIDATION_FAILED',
context: `Line ${err.line}, Column ${err.column}`
})));
}
warnings.push(...validationResult.warnings);
if (errors.length > 0) {
return this.createErrorResult(request, errors, warnings);
}
// Parse the source entity
const parseStartTime = Date.now();
const parsedEntity = await this.parseSourceEntity(request);
this.metrics.parseTime = Date.now() - parseStartTime;
// Generate the code
const generationStartTime = Date.now();
const generatedCode = await this.generateCode(parsedEntity, request.options);
this.metrics.generationTime = Date.now() - generationStartTime;
// Validate the generated code
const validationStartTime = Date.now();
const codeValidation = await this.validateGeneratedCode(generatedCode);
this.metrics.validationTime = Date.now() - validationStartTime;
if (!codeValidation.isValid) {
errors.push(...codeValidation.errors.map(err => ({
type: types_1.GenerationErrorType.VALIDATION_ERROR,
message: err.message,
code: 'CODE_VALIDATION_FAILED',
context: `Generated code line ${err.line}`
})));
}
warnings.push(...codeValidation.warnings);
// Create successful result
return this.createSuccessResult(request, generatedCode, warnings);
}
catch (error) {
const generationError = {
type: types_1.GenerationErrorType.PARSING_ERROR,
message: error instanceof Error ? error.message : 'Unknown error occurred',
code: 'GENERATION_FAILED',
context: 'Code generation process'
};
errors.push(generationError);
return this.createErrorResult(request, errors, warnings);
}
}
/**
* Validate generated C# code syntax
* @param code Generated code to validate
* @returns Validation result
*/
async validateGeneratedCode(code) {
return this.context.utils.validateCSharpSyntax(code);
}
/**
* Create a successful generation result
* @param request Original request
* @param code Generated code
* @param warnings Any warnings generated
* @returns Success result
*/
createSuccessResult(request, code, warnings) {
const totalTime = Date.now() - this.startTime;
return {
success: true,
code,
metadata: this.createMetadata(request, code, totalTime),
errors: [],
warnings,
metrics: {
totalTime,
parseTime: this.metrics.parseTime || 0,
generationTime: this.metrics.generationTime || 0,
validationTime: this.metrics.validationTime || 0,
memoryUsage: process.memoryUsage().heapUsed
}
};
}
/**
* Create an error result
* @param request Original request
* @param errors Errors that occurred
* @param warnings Any warnings generated
* @returns Error result
*/
createErrorResult(request, errors, warnings) {
const totalTime = Date.now() - this.startTime;
return {
success: false,
metadata: this.createMetadata(request, '', totalTime),
errors,
warnings,
metrics: {
totalTime,
parseTime: this.metrics.parseTime || 0,
generationTime: this.metrics.generationTime || 0,
validationTime: this.metrics.validationTime || 0,
memoryUsage: process.memoryUsage().heapUsed
}
};
}
/**
* Create generation metadata
* @param request Original request
* @param code Generated code
* @param totalTime Total generation time
* @returns Generation metadata
*/
createMetadata(request, code, totalTime) {
return {
requestId: request.id,
timestamp: new Date(),
sourceInfo: this.extractSourceInfo(request),
codeStats: this.calculateCodeStatistics(code),
dependencies: this.extractDependencies(code),
fileInfo: request.target.outputPath ? {
fileName: this.generateFileName(request),
filePath: request.target.outputPath,
fileSize: Buffer.byteLength(code, 'utf8'),
encoding: 'utf8'
} : undefined
};
}
/**
* Extract source entity information
* @param request Generation request
* @returns Source entity info
*/
extractSourceInfo(request) {
const source = request.source;
return {
type: this.getEntityType(source),
name: source.name,
fullName: ('fullName' in source ? source.fullName : undefined) || source.name,
namespace: ('namespace' in source ? source.namespace : undefined) || '',
typeDefIndex: 'typeDefIndex' in source ? source.typeDefIndex : undefined
};
}
/**
* Get entity type string
* @param entity Source entity
* @returns Entity type string
*/
getEntityType(entity) {
if ('isMonoBehaviour' in entity)
return 'class';
if ('values' in entity)
return 'enum';
if ('methods' in entity && !('fields' in entity))
return 'interface';
if ('returnType' in entity)
return 'method';
if ('type' in entity && !('methods' in entity))
return 'field';
return 'unknown';
}
/**
* Calculate code statistics
* @param code Generated code
* @returns Code statistics
*/
calculateCodeStatistics(code) {
const lines = code.split('\n');
const codeLines = lines.filter(line => {
const trimmed = line.trim();
return trimmed.length > 0 && !trimmed.startsWith('//') && !trimmed.startsWith('/*');
});
const methodCount = (code.match(/\b(public|private|protected|internal)\s+.*\s+\w+\s*\(/g) || []).length;
const propertyCount = (code.match(/\b(public|private|protected|internal)\s+.*\s+\w+\s*{\s*(get|set)/g) || []).length;
const fieldCount = (code.match(/\b(public|private|protected|internal)\s+.*\s+\w+\s*[;=]/g) || []).length;
return {
totalLines: lines.length,
codeLines: codeLines.length,
methodCount,
propertyCount,
fieldCount,
complexityScore: this.calculateComplexityScore(code)
};
}
/**
* Calculate complexity score based on code patterns
* @param code Generated code
* @returns Complexity score (1-10)
*/
calculateComplexityScore(code) {
let score = 1;
// Add complexity for control structures
score += (code.match(/\b(if|else|while|for|foreach|switch|try|catch)\b/g) || []).length * 0.5;
// Add complexity for nested structures
score += (code.match(/{[^}]*{/g) || []).length * 0.3;
// Add complexity for generic types
score += (code.match(/<[^>]+>/g) || []).length * 0.2;
return Math.min(Math.round(score), 10);
}
/**
* Extract dependencies from generated code
* @param code Generated code
* @returns Array of dependency strings
*/
extractDependencies(code) {
const usingMatches = code.match(/using\s+([^;]+);/g) || [];
return usingMatches.map(match => match.replace(/using\s+/, '').replace(';', '').trim());
}
/**
* Generate file name based on request
* @param request Generation request
* @returns Generated file name
*/
generateFileName(request) {
const baseName = request.source.name;
const convention = request.target.fileNaming;
const convertedName = this.context.utils.toNamingConvention(baseName, convention);
return `${convertedName}.cs`;
}
/**
* Get template by name from context
* @param templateName Name of template to retrieve
* @returns Template config or undefined
*/
getTemplate(templateName) {
return this.context.templates.get(templateName);
}
/**
* Resolve IL2CPP type to C# type
* @param il2cppType IL2CPP type string
* @returns C# type string
*/
resolveType(il2cppType) {
return this.context.typeResolver.resolveType(il2cppType);
}
/**
* Format generated code according to style options
* @param code Raw generated code
* @param style Code style options
* @returns Formatted code
*/
formatCode(code, style) {
return this.context.utils.formatCode(code, style);
}
}
exports.BaseGenerator = BaseGenerator;
//# sourceMappingURL=base-generator.js.map