import { DocumentationPort, DocumentationOptions } from '../../domain/ports/DocumentationPort'; import { DocSuggestion, DocSuggestionImpl, DocParameter } from '../../domain/entities/DocSuggestion'; import { CodeBlock } from '../../domain/entities/CodeBlock'; import { LLMPort } from '../../domain/ports/LLMPort'; export class DocumentationAdapter implements DocumentationPort { constructor(private readonly llmPort: LLMPort) {} async generateDocumentation( codeBlock: CodeBlock, options: DocumentationOptions ): Promise { try { const prompt = this.createDocumentationPrompt(codeBlock, options); const messages = [ { role: 'system' as const, content: 'You are an expert technical writer and software documentation specialist. Generate clear, comprehensive, and accurate documentation that helps developers understand and use the code effectively.', }, { role: 'user' as const, content: prompt, }, ]; const response = await this.llmPort.generateResponse(messages, { temperature: 0.4, maxTokens: 2000, }); return this.parseDocumentationSuggestions(response.content, codeBlock, options); } catch (error) { throw new Error(`Failed to generate documentation: ${error instanceof Error ? error.message : 'Unknown error'}`); } } async generateDocumentationForMultiple( codeBlocks: CodeBlock[], options: DocumentationOptions ): Promise { const allSuggestions: DocSuggestion[] = []; for (const codeBlock of codeBlocks) { const suggestions = await this.generateDocumentation(codeBlock, options); allSuggestions.push(...suggestions); } return allSuggestions; } async generateApiDocumentation( codeBlocks: CodeBlock[], options: DocumentationOptions ): Promise { try { const prompt = this.createApiDocumentationPrompt(codeBlocks, options); const messages = [ { role: 'system' as const, content: 'You are an expert at creating API documentation. Generate comprehensive API documentation that includes endpoints, parameters, responses, examples, and usage instructions.', }, { role: 'user' as const, content: prompt, }, ]; const response = await this.llmPort.generateResponse(messages, { temperature: 0.3, maxTokens: 3000, }); return this.parseDocumentationSuggestions(response.content, codeBlocks[0]!, options); } catch (error) { throw new Error(`Failed to generate API documentation: ${error instanceof Error ? error.message : 'Unknown error'}`); } } async generateReadmeDocumentation( projectInfo: { readonly name: string; readonly description: string; readonly language: string; readonly features: string[]; readonly installation: string; readonly usage: string; }, options: DocumentationOptions ): Promise { try { const prompt = this.createReadmePrompt(projectInfo, options); const messages = [ { role: 'system' as const, content: 'You are an expert at creating project documentation. Generate a comprehensive README that includes project overview, installation instructions, usage examples, and contribution guidelines.', }, { role: 'user' as const, content: prompt, }, ]; const response = await this.llmPort.generateResponse(messages, { temperature: 0.4, maxTokens: 2500, }); const suggestion = new DocSuggestionImpl() .id(`readme-${Date.now()}`) .type('readme') .format(options.format) .title('README.md') .content(response.content) .language(projectInfo.language) .targetFile('README.md') .examples([]) .parameters([]) .seeAlso([]) .build(); return [suggestion]; } catch (error) { throw new Error(`Failed to generate README documentation: ${error instanceof Error ? error.message : 'Unknown error'}`); } } async generateChangelogDocumentation( commits: Array<{ readonly hash: string; readonly message: string; readonly date: Date; readonly author: string; }>, options: DocumentationOptions ): Promise { try { const prompt = this.createChangelogPrompt(commits, options); const messages = [ { role: 'system' as const, content: 'You are an expert at creating changelog documentation. Generate a clear, organized changelog that follows conventional changelog format with proper categorization and versioning.', }, { role: 'user' as const, content: prompt, }, ]; const response = await this.llmPort.generateResponse(messages, { temperature: 0.3, maxTokens: 2000, }); const suggestion = new DocSuggestionImpl() .id(`changelog-${Date.now()}`) .type('changelog') .format(options.format) .title('CHANGELOG.md') .content(response.content) .targetFile('CHANGELOG.md') .examples([]) .parameters([]) .seeAlso([]) .build(); return [suggestion]; } catch (error) { throw new Error(`Failed to generate changelog documentation: ${error instanceof Error ? error.message : 'Unknown error'}`); } } async generateArchitectureDocumentation( codeBlocks: CodeBlock[], options: DocumentationOptions ): Promise { try { const prompt = this.createArchitecturePrompt(codeBlocks, options); const messages = [ { role: 'system' as const, content: 'You are an expert software architect and technical writer. Generate comprehensive architecture documentation that explains system design, components, data flow, and technical decisions.', }, { role: 'user' as const, content: prompt, }, ]; const response = await this.llmPort.generateResponse(messages, { temperature: 0.4, maxTokens: 3000, }); const suggestion = new DocSuggestionImpl() .id(`architecture-${Date.now()}`) .type('architecture') .format(options.format) .title('Architecture Documentation') .content(response.content) .language(options.language) .targetFile('ARCHITECTURE.md') .examples([]) .parameters([]) .seeAlso([]) .build(); return [suggestion]; } catch (error) { throw new Error(`Failed to generate architecture documentation: ${error instanceof Error ? error.message : 'Unknown error'}`); } } async validateDocumentation( documentation: string, codeBlock: CodeBlock ): Promise<{ readonly isValid: boolean; readonly issues: Array<{ readonly type: 'error' | 'warning' | 'suggestion'; readonly message: string; readonly line?: number; }>; }> { try { const prompt = this.createDocumentationValidationPrompt(documentation, codeBlock); const messages = [ { role: 'system' as const, content: 'You are an expert at reviewing technical documentation. Analyze documentation quality, accuracy, completeness, and adherence to best practices.', }, { role: 'user' as const, content: prompt, }, ]; const response = await this.llmPort.generateResponse(messages, { temperature: 0.3, maxTokens: 1500, }); return this.parseValidationResponse(response.content); } catch (error) { return { isValid: false, issues: [{ type: 'error', message: `Failed to validate documentation: ${error instanceof Error ? error.message : 'Unknown error'}`, }], }; } } async generateChangelog( commits: Array<{ readonly hash: string; readonly message: string; readonly date: Date; readonly author: string; }>, options: DocumentationOptions ): Promise { try { const prompt = this.createChangelogPrompt(commits, options); const messages = [ { role: 'system' as const, content: 'You are an expert technical writer specializing in changelog generation. Create clear, organized, and informative changelogs that help users understand what has changed.', }, { role: 'user' as const, content: prompt, }, ]; const response = await this.llmPort.generateResponse(messages, { temperature: 0.3, maxTokens: 4000, }); const changelogContent = response.content; return [ new DocSuggestionImpl() .id(`changelog-${Date.now()}`) .type('changelog' as const) .format(options.format) .title('Changelog') .content(changelogContent) .targetFile('CHANGELOG.md') .language(options.language) .metadata({ commits: commits.length, generatedAt: new Date().toISOString(), }) .build(), ]; } catch (error) { throw new Error(`Failed to generate changelog: ${error instanceof Error ? error.message : 'Unknown error'}`); } } async extractExistingDocumentation( codeBlocks: CodeBlock[] ): Promise { const suggestions: DocSuggestion[] = []; for (const codeBlock of codeBlocks) { const extracted = this.extractDocumentationFromCode(codeBlock); suggestions.push(...extracted); } return suggestions; } private createDocumentationPrompt(codeBlock: CodeBlock, options: DocumentationOptions): string { return ` Generate ${options.format} documentation for the following ${options.language} code: File: ${codeBlock.filePath} Lines: ${codeBlock.startLine}-${codeBlock.endLine} Code: \`\`\`${codeBlock.language} ${codeBlock.content} \`\`\` Requirements: - Format: ${options.format} - Style: ${options.style} - Language: ${options.language} - ${options.includeExamples ? 'Include usage examples' : 'No examples needed'} - ${options.includeParameters ? 'Include parameter documentation' : 'No parameter documentation needed'} - ${options.includeReturnTypes ? 'Include return type documentation' : 'No return type documentation needed'} - ${options.includeSeeAlso ? 'Include see also references' : 'No see also references needed'} Please provide the documentation in JSON format: { "title": "Documentation title", "content": "Complete documentation content", "examples": ${options.includeExamples ? '["example 1", "example 2"]' : '[]'}, "parameters": ${options.includeParameters ? '[{"name": "param1", "type": "string", "description": "parameter description", "required": true}]' : '[]'}, "returnType": ${options.includeReturnTypes ? '"string"' : 'null'}, "seeAlso": ${options.includeSeeAlso ? '["related function", "related class"]' : '[]'} } `; } private createApiDocumentationPrompt(codeBlocks: CodeBlock[], options: DocumentationOptions): string { const codeContent = codeBlocks.map(block => ` File: ${block.filePath} \`\`\`${block.language} ${block.content} \`\`\` `).join('\n'); return ` Generate comprehensive API documentation for the following ${options.language} code: ${codeContent} Requirements: - Format: ${options.format} - Style: ${options.style} - Include endpoint descriptions - Include parameter documentation - Include response examples - Include error handling - Include usage examples Please provide the documentation in JSON format: { "title": "API Documentation", "content": "Complete API documentation", "examples": ["example 1", "example 2"], "parameters": [], "returnType": null, "seeAlso": [] } `; } private createReadmePrompt(projectInfo: any, options: DocumentationOptions): string { return ` Generate a comprehensive README.md for the following project: Project Name: ${projectInfo.name} Description: ${projectInfo.description} Language: ${projectInfo.language} Features: ${projectInfo.features.join(', ')} Installation: ${projectInfo.installation} Usage: ${projectInfo.usage} Requirements: - Format: ${options.format} - Style: ${options.style} - Include project overview - Include installation instructions - Include usage examples - Include feature list - Include contribution guidelines - Include license information - Include badges if applicable Generate a complete README.md content. `; } private createChangelogPrompt(commits: any[], options: DocumentationOptions): string { const commitList = commits.map(commit => ` - ${commit.hash.substring(0, 7)}: ${commit.message} (${commit.author}, ${commit.date.toISOString().split('T')[0]}) `).join(''); return ` Generate a changelog for the following commits: ${commitList} Requirements: - Format: ${options.format} - Style: ${options.style} - Follow conventional changelog format - Categorize changes (Added, Changed, Deprecated, Removed, Fixed, Security) - Include version numbers - Include dates - Include breaking changes - Include migration notes if applicable Generate a complete CHANGELOG.md content. `; } private createArchitecturePrompt(codeBlocks: CodeBlock[], options: DocumentationOptions): string { const codeContent = codeBlocks.map(block => ` File: ${block.filePath} \`\`\`${block.language} ${block.content} \`\`\` `).join('\n'); return ` Generate comprehensive architecture documentation for the following ${options.language} codebase: ${codeContent} Requirements: - Format: ${options.format} - Style: ${options.style} - Include system overview - Include component diagrams - Include data flow - Include technical decisions - Include design patterns - Include scalability considerations - Include security considerations Generate a complete architecture documentation. `; } private createDocumentationValidationPrompt(documentation: string, codeBlock: CodeBlock): string { return ` Validate the quality of this documentation against the code: Documentation: \`\`\` ${documentation} \`\`\` Code: \`\`\`${codeBlock.language} ${codeBlock.content} \`\`\` Check for: 1. Accuracy - does the documentation match the code? 2. Completeness - are all functions/classes documented? 3. Clarity - is the documentation easy to understand? 4. Examples - are there sufficient examples? 5. Best practices - does it follow documentation standards? Provide feedback in JSON format: { "isValid": true/false, "issues": [ { "type": "error|warning|suggestion", "message": "description of the issue", "line": 42 } ] } `; } private parseDocumentationSuggestions(response: string, codeBlock: CodeBlock, options: DocumentationOptions): DocSuggestion[] { try { const parsed = JSON.parse(response); if (parsed.content) { const suggestion = new DocSuggestionImpl() .id(`doc-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`) .type('function') .format(options.format) .title(parsed.title || 'Generated Documentation') .content(parsed.content) .language(options.language) .targetFile(codeBlock.filePath); if (parsed.examples && Array.isArray(parsed.examples)) { suggestion.examples(parsed.examples); } if (parsed.parameters && Array.isArray(parsed.parameters)) { suggestion.parameters(parsed.parameters); } if (parsed.returnType) { suggestion.returnType(parsed.returnType); } if (parsed.seeAlso && Array.isArray(parsed.seeAlso)) { suggestion.seeAlso(parsed.seeAlso); } return [suggestion.build()]; } } catch (error) { // If JSON parsing fails, create a basic documentation suggestion const suggestion = new DocSuggestionImpl() .id(`doc-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`) .type('function') .format(options.format) .title('Generated Documentation') .content(response) .language(options.language) .targetFile(codeBlock.filePath) .examples([]) .parameters([]) .seeAlso([]) .build(); return [suggestion]; } return []; } private parseValidationResponse(response: string): { readonly isValid: boolean; readonly issues: Array<{ readonly type: 'error' | 'warning' | 'suggestion'; readonly message: string; readonly line?: number; }>; } { try { const parsed = JSON.parse(response); return { isValid: parsed.isValid || false, issues: parsed.issues || [], }; } catch (error) { return { isValid: false, issues: [{ type: 'error', message: 'Failed to parse validation response', }], }; } } private extractDocumentationFromCode(codeBlock: CodeBlock): DocSuggestion[] { const suggestions: DocSuggestion[] = []; const lines = codeBlock.content.split('\n'); // Extract JSDoc comments let currentDoc = ''; let docStart = -1; for (let i = 0; i < lines.length; i++) { const line = lines[i]; if (!line) continue; if (line.trim().startsWith('/**')) { currentDoc = line + '\n'; docStart = i; } else if (docStart >= 0 && line.trim().startsWith('*')) { currentDoc += line + '\n'; } else if (docStart >= 0 && line.trim().startsWith('*/')) { currentDoc += line; // Create documentation suggestion const suggestion = new DocSuggestionImpl() .id(`extracted-${Date.now()}-${i}`) .type('function') .format('jsdoc') .title('Extracted Documentation') .content(currentDoc) .language(codeBlock.language) .targetFile(codeBlock.filePath) .examples([]) .parameters([]) .seeAlso([]) .build(); suggestions.push(suggestion); currentDoc = ''; docStart = -1; } } return suggestions; } }