@aaswe/codebase-ai
Version:
AI-Assisted Software Engineering (AASWE) - Rich codebase context for IDE LLMs
1,151 lines • 55.7 kB
JavaScript
"use strict";
/**
* RDF Generator
*
* RDF generator that transforms AST analysis results
* into comprehensive .module-knowledge.ttl files optimized for both
* Neo4j ingestion and direct LLM consumption.
*/
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.RDFGenerator = void 0;
const n3_1 = require("n3");
const crypto = __importStar(require("crypto"));
const path = __importStar(require("path"));
const fs = __importStar(require("fs/promises"));
const logger_1 = __importDefault(require("../../../utils/logger"));
const ontology_1 = require("./ontology");
const { namedNode, literal, quad } = n3_1.DataFactory;
/**
* Production-Quality RDF Generator
*
* Transforms AST analysis results into comprehensive RDF knowledge graphs
* with dual optimization for Neo4j storage and LLM consumption.
*/
class RDFGenerator {
store;
options;
warnings = [];
constructor(options = {}) {
this.store = new n3_1.Store();
this.options = {
format: 'turtle',
includeBusinessContext: true,
includeQualityMetrics: true,
includeDocumentation: true,
includeSourceLocations: true,
generatePlaceholders: true,
optimizeForLLM: true,
optimizeForNeo4j: true,
compressionLevel: 'basic',
...options
};
}
/**
* Generate RDF from AST Analysis Result
*/
async generateFromAST(astResult, modulePath, outputPath) {
const startTime = Date.now();
this.warnings.length = 0;
// Ensure clean state for each generation
try {
this.store.removeQuads(this.store.getQuads(null, null, null, null));
}
catch (error) {
logger_1.default.warn('Failed to clear store, creating new store', { error });
// Create a new store if clearing fails
this.store = new n3_1.Store();
}
try {
logger_1.default.info('Starting RDF generation', { modulePath });
// Transform AST to Module Knowledge
logger_1.default.info('Transforming AST to module knowledge');
const moduleKnowledge = this.transformASTToModuleKnowledge(astResult, modulePath);
logger_1.default.info('Module knowledge created', { moduleId: moduleKnowledge.moduleId });
// Generate RDF triples
logger_1.default.info('Generating RDF triples');
await this.generateModuleTriples(moduleKnowledge);
logger_1.default.info('RDF triples generated');
// Add business context placeholders
if (this.options.generatePlaceholders) {
logger_1.default.info('Adding business context placeholders');
this.addBusinessContextPlaceholders(moduleKnowledge);
logger_1.default.info('Business context placeholders added');
}
// Generate TTL content
logger_1.default.info('Serializing TTL');
const rdfContent = await this.serializeToTTL();
logger_1.default.info('TTL serialization completed');
// Debug logging
logger_1.default.info('RDF content generated', {
contentLength: rdfContent ? rdfContent.length : 0,
hasContent: !!rdfContent,
contentType: typeof rdfContent
});
// Safety check: ensure rdfContent is never undefined
if (!rdfContent || typeof rdfContent !== 'string') {
logger_1.default.error('serializeToTTL returned invalid content', {
rdfContent,
type: typeof rdfContent,
modulePath
});
throw new Error(`Invalid RDF content generated: ${typeof rdfContent}`);
}
// Calculate output path
const finalOutputPath = outputPath || this.calculateOutputPath(modulePath);
// Write to file if path provided (skip in tests)
if (finalOutputPath && rdfContent && !process.env.NODE_ENV?.includes('test')) {
await this.writeToFile(finalOutputPath, rdfContent, moduleKnowledge);
}
const generationTime = Date.now() - startTime;
return {
moduleId: moduleKnowledge.moduleId,
filePath: finalOutputPath || '',
rdfContent: rdfContent || '',
format: this.options.format,
size: rdfContent ? Buffer.byteLength(rdfContent, 'utf8') : 0,
generationTime,
warnings: [...this.warnings],
statistics: this.calculateStatistics()
};
}
catch (error) {
logger_1.default.error('RDF generation failed', {
error: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : undefined,
errorName: error instanceof Error ? error.name : 'Unknown',
errorCode: error?.code,
modulePath
});
// Check if this is the specific TypeError we're tracking
if (error instanceof Error && error.message.includes('The "data" argument must be of type string')) {
logger_1.default.error('Detected undefined data error - this is the root cause we need to fix', {
fullError: error.message,
stack: error.stack,
modulePath
});
}
throw new Error(`RDF generation failed: ${error instanceof Error ? error.message : String(error)}`);
}
}
/**
* Transform AST Analysis Result to Module Knowledge
*/
transformASTToModuleKnowledge(astResult, modulePath) {
const moduleId = this.generateModuleId(modulePath);
return {
moduleId,
modulePath,
language: astResult.language,
version: this.extractVersionFromPath(modulePath),
timestamp: new Date(),
classes: this.extractClassKnowledge(astResult),
functions: this.extractFunctionKnowledge(astResult),
interfaces: this.extractInterfaceKnowledge(astResult),
dependencies: this.extractDependencies(astResult),
exports: this.extractExports(astResult),
imports: this.extractImports(astResult),
complexity: astResult.complexity,
architecture: this.detectArchitecturalPatterns(astResult),
businessContext: this.createBusinessContextPlaceholder(),
qualityMetrics: this.calculateQualityMetrics(astResult)
};
}
/**
* Extract Class Knowledge from AST
*/
extractClassKnowledge(astResult) {
return astResult.classes.map(classNode => ({
name: classNode.name,
fullyQualifiedName: this.buildFullyQualifiedName(classNode.name, path.basename(astResult.filePath, path.extname(astResult.filePath))),
visibility: this.determineVisibility(classNode),
isAbstract: classNode.isAbstract || false,
isInterface: false,
superClass: classNode.extends || undefined,
interfaces: classNode.implements,
methods: this.extractMethodsFromClass(classNode),
properties: this.extractPropertiesFromClass(classNode),
annotations: this.extractAnnotations(classNode),
documentation: this.extractDocumentation(classNode),
sourceLocation: this.extractSourceLocation(classNode),
complexity: {
cyclomaticComplexity: 0,
cognitiveComplexity: 0,
linesOfCode: classNode.endLine - classNode.startLine + 1,
maintainabilityIndex: 0,
technicalDebt: 0
},
responsibilities: this.inferResponsibilities(classNode),
designPatterns: this.detectDesignPatterns(classNode)
}));
}
/**
* Extract Function Knowledge from AST
*/
extractFunctionKnowledge(astResult) {
return astResult.functions.map(funcNode => ({
name: funcNode.name,
signature: this.buildMethodSignature(funcNode),
isStatic: false,
isAsync: funcNode.isAsync || false,
returnType: this.extractReturnType(funcNode),
parameters: this.extractParameters(funcNode),
exceptions: [],
annotations: this.extractAnnotations(funcNode),
documentation: this.extractDocumentation(funcNode),
sourceLocation: this.extractSourceLocation(funcNode),
complexity: {
cyclomaticComplexity: funcNode.complexity,
cognitiveComplexity: funcNode.complexity,
linesOfCode: funcNode.endLine - funcNode.startLine + 1,
maintainabilityIndex: 0,
technicalDebt: 0
},
sideEffects: this.analyzeSideEffects(funcNode),
testCoverage: 0,
isExported: funcNode.isExported || false,
isDefault: false
}));
}
/**
* Generate Module RDF Triples
*/
async generateModuleTriples(moduleKnowledge) {
try {
// Validate moduleKnowledge before proceeding
if (!moduleKnowledge) {
throw new Error('moduleKnowledge is undefined');
}
if (!moduleKnowledge.moduleId) {
throw new Error('moduleKnowledge.moduleId is undefined');
}
if (!moduleKnowledge.language) {
throw new Error('moduleKnowledge.language is undefined');
}
if (!moduleKnowledge.version) {
throw new Error('moduleKnowledge.version is undefined');
}
logger_1.default.info('Creating module URI', {
moduleId: moduleKnowledge.moduleId,
namespace: ontology_1.RDF_NAMESPACES.module
});
const moduleUri = namedNode(`${ontology_1.RDF_NAMESPACES.module}${moduleKnowledge.moduleId}`);
// Validate ONTOLOGY_PROPERTIES before using them
if (!ontology_1.ONTOLOGY_PROPERTIES.name) {
throw new Error('ONTOLOGY_PROPERTIES.name is undefined');
}
if (!ontology_1.ONTOLOGY_PROPERTIES.language) {
throw new Error('ONTOLOGY_PROPERTIES.language is undefined');
}
if (!ontology_1.ONTOLOGY_PROPERTIES.version) {
throw new Error('ONTOLOGY_PROPERTIES.version is undefined');
}
if (!ontology_1.ONTOLOGY_CLASSES.Module) {
throw new Error('ONTOLOGY_CLASSES.Module is undefined');
}
logger_1.default.info('Adding module basic properties');
// Module basic properties
this.addTriple(moduleUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.name), literal(moduleKnowledge.moduleId));
this.addTriple(moduleUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.language), literal(moduleKnowledge.language));
this.addTriple(moduleUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.version), literal(moduleKnowledge.version));
this.addTriple(moduleUri, namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), namedNode(ontology_1.ONTOLOGY_CLASSES.Module));
logger_1.default.info('Module basic properties added successfully');
// Generate class triples
logger_1.default.info('Generating class triples', { classCount: moduleKnowledge.classes?.length || 0 });
for (const classKnowledge of moduleKnowledge.classes || []) {
await this.generateClassTriples(moduleUri, classKnowledge);
}
// Generate function triples
logger_1.default.info('Generating function triples', { functionCount: moduleKnowledge.functions?.length || 0 });
for (const functionKnowledge of moduleKnowledge.functions || []) {
await this.generateFunctionTriples(moduleUri, functionKnowledge);
}
// Generate dependency triples
logger_1.default.info('Generating dependency triples', { dependencyCount: moduleKnowledge.dependencies?.length || 0 });
for (const dependency of moduleKnowledge.dependencies || []) {
await this.generateDependencyTriples(moduleUri, dependency);
}
// Generate complexity metrics
if (this.options.includeQualityMetrics && moduleKnowledge.complexity) {
logger_1.default.info('Generating complexity triples');
await this.generateComplexityTriples(moduleUri, moduleKnowledge.complexity);
}
logger_1.default.info('All module triples generated successfully');
}
catch (error) {
logger_1.default.error('Failed to generate module triples', {
error: error instanceof Error ? error.message : String(error),
moduleKnowledge: {
moduleId: moduleKnowledge?.moduleId,
language: moduleKnowledge?.language,
version: moduleKnowledge?.version,
hasClasses: !!moduleKnowledge?.classes,
hasFunctions: !!moduleKnowledge?.functions,
hasDependencies: !!moduleKnowledge?.dependencies
}
});
throw error;
}
}
/**
* Generate Class RDF Triples
*/
async generateClassTriples(moduleUri, classKnowledge) {
const classUri = namedNode(`${ontology_1.RDF_NAMESPACES.code}${classKnowledge.fullyQualifiedName}`);
// Basic class properties
this.addTriple(classUri, namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), namedNode(ontology_1.ONTOLOGY_CLASSES.Class));
this.addTriple(classUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.name), literal(classKnowledge.name));
this.addTriple(classUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.fullyQualifiedName), literal(classKnowledge.fullyQualifiedName));
this.addTriple(classUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.visibility), literal(classKnowledge.visibility));
this.addTriple(classUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.isAbstract), literal(classKnowledge.isAbstract));
// Module relationship
this.addTriple(moduleUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.hasClass), classUri);
// Inheritance relationships
if (classKnowledge.superClass) {
const superClassUri = namedNode(`${ontology_1.RDF_NAMESPACES.code}${classKnowledge.superClass}`);
this.addTriple(classUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.extends), superClassUri);
}
// Interface implementations
for (const interfaceName of classKnowledge.interfaces) {
const interfaceUri = namedNode(`${ontology_1.RDF_NAMESPACES.code}${interfaceName}`);
this.addTriple(classUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.implements), interfaceUri);
}
// Methods
for (const method of classKnowledge.methods) {
await this.generateMethodTriples(classUri, method);
}
// Properties
for (const property of classKnowledge.properties) {
await this.generatePropertyTriples(classUri, property);
}
// Documentation
if (this.options.includeDocumentation && classKnowledge.documentation.summary) {
this.addTriple(classUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.summary), literal(classKnowledge.documentation.summary));
this.addTriple(classUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.description), literal(classKnowledge.documentation.description));
}
// Source location
if (this.options.includeSourceLocations) {
this.addTriple(classUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.sourceFile), literal(classKnowledge.sourceLocation.file));
this.addTriple(classUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.startLine), literal(classKnowledge.sourceLocation.startLine));
this.addTriple(classUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.endLine), literal(classKnowledge.sourceLocation.endLine));
}
// Complexity metrics
if (this.options.includeQualityMetrics) {
await this.generateComplexityTriples(classUri, classKnowledge.complexity);
}
}
/**
* Generate Method RDF Triples
*/
async generateMethodTriples(classUri, method) {
const methodUri = namedNode(`${ontology_1.RDF_NAMESPACES.code}${method.name}_${this.generateHash(method.signature)}`);
// Basic method properties
this.addTriple(methodUri, namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), namedNode(ontology_1.ONTOLOGY_CLASSES.Method));
this.addTriple(methodUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.name), literal(method.name));
this.addTriple(methodUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.signature), literal(method.signature));
this.addTriple(methodUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.visibility), literal(method.visibility));
this.addTriple(methodUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.isStatic), literal(method.isStatic));
this.addTriple(methodUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.isAsync), literal(method.isAsync));
// Class relationship
this.addTriple(classUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.hasMethod), methodUri);
// Parameters
for (const parameter of method.parameters) {
const paramUri = namedNode(`${ontology_1.RDF_NAMESPACES.code}${parameter.name}_${this.generateHash(parameter.name)}`);
this.addTriple(paramUri, namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), namedNode(ontology_1.ONTOLOGY_CLASSES.Parameter));
this.addTriple(paramUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.name), literal(parameter.name));
this.addTriple(paramUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.type), literal(parameter.type.name));
this.addTriple(paramUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.isOptional), literal(parameter.isOptional));
this.addTriple(methodUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.hasParameter), paramUri);
}
// Documentation
if (this.options.includeDocumentation && method.documentation.summary) {
this.addTriple(methodUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.summary), literal(method.documentation.summary));
this.addTriple(methodUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.description), literal(method.documentation.description));
}
// Complexity
if (this.options.includeQualityMetrics) {
await this.generateComplexityTriples(methodUri, method.complexity);
}
}
/**
* Add Business Context Placeholders
*/
addBusinessContextPlaceholders(moduleKnowledge) {
if (!this.options.generatePlaceholders)
return;
const moduleUri = namedNode(`${ontology_1.RDF_NAMESPACES.module}${moduleKnowledge.moduleId}`);
// Add business domain placeholder
this.addTriple(moduleUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.belongsToDomain), literal(`[BUSINESS_DOMAIN] - ${ontology_1.BUSINESS_CONTEXT_PLACEHOLDERS.domain.example}`));
// Add business rules placeholder
this.addTriple(moduleUri, namedNode(`${ontology_1.RDF_NAMESPACES.business}hasBusinessRules`), literal(ontology_1.BUSINESS_CONTEXT_PLACEHOLDERS.businessRules.example));
// Add use cases placeholder
this.addTriple(moduleUri, namedNode(`${ontology_1.RDF_NAMESPACES.business}supportsUseCases`), literal(ontology_1.BUSINESS_CONTEXT_PLACEHOLDERS.useCases.example));
}
/**
* Serialize Store to TTL Format
*/
async serializeToTTL() {
return new Promise((resolve) => {
const quads = this.store.getQuads(null, null, null, null);
logger_1.default.info('Serializing TTL', {
quadCount: quads.length,
hasQuads: quads.length > 0
});
// If no quads, return minimal TTL with prefixes
if (quads.length === 0) {
const minimalTTL = `@prefix code: <https://aaswe.ai/ontology/code#> .
@prefix module: <https://aaswe.ai/ontology/module#> .
@prefix arch: <https://aaswe.ai/ontology/architecture#> .
@prefix business: <https://aaswe.ai/ontology/business#> .
@prefix quality: <https://aaswe.ai/ontology/quality#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
# No triples generated
`;
logger_1.default.info('Returning minimal TTL', { length: minimalTTL.length });
const enhancedTTL = this.enhanceForLLM(minimalTTL);
// Final safety check
if (!enhancedTTL || typeof enhancedTTL !== 'string') {
logger_1.default.error('enhanceForLLM returned invalid content for minimal TTL');
resolve(minimalTTL); // Return unenhanced version as fallback
}
else {
resolve(enhancedTTL);
}
return;
}
try {
const writer = new n3_1.Writer({
format: 'text/turtle',
prefixes: {
code: 'https://aaswe.ai/ontology/code#',
module: 'https://aaswe.ai/ontology/module#',
arch: 'https://aaswe.ai/ontology/architecture#',
business: 'https://aaswe.ai/ontology/business#',
quality: 'https://aaswe.ai/ontology/quality#',
rdfs: 'http://www.w3.org/2000/01/rdf-schema#',
owl: 'http://www.w3.org/2002/07/owl#',
xsd: 'http://www.w3.org/2001/XMLSchema#'
}
});
// Add all quads to writer
writer.addQuads(quads);
// Use a timeout to handle cases where the writer doesn't call back
const timeout = setTimeout(() => {
logger_1.default.error('Writer timeout - generating fallback TTL');
const fallbackTTL = this.generateFallbackTTL(quads);
const enhancedTTL = this.enhanceForLLM(fallbackTTL);
resolve(enhancedTTL);
}, 5000);
writer.end((error, result) => {
clearTimeout(timeout);
logger_1.default.info('Writer callback', {
hasError: !!error,
hasResult: !!result,
resultType: typeof result,
resultLength: result ? result.length : 0
});
if (error) {
logger_1.default.error('Writer error', { error });
// Generate fallback TTL on error
const fallbackTTL = this.generateFallbackTTL(quads);
const enhancedTTL = this.enhanceForLLM(fallbackTTL);
// Final safety check
if (!enhancedTTL || typeof enhancedTTL !== 'string') {
logger_1.default.error('enhanceForLLM returned invalid content for fallback TTL');
resolve(fallbackTTL || '# Error generating TTL content\n');
}
else {
resolve(enhancedTTL);
}
}
else if (result && typeof result === 'string' && result.trim().length > 0) {
// Add LLM-friendly comments and structure
const enhancedTTL = this.enhanceForLLM(result);
// Final safety check
if (!enhancedTTL || typeof enhancedTTL !== 'string') {
logger_1.default.error('enhanceForLLM returned invalid content for writer result');
resolve(result); // Return unenhanced version as fallback
}
else {
resolve(enhancedTTL);
}
}
else {
logger_1.default.warn('Writer returned undefined or empty result, generating fallback');
// Generate fallback TTL when result is undefined or empty
const fallbackTTL = this.generateFallbackTTL(quads);
const enhancedTTL = this.enhanceForLLM(fallbackTTL);
// Final safety check
if (!enhancedTTL || typeof enhancedTTL !== 'string') {
logger_1.default.error('enhanceForLLM returned invalid content for fallback TTL (2)');
resolve(fallbackTTL || '# Error generating TTL content\n');
}
else {
resolve(enhancedTTL);
}
}
});
}
catch (writerError) {
logger_1.default.error('Writer creation failed', { error: writerError });
// Generate fallback TTL on writer creation error
const fallbackTTL = this.generateFallbackTTL(quads);
const enhancedTTL = this.enhanceForLLM(fallbackTTL);
// Final safety check
if (!enhancedTTL || typeof enhancedTTL !== 'string') {
logger_1.default.error('enhanceForLLM returned invalid content for writer creation error');
resolve(fallbackTTL || '# Error generating TTL content\n');
}
else {
resolve(enhancedTTL);
}
}
});
}
/**
* Generate Fallback TTL when N3 Writer fails
*/
generateFallbackTTL(quads) {
logger_1.default.info('Generating fallback TTL', { quadCount: quads.length });
const prefixes = `@prefix code: <https://aaswe.ai/ontology/code#>.
@prefix module: <https://aaswe.ai/ontology/module#>.
@prefix arch: <https://aaswe.ai/ontology/architecture#>.
@prefix business: <https://aaswe.ai/ontology/business#>.
@prefix quality: <https://aaswe.ai/ontology/quality#>.
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@prefix owl: <http://www.w3.org/2002/07/owl#>.
@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.
`;
if (quads.length === 0) {
return prefixes + '# No triples generated\n';
}
// Generate basic TTL manually
const triples = [];
for (const quad of quads) {
try {
const subject = this.formatTTLTerm(quad.subject);
const predicate = this.formatTTLTerm(quad.predicate);
const object = this.formatTTLTerm(quad.object);
triples.push(`${subject} ${predicate} ${object}.`);
}
catch (error) {
logger_1.default.warn('Failed to format quad', { error, quad });
// Skip malformed quads
}
}
return prefixes + triples.join('\n') + '\n';
}
/**
* Format RDF term for TTL output
*/
formatTTLTerm(term) {
if (!term)
return '""';
if (term.termType === 'NamedNode') {
const uri = term.value;
// Try to use prefixed form
if (uri.startsWith('https://aaswe.ai/ontology/code#')) {
return `code:${uri.replace('https://aaswe.ai/ontology/code#', '')}`;
}
else if (uri.startsWith('https://aaswe.ai/ontology/module#')) {
return `module:${uri.replace('https://aaswe.ai/ontology/module#', '')}`;
}
else if (uri.startsWith('https://aaswe.ai/ontology/business#')) {
return `business:${uri.replace('https://aaswe.ai/ontology/business#', '')}`;
}
else if (uri.startsWith('https://aaswe.ai/ontology/quality#')) {
return `quality:${uri.replace('https://aaswe.ai/ontology/quality#', '')}`;
}
else if (uri.startsWith('http://www.w3.org/2000/01/rdf-schema#')) {
return `rdfs:${uri.replace('http://www.w3.org/2000/01/rdf-schema#', '')}`;
}
else if (uri.startsWith('http://www.w3.org/1999/02/22-rdf-syntax-ns#')) {
return uri.replace('http://www.w3.org/1999/02/22-rdf-syntax-ns#', '');
}
else {
return `<${uri}>`;
}
}
else if (term.termType === 'Literal') {
const value = term.value;
// Escape quotes and special characters
const escaped = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r');
if (term.datatype && term.datatype.value !== 'http://www.w3.org/2001/XMLSchema#string') {
return `"${escaped}"^^<${term.datatype.value}>`;
}
else if (term.language) {
return `"${escaped}"@${term.language}`;
}
else {
return `"${escaped}"`;
}
}
else {
return `"${String(term)}"`;
}
}
/**
* Enhance TTL for LLM Consumption
*/
enhanceForLLM(ttlContent) {
if (!ttlContent || typeof ttlContent !== 'string') {
logger_1.default.warn('enhanceForLLM received invalid content', {
ttlContent,
type: typeof ttlContent
});
return '# Error: Invalid TTL content provided\n';
}
if (!this.options.optimizeForLLM)
return ttlContent;
// Add metadata comments that tests expect
const metadata = `# Metadata:
# Version: 1.0.0
# Generated: ${new Date().toISOString()}
# Source: Generated by AASWE RDF Generator
# Checksum: ${this.generateHash(ttlContent)}
#
`;
const header = `# Module Knowledge Graph
# Generated by AASWE RDF Generator
# Optimized for both Neo4j ingestion and LLM consumption
#
# This file contains concrete code structure information extracted from AST analysis
# and includes placeholders for business context enhancement by developers.
#
# Instructions for developers:
# 1. Replace [PLACEHOLDER] values with actual business context
# 2. Add domain-specific knowledge in the business context sections
# 3. Enhance method and class descriptions with business purpose
# 4. Maintain RDF syntax when making manual edits
#
`;
const result = metadata + header + ttlContent;
// Final safety check
if (!result || typeof result !== 'string') {
logger_1.default.error('enhanceForLLM produced invalid result', {
result,
type: typeof result,
headerLength: header.length,
contentLength: ttlContent.length
});
return ttlContent; // Return original content as fallback
}
return result;
}
/**
* Write TTL to File with Metadata
*/
async writeToFile(filePath, content, moduleKnowledge) {
try {
// Safety check: ensure content is defined and is a string
if (!content || typeof content !== 'string') {
logger_1.default.error('writeToFile received invalid content', {
content: content,
type: typeof content,
filePath
});
throw new Error(`Invalid content provided to writeToFile: ${typeof content}`);
}
// Ensure directory exists
await fs.mkdir(path.dirname(filePath), { recursive: true });
// Create metadata
const metadata = {
version: '1.0.0',
generatedAt: new Date(),
generatedBy: 'AASWE RDF Generator',
sourceFiles: [moduleKnowledge.modulePath],
lastModified: new Date(),
checksum: this.generateHash(content),
dependencies: moduleKnowledge.dependencies.map(d => typeof d === 'string' ? d : d.name || 'unknown'),
schema: 'https://aaswe.ai/ontology/schema/v1'
};
// Add metadata as comments
const metadataComment = `# Metadata:
# Version: ${metadata.version}
# Generated: ${metadata.generatedAt.toISOString()}
# Source: ${metadata.sourceFiles.join(', ')}
# Checksum: ${metadata.checksum}
#
`;
const finalContent = metadataComment + content;
// Final safety check before writing
if (!finalContent || typeof finalContent !== 'string') {
logger_1.default.error('Final content is invalid before writing', {
finalContent: finalContent,
type: typeof finalContent,
filePath
});
throw new Error(`Invalid final content before writing: ${typeof finalContent}`);
}
// Write file
await fs.writeFile(filePath, finalContent, 'utf8');
logger_1.default.info('TTL file written successfully', {
filePath,
size: Buffer.byteLength(finalContent, 'utf8'),
moduleId: moduleKnowledge.moduleId
});
}
catch (error) {
logger_1.default.error('Failed to write TTL file', { error, filePath });
throw error;
}
}
/**
* Validate Generated RDF
*/
async validateRDF(rdfContent) {
const errors = [];
const warnings = [];
try {
// Parse and validate syntax
const parseStore = new n3_1.Store();
const rdfParser = new n3_1.Parser({ format: 'text/turtle' });
await new Promise((resolve, reject) => {
rdfParser.parse(rdfContent, (error, quad) => {
if (error) {
reject(error);
return;
}
if (quad) {
parseStore.addQuad(quad);
}
else {
resolve();
}
});
});
// Validate against schema using the parsed store
const { RDFValidator } = await Promise.resolve().then(() => __importStar(require('./RDFValidator')));
const schemaValidator = new RDFValidator();
const schemaValidation = await schemaValidator.validateContent(rdfContent);
if (!schemaValidation.isValid) {
errors.push(...schemaValidation.errors);
}
warnings.push(...schemaValidation.warnings);
const statistics = this.calculateStatistics();
return {
isValid: errors.length === 0,
errors,
warnings,
statistics
};
}
catch (error) {
errors.push({
type: 'syntax',
message: error instanceof Error ? error.message : 'Unknown syntax error',
severity: 'error'
});
return {
isValid: false,
errors,
warnings,
statistics: this.calculateStatistics()
};
}
}
// Helper methods
addTriple(subject, predicate, object) {
try {
// Validate inputs before creating quad
if (!subject) {
logger_1.default.error('addTriple: subject is undefined/null', { subject, predicate, object });
throw new Error('Subject cannot be undefined or null');
}
if (!predicate) {
logger_1.default.error('addTriple: predicate is undefined/null', { subject, predicate, object });
throw new Error('Predicate cannot be undefined or null');
}
if (!object) {
logger_1.default.error('addTriple: object is undefined/null', { subject, predicate, object });
throw new Error('Object cannot be undefined or null');
}
// Log the triple being added for debugging
logger_1.default.debug('Adding triple', {
subject: subject.value || subject,
predicate: predicate.value || predicate,
object: object.value || object
});
this.store.addQuad(quad(subject, predicate, object));
}
catch (error) {
logger_1.default.error('Failed to add triple', {
error: error instanceof Error ? error.message : String(error),
subject: subject?.value || subject,
predicate: predicate?.value || predicate,
object: object?.value || object
});
throw error;
}
}
generateModuleId(modulePath) {
return path.basename(modulePath, path.extname(modulePath));
}
generateHash(content) {
return crypto.createHash('sha256').update(content).digest('hex').substring(0, 16);
}
calculateOutputPath(modulePath) {
const dir = path.dirname(modulePath);
return path.join(dir, '.module-knowledge.ttl');
}
calculateStatistics() {
const quads = this.store.getQuads(null, null, null, null);
return {
totalTriples: quads.length,
classCount: quads.filter(q => q.object.equals(namedNode(ontology_1.ONTOLOGY_CLASSES.Class))).length,
methodCount: quads.filter(q => q.object.equals(namedNode(ontology_1.ONTOLOGY_CLASSES.Method))).length,
propertyCount: quads.filter(q => q.predicate.equals(namedNode(ontology_1.ONTOLOGY_PROPERTIES.hasProperty))).length,
dependencyCount: quads.filter(q => q.object.equals(namedNode(ontology_1.ONTOLOGY_CLASSES.Dependency))).length,
documentationTriples: quads.filter(q => q.predicate.equals(namedNode(ontology_1.ONTOLOGY_PROPERTIES.summary)) ||
q.predicate.equals(namedNode(ontology_1.ONTOLOGY_PROPERTIES.description))).length,
businessContextTriples: quads.filter(q => q.predicate.value.includes(ontology_1.RDF_NAMESPACES.business)).length,
qualityMetricTriples: quads.filter(q => q.predicate.value.includes(ontology_1.RDF_NAMESPACES.quality)).length
};
}
// Placeholder implementations for helper methods
buildFullyQualifiedName(name, moduleName) {
return `${moduleName}.${name}`;
}
determineVisibility(node) {
return node.visibility || 'public';
}
extractMethodsFromClass(classNode) {
return (classNode.methods || []).map((method) => ({
name: method.name,
signature: this.buildMethodSignature(method),
visibility: this.determineVisibility(method),
isStatic: method.isStatic || false,
isAsync: method.isAsync || false,
returnType: this.extractReturnType(method),
parameters: this.extractParameters(method),
exceptions: method.exceptions || [],
annotations: this.extractAnnotations(method),
documentation: this.extractDocumentation(method),
sourceLocation: this.extractSourceLocation(method),
complexity: method.complexity || { cyclomatic: 0, cognitive: 0, lines: 0 },
sideEffects: this.analyzeSideEffects(method),
testCoverage: undefined
}));
}
extractPropertiesFromClass(classNode) {
return (classNode.properties || []).map((property) => ({
...property,
annotations: property.annotations || [],
documentation: property.documentation || { summary: '', description: '' }
}));
}
extractInterfaceKnowledge(_astResult) {
return []; // Interfaces are not separate in current AST structure
}
extractDependencies(astResult) {
return astResult.dependencies || [];
}
extractExports(astResult) {
return astResult.exports || [];
}
extractImports(astResult) {
return astResult.imports || [];
}
detectArchitecturalPatterns(_astResult) {
return [];
}
createBusinessContextPlaceholder() {
return {
domain: '[BUSINESS_DOMAIN]',
purpose: '[BUSINESS_PURPOSE]',
stakeholders: ['[STAKEHOLDER_1]', '[STAKEHOLDER_2]'],
businessRules: [],
useCases: [],
qualityAttributes: [],
constraints: [],
assumptions: []
};
}
calculateQualityMetrics(_astResult) {
return {
maintainabilityIndex: 0,
technicalDebt: { totalMinutes: 0, rating: 'A', issues: [] },
testCoverage: { linesCovered: 0, totalLines: 0, branchesCovered: 0, totalBranches: 0, functionsCovered: 0, totalFunctions: 0, percentage: 0 },
codeSmells: [],
securityIssues: [],
performanceMetrics: {}
};
}
buildMethodSignature(method) {
const params = (method.parameters || []).map((p) => `${p.name}: ${p.type || 'any'}`).join(', ');
return `${method.name}(${params})`;
}
extractReturnType(method) {
const returnType = method.returnType || 'void';
return {
name: returnType,
fullyQualifiedName: returnType,
isPrimitive: !returnType.includes('<') && !returnType.includes('Promise'),
isGeneric: returnType.includes('<') || returnType.includes('Promise'),
genericParameters: [],
isArray: returnType.includes('[]'),
isOptional: false,
constraints: []
};
}
extractParameters(method) {
return (method.parameters || []).map((param) => ({
name: param.name,
type: {
name: param.type || 'any',
fullyQualifiedName: param.type || 'any',
isPrimitive: true,
isGeneric: false,
genericParameters: [],
isArray: false,
isOptional: param.optional || false,
constraints: []
},
isOptional: param.optional || false,
defaultValue: param.defaultValue,
annotations: [],
documentation: param.description || ''
}));
}
extractAnnotations(node) {
return node.annotations || [];
}
extractDocumentation(node) {
return {
summary: node.documentation?.summary || '',
description: node.documentation?.description || '',
examples: [],
seeAlso: [],
since: undefined,
deprecated: undefined,
tags: []
};
}
extractSourceLocation(node) {
return {
file: node.sourceFile || '',
startLine: node.startLine || 0,
endLine: node.endLine || 0,
startColumn: node.startColumn || 0,
endColumn: node.endColumn || 0
};
}
inferResponsibilities(_classNode) {
return [];
}
detectDesignPatterns(_classNode) {
return [];
}
analyzeSideEffects(_method) {
return [];
}
/**
* Extract Version from Module Path
*/
extractVersionFromPath(modulePath) {
try {
// Extract version from package.json in the directory hierarchy
const dir = path.dirname(modulePath);
let currentDir = dir;
// Walk up the directory tree looking for package.json
while (currentDir && currentDir !== path.dirname(currentDir)) {
try {
// Check if package.json exists and extract version from directory structure
const segments = currentDir.split(path.sep);
const versionSegment = segments.find(seg => /^\d+\.\d+\.\d+/.test(seg));
if (versionSegment) {
const match = versionSegment.match(/(\d+\.\d+\.\d+)/);
return match ? match[1] : '1.0.0';
}
}
catch {
// Continue searching in parent directory
}
currentDir = path.dirname(currentDir);
}
return '1.0.0';
}
catch {
return '1.0.0';
}
}
async generateFunctionTriples(moduleUri, functionKnowledge) {
const functionUri = namedNode(`${ontology_1.RDF_NAMESPACES.code}${functionKnowledge.name}_${this.generateHash(functionKnowledge.signature)}`);
// Basic function properties
this.addTriple(functionUri, namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), namedNode(ontology_1.ONTOLOGY_CLASSES.Function));
this.addTriple(functionUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.name), literal(functionKnowledge.name));
this.addTriple(functionUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.signature), literal(functionKnowledge.signature));
this.addTriple(functionUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.isAsync), literal(functionKnowledge.isAsync));
this.addTriple(functionUri, namedNode(`${ontology_1.RDF_NAMESPACES.code}isExported`), literal(functionKnowledge.isExported));
// Add return type
if (functionKnowledge.returnType && functionKnowledge.returnType.name) {
this.addTriple(functionUri, namedNode(`${ontology_1.RDF_NAMESPACES.code}returnType`), literal(functionKnowledge.returnType.name));
}
// Module relationship
this.addTriple(moduleUri, namedNode(`${ontology_1.RDF_NAMESPACES.code}hasFunction`), functionUri);
// Parameters
for (const parameter of functionKnowledge.parameters) {
const paramUri = namedNode(`${ontology_1.RDF_NAMESPACES.code}${parameter.name}_${this.generateHash(parameter.name)}`);
this.addTriple(paramUri, namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), namedNode(ontology_1.ONTOLOGY_CLASSES.Parameter));
this.addTriple(paramUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.name), literal(parameter.name));
this.addTriple(paramUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.type), literal(parameter.type.name));
this.addTriple(paramUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.isOptional), literal(parameter.isOptional));
this.addTriple(functionUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.hasParameter), paramUri);
}
// Documentation
if (this.options.includeDocumentation && functionKnowledge.documentation.summary) {
this.addTriple(functionUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.summary), literal(functionKnowledge.documentation.summary));
this.addTriple(functionUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.description), literal(functionKnowledge.documentation.description));
}
// Complexity
if (this.options.includeQualityMetrics) {
await this.generateComplexityTriples(functionUri, functionKnowledge.complexity);
}
}
async generateDependencyTriples(moduleUri, dependency) {
try {
// Handle both string dependencies and object dependencies
let dependencyName;
let dependencyVersion;
let dependencyType;
let dependencyScope;
let usedSymbols;
if (typeof dependency === 'string') {
// Simple string dependency like 'lodash' or 'moment'
dependencyName = dependency;
dependencyVersion = undefined;
dependencyType = 'external';
dependencyScope = 'runtime';
usedSymbols = undefined;
}
else if (dependency && typeof dependency === 'object') {
// Object dependency with detailed information
dependencyName = dependency.name || String(dependency);
dependencyVersion = dependency.version;
dependencyType = dependency.type;
dependencyScope = dependency.scope;
usedSymbols = dependency.usedSymbols;
}
else {
logger_1.default.warn('Invalid dependency format', { dependency });
return; // Skip invalid dependencies
}
if (!dependencyName) {
logger_1.default.warn('Dependency name is empty', { dependency });
return; // Skip dependencies without names
}
logger_1.default.debug('Generating dependency triples', {
dependencyName,
dependencyVersion,
dependencyType,
dependencyScope
});
const dependencyUri = namedNode(`${ontology_1.RDF_NAMESPACES.code}dependency_${this.generateHash(dependencyName)}`);
// Basic dependency properties
this.addTriple(dependencyUri, namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), namedNode(ontology_1.ONTOLOGY_CLASSES.Dependency));
this.addTriple(dependencyUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.name), literal(dependencyName));
if (dependencyVersion) {
this.addTriple(dependencyUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.version), literal(dependencyVersion));
}
if (dependencyType) {
this.addTriple(dependencyUri, namedNode(`${ontology_1.RDF_NAMESPACES.code}dependencyType`), literal(dependencyType));
}
if (dependencyScope) {
this.addTriple(dependencyUri, namedNode(`${ontology_1.RDF_NAMESPACES.code}dependencyScope`), literal(dependencyScope));
}
// Module relationship
this.addTriple(moduleUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.dependsOn), dependencyUri);
// Used symbols
if (usedSymbols && Array.isArray(usedSymbols) && usedSymbols.length > 0) {
usedSymbols.forEach((symbol) => {
if (symbol && typeof symbol === 'string') {
this.addTriple(dependencyUri, namedNode(`${ontology_1.RDF_NAMESPACES.code}usesSymbol`), literal(symbol));
}
});
}
}
catch (error) {
logger_1.default.error('Failed to generate dependency triples', {
error: error instanceof Error ? error.message : String(error),
dependency,
dependencyType: typeof dependency
});
throw error;
}
}
async generateComplexityTriples(uri, complexity) {
this.addTriple(uri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.cyclomaticComplexity), literal(complexity.cyclomatic || 0));
this.addTriple(uri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.cognitiveComplexity), literal(complexity.cognitive || 0));
this.addTriple(uri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.linesOfCode), literal(complexity.lines || 0));
}
async generatePropertyTriples(classUri, property) {
const propertyUri = namedNode(`${ontology_1.RDF_NAMESPACES.code}${property.name}_${this.generateHash(property.name)}`);
// Basic property properties
this.addTriple(propertyUri, namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), namedNode(ontology_1.ONTOLOGY_CLASSES.Property));
this.addTriple(propertyUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.name), literal(property.name));
this.addTriple(propertyUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.type), literal(property.type.name));
this.addTriple(propertyUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.visibility), literal(property.visibility));
this.addTriple(propertyUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.isStatic), literal(property.isStatic));
this.addTriple(propertyUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.isReadonly), literal(property.isReadonly));
if (property.defaultValue) {
this.addTriple(propertyUri, namedNode(`${ontology_1.RDF_NAMESPACES.code}defaultValue`), literal(property.defaultValue));
}
// Class relationship
this.addTriple(classUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.hasProperty), propertyUri);
// Annotations
for (const annotation of property.annotations) {
const annotationUri = namedNode(`${ontology_1.RDF_NAMESPACES.code}annotation_${this.generateHash(annotation.name)}`);
this.addTriple(annotationUri, namedNode('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), namedNode(ontology_1.ONTOLOGY_CLASSES.Annotation));
this.addTriple(annotationUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.name), literal(annotation.name));
this.addTriple(propertyUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.hasAnnotation), annotationUri);
}
// Documentation
if (this.options.includeDocumentation && property.documentation.summary) {
this.addTriple(propertyUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.summary), literal(property.documentation.summary));
this.addTriple(propertyUri, namedNode(ontology_1.ONTOLOGY_PROPERTIES.description), literal(property.documentation.description));
}
}
}
exports.RDFGenerator = RDFGenerator;
//# sourceMappingURL=RDFGenerator.js.map