UNPKG

@aaswe/codebase-ai

Version:

AI-Assisted Software Engineering (AASWE) - Rich codebase context for IDE LLMs

865 lines 38.1 kB
"use strict"; /** * Knowledge Graph Populator * * Automatic knowledge graph population system that ingests TTL files * into Neo4j database with intelligent entity creation and relationship mapping. */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.KnowledgeGraphPopulator = void 0; const path = __importStar(require("path")); const events_1 = require("events"); const logger_1 = __importDefault(require("../../utils/logger")); const Neo4jDatabaseService_1 = require("../layer2/neo4j-database/Neo4jDatabaseService"); /** * Knowledge Graph Populator * * Orchestrates automatic population of Neo4j knowledge graph from TTL files * with intelligent entity extraction, relationship mapping, and conflict resolution. */ class KnowledgeGraphPopulator extends events_1.EventEmitter { config; neo4jService; isInitialized = false; constructor(config = {}) { super(); this.config = { neo4jUri: process.env.NEO4J_URI || 'bolt://localhost:7687', neo4jUsername: process.env.NEO4J_USERNAME || 'neo4j', neo4jPassword: process.env.NEO4J_PASSWORD || 'password', neo4jDatabase: process.env.NEO4J_DATABASE || 'neo4j', batchSize: 50, enableIndexCreation: true, enableConstraintCreation: true, preserveExistingData: true, conflictResolution: 'merge', ...config }; this.neo4jService = new Neo4jDatabaseService_1.Neo4jDatabaseService(); } /** * Initialize the knowledge graph populator */ async initialize() { if (this.isInitialized) { return; } try { logger_1.default.info('Initializing Knowledge Graph Populator', { neo4jUri: this.config.neo4jUri, database: this.config.neo4jDatabase, batchSize: this.config.batchSize }); // Connect to Neo4j await this.neo4jService.connect({ uri: this.config.neo4jUri, username: this.config.neo4jUsername, password: this.config.neo4jPassword, database: this.config.neo4jDatabase || 'neo4j' }); // Test connection const isConnected = await this.neo4jService.testConnection(); if (!isConnected) { throw new Error('Failed to establish Neo4j connection'); } // Create schema if enabled if (this.config.enableConstraintCreation) { await this.createKnowledgeGraphSchema(); } // Create indexes if enabled if (this.config.enableIndexCreation) { await this.createKnowledgeGraphIndexes(); } this.isInitialized = true; logger_1.default.info('Knowledge Graph Populator initialized successfully'); } catch (error) { logger_1.default.error('Failed to initialize Knowledge Graph Populator', { error }); throw error; } } /** * Populate knowledge graph from TTL files */ async populateFromTTLFiles(ttlFilePaths) { if (!this.isInitialized) { await this.initialize(); } const startTime = Date.now(); const result = { success: false, totalTTLFiles: ttlFilePaths.length, processedFiles: 0, failedFiles: 0, totalNodesCreated: 0, totalRelationshipsCreated: 0, totalPropertiesSet: 0, processingTime: 0, errors: [], warnings: [], statistics: this.initializeStats() }; try { logger_1.default.info('Starting knowledge graph population', { totalFiles: ttlFilePaths.length, batchSize: this.config.batchSize }); // Process TTL files in batches const batches = this.createBatches(ttlFilePaths, this.config.batchSize); for (let i = 0; i < batches.length; i++) { const batch = batches[i]; logger_1.default.info(`Processing batch ${i + 1}/${batches.length}`, { batchSize: batch.length }); try { const batchResult = await this.processTTLBatch(batch); // Aggregate results result.processedFiles += batchResult.successfulFiles; result.failedFiles += batchResult.failedFiles; result.totalNodesCreated += batchResult.totalNodesCreated; result.totalRelationshipsCreated += batchResult.totalRelationshipsCreated; result.errors.push(...batchResult.errors.map(err => ({ type: 'INGESTION_ERROR', message: err.message, sourceFile: err.sourceFile, details: err }))); this.emit('batch_processed', { batchIndex: i + 1, totalBatches: batches.length, batchResult }); } catch (error) { logger_1.default.error(`Failed to process batch ${i + 1}`, { error }); result.errors.push({ type: 'INGESTION_ERROR', message: `Batch processing failed: ${error.message}`, details: { batchIndex: i + 1, batchSize: batch.length } }); result.failedFiles += batch.length; } } // Calculate final statistics result.statistics = await this.calculatePopulationStatistics(); result.processingTime = Date.now() - startTime; result.success = result.errors.length === 0 || result.processedFiles > 0; logger_1.default.info('Knowledge graph population completed', { success: result.success, processedFiles: result.processedFiles, failedFiles: result.failedFiles, totalNodes: result.totalNodesCreated, totalRelationships: result.totalRelationshipsCreated, processingTime: result.processingTime }); this.emit('population_completed', result); return result; } catch (error) { logger_1.default.error('Knowledge graph population failed', { error }); result.errors.push({ type: 'CONNECTION_ERROR', message: `Population failed: ${error.message}`, details: error }); result.processingTime = Date.now() - startTime; this.emit('population_failed', { error, result }); return result; } } /** * Populate knowledge graph from TTL content map */ async populateFromTTLContent(ttlContentMap) { if (!this.isInitialized) { await this.initialize(); } const startTime = Date.now(); const result = { success: false, totalTTLFiles: ttlContentMap.size, processedFiles: 0, failedFiles: 0, totalNodesCreated: 0, totalRelationshipsCreated: 0, totalPropertiesSet: 0, processingTime: 0, errors: [], warnings: [], statistics: this.initializeStats() }; try { logger_1.default.info('Starting knowledge graph population from content', { totalModules: ttlContentMap.size }); for (const [ttlPath, ttlData] of ttlContentMap) { try { // Extract entities from TTL content const entities = await this.extractEntitiesFromTTL(ttlPath, ttlData); // Create knowledge graph entities const creationResult = await this.createKnowledgeGraphEntities(entities); result.processedFiles++; result.totalNodesCreated += creationResult.nodesCreated; result.totalRelationshipsCreated += creationResult.relationshipsCreated; result.totalPropertiesSet += creationResult.propertiesSet; logger_1.default.debug('Processed TTL module', { ttlPath, nodesCreated: creationResult.nodesCreated, relationshipsCreated: creationResult.relationshipsCreated }); } catch (error) { logger_1.default.error('Failed to process TTL content', { ttlPath, error }); result.failedFiles++; result.errors.push({ type: 'INGESTION_ERROR', message: `Failed to process ${ttlPath}: ${error.message}`, sourceFile: ttlPath, details: error }); } } // Calculate final statistics result.statistics = await this.calculatePopulationStatistics(); result.processingTime = Date.now() - startTime; result.success = result.errors.length === 0 || result.processedFiles > 0; logger_1.default.info('Knowledge graph population from content completed', { success: result.success, processedFiles: result.processedFiles, failedFiles: result.failedFiles, totalNodes: result.totalNodesCreated, totalRelationships: result.totalRelationshipsCreated }); this.emit('population_completed', result); return result; } catch (error) { logger_1.default.error('Knowledge graph population from content failed', { error }); result.errors.push({ type: 'CONNECTION_ERROR', message: `Population failed: ${error.message}`, details: error }); result.processingTime = Date.now() - startTime; return result; } } /** * Update knowledge graph incrementally for specific modules */ async updateModules(moduleUpdates) { if (!this.isInitialized) { await this.initialize(); } const startTime = Date.now(); logger_1.default.info('Starting incremental knowledge graph update', { modulesToUpdate: moduleUpdates.size }); const result = { success: false, totalTTLFiles: moduleUpdates.size, processedFiles: 0, failedFiles: 0, totalNodesCreated: 0, totalRelationshipsCreated: 0, totalPropertiesSet: 0, processingTime: 0, errors: [], warnings: [], statistics: this.initializeStats() }; try { for (const [moduleId, moduleData] of moduleUpdates) { try { // Remove existing module data if conflict resolution is 'replace' if (this.config.conflictResolution === 'replace') { await this.removeModuleFromGraph(moduleId); } // Extract and create updated entities const entities = await this.extractEntitiesFromTTL(moduleId, moduleData); const creationResult = await this.createKnowledgeGraphEntities(entities); result.processedFiles++; result.totalNodesCreated += creationResult.nodesCreated; result.totalRelationshipsCreated += creationResult.relationshipsCreated; result.totalPropertiesSet += creationResult.propertiesSet; logger_1.default.debug('Updated module in knowledge graph', { moduleId, nodesCreated: creationResult.nodesCreated, relationshipsCreated: creationResult.relationshipsCreated }); } catch (error) { logger_1.default.error('Failed to update module', { moduleId, error }); result.failedFiles++; result.errors.push({ type: 'INGESTION_ERROR', message: `Failed to update module ${moduleId}: ${error.message}`, sourceFile: moduleId, details: error }); } } result.statistics = await this.calculatePopulationStatistics(); result.processingTime = Date.now() - startTime; result.success = result.errors.length === 0 || result.processedFiles > 0; logger_1.default.info('Incremental knowledge graph update completed', { success: result.success, processedModules: result.processedFiles, failedModules: result.failedFiles }); return result; } catch (error) { logger_1.default.error('Incremental knowledge graph update failed', { error }); result.errors.push({ type: 'CONNECTION_ERROR', message: `Update failed: ${error.message}`, details: error }); result.processingTime = Date.now() - startTime; return result; } } /** * Get knowledge graph health status */ async getHealthStatus() { if (!this.isInitialized) { throw new Error('Knowledge Graph Populator not initialized'); } try { const healthStatus = await this.neo4jService.checkHealth(); const metrics = await this.neo4jService.getMetrics(); const constraints = await this.neo4jService.getConstraints(); const indexes = await this.neo4jService.getIndexes(); return { neo4jHealth: healthStatus, databaseMetrics: metrics, schemaConstraints: constraints, schemaIndexes: indexes, populationStatistics: await this.calculatePopulationStatistics() }; } catch (error) { logger_1.default.error('Failed to get knowledge graph health status', { error }); throw error; } } /** * Shutdown the knowledge graph populator */ async shutdown() { try { logger_1.default.info('Shutting down Knowledge Graph Populator'); if (this.neo4jService) { await this.neo4jService.disconnect(); } this.isInitialized = false; logger_1.default.info('Knowledge Graph Populator shutdown completed'); } catch (error) { logger_1.default.error('Failed to shutdown Knowledge Graph Populator', { error }); throw error; } } // Private helper methods initializeStats() { return { moduleNodes: 0, classNodes: 0, methodNodes: 0, functionNodes: 0, dependencyRelationships: 0, inheritanceRelationships: 0, containmentRelationships: 0, businessContextNodes: 0 }; } createBatches(items, batchSize) { const batches = []; for (let i = 0; i < items.length; i += batchSize) { batches.push(items.slice(i, i + batchSize)); } return batches; } async processTTLBatch(ttlFilePaths) { try { // Use Neo4j service's batch ingestion capability return await this.neo4jService.batchIngestTTLFiles(ttlFilePaths); } catch (error) { logger_1.default.error('Failed to process TTL batch', { error, batchSize: ttlFilePaths.length }); throw error; } } async extractEntitiesFromTTL(ttlPath, ttlData) { const entities = { modules: [], codeEntities: [], relationships: [] }; try { const content = ttlData.rdfContent || ttlData.content || ttlData; // Basic TTL validation if (!content || typeof content !== 'string') { throw new Error('Invalid TTL content: content is empty or not a string'); } // Check for basic TTL syntax if (!content.includes('@prefix') && !content.includes('aide:')) { throw new Error('Invalid TTL content: missing required prefixes or aide namespace'); } // Extract module information const moduleId = this.extractModuleIdFromTTL(content); const businessDomain = this.extractBusinessDomainFromTTL(content); const moduleEntity = { id: moduleId, name: path.basename(ttlPath, '.module-knowledge.ttl'), filePath: ttlPath, language: this.extractLanguageFromTTL(content), architecturalPatterns: this.extractArchitecturalPatternsFromTTL(content), qualityMetrics: this.extractQualityMetricsFromTTL(content), lastUpdated: new Date(), ...(businessDomain && { businessDomain }) }; entities.modules.push(moduleEntity); // Extract classes const classMatches = content.match(/aide:(\w+)\s+a\s+aide:Class/g) || []; for (const match of classMatches) { const classNameMatch = match.match(/aide:(\w+)/); if (classNameMatch) { const className = classNameMatch[1]; const businessContext = this.extractEntityBusinessContext(content, className); const technicalContext = this.extractEntityTechnicalContext(content, className); entities.codeEntities.push({ id: `${moduleId}_${className}`, name: className, type: 'class', moduleId, ...(businessContext && { businessContext }), ...(technicalContext && { technicalContext }) }); } } // Extract methods const methodMatches = content.match(/aide:(\w+)\s+a\s+aide:Method/g) || []; for (const match of methodMatches) { const methodNameMatch = match.match(/aide:(\w+)/); if (methodNameMatch) { const methodName = methodNameMatch[1]; const signature = this.extractMethodSignature(content, methodName); const businessContext = this.extractEntityBusinessContext(content, methodName); entities.codeEntities.push({ id: `${moduleId}_${methodName}`, name: methodName, type: 'method', moduleId, ...(signature && { signature }), ...(businessContext && { businessContext }) }); } } // Extract functions const functionMatches = content.match(/aide:(\w+)\s+a\s+aide:Function/g) || []; for (const match of functionMatches) { const functionNameMatch = match.match(/aide:(\w+)/); if (functionNameMatch) { const functionName = functionNameMatch[1]; const signature = this.extractFunctionSignature(content, functionName); const businessContext = this.extractEntityBusinessContext(content, functionName); entities.codeEntities.push({ id: `${moduleId}_${functionName}`, name: functionName, type: 'function', moduleId, ...(signature && { signature }), ...(businessContext && { businessContext }) }); } } // Extract relationships const dependencyMatches = content.match(/aide:(\w+)\s+aide:dependsOn\s+aide:(\w+)/g) || []; for (const match of dependencyMatches) { const relationshipMatch = match.match(/aide:(\w+)\s+aide:dependsOn\s+aide:(\w+)/); if (relationshipMatch) { entities.relationships.push({ sourceId: `${moduleId}_${relationshipMatch[1]}`, targetId: `${moduleId}_${relationshipMatch[2]}`, type: 'DEPENDS_ON' }); } } // Extract inheritance relationships const extendsMatches = content.match(/aide:(\w+)\s+aide:extends\s+aide:(\w+)/g) || []; for (const match of extendsMatches) { const relationshipMatch = match.match(/aide:(\w+)\s+aide:extends\s+aide:(\w+)/); if (relationshipMatch) { entities.relationships.push({ sourceId: `${moduleId}_${relationshipMatch[1]}`, targetId: `${moduleId}_${relationshipMatch[2]}`, type: 'EXTENDS' }); } } return entities; } catch (error) { logger_1.default.error('Failed to extract entities from TTL', { ttlPath, error }); throw error; } } async createKnowledgeGraphEntities(entities) { let nodesCreated = 0; let relationshipsCreated = 0; let propertiesSet = 0; try { // Create module nodes for (const module of entities.modules) { const moduleQuery = ` MERGE (m:Module {id: $id}) SET m.name = $name, m.filePath = $filePath, m.language = $language, m.businessDomain = $businessDomain, m.architecturalPatterns = $architecturalPatterns, m.complexityScore = $complexityScore, m.maintainabilityScore = $maintainabilityScore, m.documentationScore = $documentationScore, m.lastUpdated = datetime() RETURN m `; const session = this.neo4jService.getSession(); try { const result = await session.run(moduleQuery, { id: module.id, name: module.name, filePath: module.filePath, language: module.language, businessDomain: module.businessDomain || null, architecturalPatterns: module.architecturalPatterns, complexityScore: module.qualityMetrics.complexity, maintainabilityScore: module.qualityMetrics.maintainability, documentationScore: module.qualityMetrics.documentation }); if (result.records.length > 0) { nodesCreated++; propertiesSet += 9; // Number of properties set } } finally { await session.close(); } } // Create code entity nodes for (const entity of entities.codeEntities) { const entityQuery = ` MERGE (e:CodeEntity {id: $id}) SET e.name = $name, e.type = $type, e.moduleId = $moduleId, e.signature = $signature, e.businessContext = $businessContext, e.technicalContext = $technicalContext, e.lastUpdated = datetime() WITH e MATCH (m:Module {id: $moduleId}) MERGE (m)-[:CONTAINS]->(e) RETURN e `; const session = this.neo4jService.getSession(); try { const result = await session.run(entityQuery, { id: entity.id, name: entity.name, type: entity.type, moduleId: entity.moduleId, signature: entity.signature || null, businessContext: entity.businessContext || null, technicalContext: entity.technicalContext || null }); if (result.records.length > 0) { nodesCreated++; relationshipsCreated++; // CONTAINS relationship propertiesSet += 7; } } finally { await session.close(); } } // Create relationships for (const relationship of entities.relationships) { const relationshipQuery = ` MATCH (source:CodeEntity {id: $sourceId}) MATCH (target:CodeEntity {id: $targetId}) MERGE (source)-[r:${relationship.type}]->(target) SET r.lastUpdated = datetime() RETURN r `; const session = this.neo4jService.getSession(); try { const result = await session.run(relationshipQuery, { sourceId: relationship.sourceId, targetId: relationship.targetId }); if (result.records.length > 0) { relationshipsCreated++; propertiesSet += 1; } } finally { await session.close(); } } return { nodesCreated, relationshipsCreated, propertiesSet }; } catch (error) { logger_1.default.error('Failed to create knowledge graph entities', { error }); throw error; } } async createKnowledgeGraphSchema() { try { logger_1.default.info('Creating knowledge graph schema constraints'); const constraints = [ 'CREATE CONSTRAINT module_id_unique IF NOT EXISTS FOR (m:Module) REQUIRE m.id IS UNIQUE', 'CREATE CONSTRAINT code_entity_id_unique IF NOT EXISTS FOR (e:CodeEntity) REQUIRE e.id IS UNIQUE', 'CREATE CONSTRAINT module_name_exists IF NOT EXISTS FOR (m:Module) REQUIRE m.name IS NOT NULL', 'CREATE CONSTRAINT code_entity_name_exists IF NOT EXISTS FOR (e:CodeEntity) REQUIRE e.name IS NOT NULL' ]; for (const constraint of constraints) { const session = this.neo4jService.getSession(); try { await session.run(constraint); logger_1.default.debug('Created constraint', { constraint }); } catch (error) { // Constraint might already exist, log as warning logger_1.default.warn('Failed to create constraint (might already exist)', { constraint, error }); } finally { await session.close(); } } } catch (error) { logger_1.default.error('Failed to create knowledge graph schema', { error }); throw error; } } async createKnowledgeGraphIndexes() { try { logger_1.default.info('Creating knowledge graph indexes'); const indexes = [ 'CREATE INDEX module_name_idx IF NOT EXISTS FOR (m:Module) ON (m.name)', 'CREATE INDEX module_language_idx IF NOT EXISTS FOR (m:Module) ON (m.language)', 'CREATE INDEX module_business_domain_idx IF NOT EXISTS FOR (m:Module) ON (m.businessDomain)', 'CREATE INDEX code_entity_name_idx IF NOT EXISTS FOR (e:CodeEntity) ON (e.name)', 'CREATE INDEX code_entity_type_idx IF NOT EXISTS FOR (e:CodeEntity) ON (e.type)', 'CREATE INDEX code_entity_module_idx IF NOT EXISTS FOR (e:CodeEntity) ON (e.moduleId)', 'CREATE FULLTEXT INDEX business_context_fulltext IF NOT EXISTS FOR (e:CodeEntity) ON EACH [e.businessContext]', 'CREATE FULLTEXT INDEX technical_context_fulltext IF NOT EXISTS FOR (e:CodeEntity) ON EACH [e.technicalContext]' ]; for (const index of indexes) { const session = this.neo4jService.getSession(); try { await session.run(index); logger_1.default.debug('Created index', { index }); } catch (error) { // Index might already exist, log as warning logger_1.default.warn('Failed to create index (might already exist)', { index, error }); } finally { await session.close(); } } } catch (error) { logger_1.default.error('Failed to create knowledge graph indexes', { error }); throw error; } } async calculatePopulationStatistics() { try { const session = this.neo4jService.getSession(); try { // Count different types of nodes and relationships const statsQuery = ` MATCH (m:Module) OPTIONAL MATCH (e:CodeEntity) OPTIONAL MATCH ()-[r:DEPENDS_ON]->() OPTIONAL MATCH ()-[r2:EXTENDS]->() OPTIONAL MATCH ()-[r3:CONTAINS]->() RETURN count(DISTINCT m) as moduleNodes, count(DISTINCT CASE WHEN e.type = 'class' THEN e END) as classNodes, count(DISTINCT CASE WHEN e.type = 'method' THEN e END) as methodNodes, count(DISTINCT CASE WHEN e.type = 'function' THEN e END) as functionNodes, count(DISTINCT r) as dependencyRelationships, count(DISTINCT r2) as inheritanceRelationships, count(DISTINCT r3) as containmentRelationships, count(DISTINCT CASE WHEN e.businessContext IS NOT NULL THEN e END) as businessContextNodes `; const result = await session.run(statsQuery); if (result.records.length > 0) { const record = result.records[0]; return { moduleNodes: record.get('moduleNodes').toNumber(), classNodes: record.get('classNodes').toNumber(), methodNodes: record.get('methodNodes').toNumber(), functionNodes: record.get('functionNodes').toNumber(), dependencyRelationships: record.get('dependencyRelationships').toNumber(), inheritanceRelationships: record.get('inheritanceRelationships').toNumber(), containmentRelationships: record.get('containmentRelationships').toNumber(), businessContextNodes: record.get('businessContextNodes').toNumber() }; } return this.initializeStats(); } finally { await session.close(); } } catch (error) { logger_1.default.error('Failed to calculate population statistics', { error }); return this.initializeStats(); } } async removeModuleFromGraph(moduleId) { try { const session = this.neo4jService.getSession(); try { // Remove module and all its contained entities const removeQuery = ` MATCH (m:Module {id: $moduleId}) OPTIONAL MATCH (m)-[:CONTAINS]->(e:CodeEntity) DETACH DELETE m, e `; await session.run(removeQuery, { moduleId }); logger_1.default.debug('Removed module from knowledge graph', { moduleId }); } finally { await session.close(); } } catch (error) { logger_1.default.error('Failed to remove module from graph', { moduleId, error }); throw error; } } extractModuleIdFromTTL(content) { const moduleMatch = content.match(/aide:(\w+)\s+a\s+aide:Module/); return moduleMatch ? moduleMatch[1] : `module_${Date.now()}`; } extractLanguageFromTTL(content) { const languageMatch = content.match(/aide:language\s+"([^"]+)"/); return languageMatch ? languageMatch[1] : 'unknown'; } extractBusinessDomainFromTTL(content) { const domainMatch = content.match(/aide:businessDomain\s+"([^"]+)"/); return domainMatch ? domainMatch[1] : undefined; } extractArchitecturalPatternsFromTTL(content) { const patternMatches = content.match(/aide:architecturalPattern\s+"([^"]+)"/g) || []; return patternMatches.map(match => match.replace(/aide:architecturalPattern\s+"([^"]+)"/, '$1')); } extractQualityMetricsFromTTL(content) { const complexityMatch = content.match(/aide:complexity\s+(\d+(?:\.\d+)?)/); const maintainabilityMatch = content.match(/aide:maintainability\s+(\d+(?:\.\d+)?)/); const testCoverageMatch = content.match(/aide:testCoverage\s+(\d+(?:\.\d+)?)/); const documentationMatch = content.match(/aide:documentation\s+(\d+(?:\.\d+)?)/); return { complexity: complexityMatch ? parseFloat(complexityMatch[1]) : 0, maintainability: maintainabilityMatch ? parseFloat(maintainabilityMatch[1]) : 100, testCoverage: testCoverageMatch ? parseFloat(testCoverageMatch[1]) : 0, documentation: documentationMatch ? parseFloat(documentationMatch[1]) : 0 }; } extractEntityBusinessContext(content, entityName) { // Try multiple patterns for business context extraction const patterns = [ new RegExp(`aide:${entityName}\\s+aide:businessContext\\s+"([^"]+)"`), new RegExp(`aide:${entityName}[^;]*aide:businessContext\\s+"([^"]+)"`), new RegExp(`aide:${entityName}[\\s\\S]*?aide:businessContext\\s+"([^"]+)"`) ]; for (const pattern of patterns) { const match = content.match(pattern); if (match) { return match[1]; } } return undefined; } extractEntityTechnicalContext(content, entityName) { const contextMatch = content.match(new RegExp(`aide:${entityName}\\s+aide:technicalContext\\s+"([^"]+)"`)); return contextMatch ? contextMatch[1] : undefined; } extractMethodSignature(content, methodName) { // Try multiple patterns for signature extraction const patterns = [ new RegExp(`aide:${methodName}\\s+aide:signature\\s+"([^"]+)"`), new RegExp(`aide:${methodName}[^;]*aide:signature\\s+"([^"]+)"`), new RegExp(`aide:${methodName}[\\s\\S]*?aide:signature\\s+"([^"]+)"`) ]; for (const pattern of patterns) { const match = content.match(pattern); if (match) { return match[1]; } } return undefined; } extractFunctionSignature(content, functionName) { // Try multiple patterns for signature extraction const patterns = [ new RegExp(`aide:${functionName}\\s+aide:signature\\s+"([^"]+)"`), new RegExp(`aide:${functionName}[^;]*aide:signature\\s+"([^"]+)"`), new RegExp(`aide:${functionName}[\\s\\S]*?aide:signature\\s+"([^"]+)"`) ]; for (const pattern of patterns) { const match = content.match(pattern); if (match) { return match[1]; } } return undefined; } } exports.KnowledgeGraphPopulator = KnowledgeGraphPopulator; //# sourceMappingURL=KnowledgeGraphPopulator.js.map