import { OutputPort, OutputOptions } from '../../domain/ports/OutputPort'; import { ReviewReport, SecurityIssue, TestSuggestion, DocSuggestion } from '../../domain/entities'; import { marked } from 'marked'; import * as fs from 'fs/promises'; import * as path from 'path'; import chalk from 'chalk'; import ora from 'ora'; export class OutputAdapter implements OutputPort { private spinner: any | null = null; async displayReviewReport(report: ReviewReport, options: OutputOptions = { format: 'console' }): Promise { const { format = 'console' } = options; switch (format) { case 'console': await this.displayReviewReportConsole(report, options); break; case 'markdown': await this.displayReviewReportMarkdown(report, options); break; case 'json': await this.displayReviewReportJSON(report, options); break; case 'html': await this.displayReviewReportHTML(report, options); break; case 'file': await this.exportToFile(report, options.outputPath || 'review-report.json', 'json'); break; default: throw new Error(`Unsupported output format: ${format}`); } } async displaySecurityIssues(issues: SecurityIssue[], options: OutputOptions = { format: 'console' }): Promise { const { format = 'console' } = options; switch (format) { case 'console': await this.displaySecurityIssuesConsole(issues, options); break; case 'markdown': await this.displaySecurityIssuesMarkdown(issues, options); break; case 'json': await this.displaySecurityIssuesJSON(issues, options); break; case 'html': await this.displaySecurityIssuesHTML(issues, options); break; case 'file': await this.exportToFile(issues, options.outputPath || 'security-issues.json', 'json'); break; default: throw new Error(`Unsupported output format: ${format}`); } } async displayTestSuggestions(suggestions: TestSuggestion[], options: OutputOptions = { format: 'console' }): Promise { const { format = 'console' } = options; switch (format) { case 'console': await this.displayTestSuggestionsConsole(suggestions, options); break; case 'markdown': await this.displayTestSuggestionsMarkdown(suggestions, options); break; case 'json': await this.displayTestSuggestionsJSON(suggestions, options); break; case 'html': await this.displayTestSuggestionsHTML(suggestions, options); break; case 'file': await this.exportToFile(suggestions, options.outputPath || 'test-suggestions.json', 'json'); break; default: throw new Error(`Unsupported output format: ${format}`); } } async displayDocSuggestions(suggestions: DocSuggestion[], options: OutputOptions = { format: 'console' }): Promise { const { format = 'console' } = options; switch (format) { case 'console': await this.displayDocSuggestionsConsole(suggestions, options); break; case 'markdown': await this.displayDocSuggestionsMarkdown(suggestions, options); break; case 'json': await this.displayDocSuggestionsJSON(suggestions, options); break; case 'html': await this.displayDocSuggestionsHTML(suggestions, options); break; case 'file': await this.exportToFile(suggestions, options.outputPath || 'doc-suggestions.json', 'json'); break; default: throw new Error(`Unsupported output format: ${format}`); } } async displayMessage(message: string, options: OutputOptions = { format: 'console' }): Promise { const { format = 'console', colorize = true } = options; if (format === 'console') { if (colorize) { console.log(chalk.blue(message)); } else { console.log(message); } } else if (format === 'file' && options.outputPath) { await this.exportToFile(message, options.outputPath, 'markdown'); } else { console.log(message); } } async displayError(error: string, options: OutputOptions = { format: 'console' }): Promise { const { format = 'console', colorize = true } = options; if (format === 'console') { if (colorize) { console.error(chalk.red(error)); } else { console.error(error); } } else { console.error(error); } } async displayWarning(warning: string, options: OutputOptions = { format: 'console' }): Promise { const { format = 'console', colorize = true } = options; if (format === 'console') { if (colorize) { console.warn(chalk.yellow(warning)); } else { console.warn(warning); } } else { console.warn(warning); } } async displaySuccess(message: string, options: OutputOptions = { format: 'console' }): Promise { const { format = 'console', colorize = true } = options; if (format === 'console') { if (colorize) { console.log(chalk.green(message)); } else { console.log(message); } } else { console.log(message); } } displayProgress(message: string): void { this.spinner = ora(message).start(); } clearProgress(): void { if (this.spinner) { this.spinner.stop(); this.spinner = null; } } async displayTable(data: Record[], options: OutputOptions = { format: 'console' }): Promise { const { format = 'console' } = options; if (format === 'console') { console.table(data); } else if (format === 'markdown') { const markdown = this.convertTableToMarkdown(data); await this.displayMessage(markdown, options); } else { await this.exportToFile(data, options.outputPath || 'table.json', 'json'); } } async exportToFile(data: unknown, filePath: string, format: 'json' | 'markdown' | 'html'): Promise { let content: string; switch (format) { case 'json': content = JSON.stringify(data, null, 2); break; case 'markdown': content = typeof data === 'string' ? data : JSON.stringify(data, null, 2); break; case 'html': content = this.convertToHTML(data); break; default: throw new Error(`Unsupported export format: ${format}`); } await fs.writeFile(filePath, content, 'utf-8'); console.log(`Exported to: ${filePath}`); } private async displayReviewReportConsole(report: ReviewReport, options: OutputOptions): Promise { const { colorize = true } = options; console.log('\n' + (colorize ? chalk.bold.blue('๐Ÿ“‹ Review Report') : 'Review Report')); console.log('=' .repeat(50)); console.log(`Summary: ${report.summary}`); console.log(`Overall Score: ${this.getScoreColor(report.overallScore, colorize)}`); console.log(`Timestamp: ${report.timestamp.toISOString()}`); console.log('\n' + (colorize ? chalk.bold('๐Ÿ“Š Metrics') : 'Metrics')); console.log('-'.repeat(20)); console.log(`Total Comments: ${report.metrics.totalComments}`); console.log(`Errors: ${report.metrics.errorCount}`); console.log(`Warnings: ${report.metrics.warningCount}`); console.log(`Info: ${report.metrics.infoCount}`); console.log(`Suggestions: ${report.metrics.suggestionCount}`); console.log(`Files Reviewed: ${report.metrics.filesReviewed}`); console.log(`Lines Added: ${report.metrics.linesAdded}`); console.log(`Lines Removed: ${report.metrics.linesRemoved}`); if (report.comments.length > 0) { console.log('\n' + (colorize ? chalk.bold('๐Ÿ’ฌ Comments') : 'Comments')); console.log('-'.repeat(20)); for (const comment of report.comments) { console.log(`\n${colorize ? chalk.bold.cyan(comment.filePath) : comment.filePath}${comment.lineNumber ? `:${colorize ? chalk.gray(comment.lineNumber.toString()) : comment.lineNumber}` : ''}`); // Parse JSON response if it's a JSON string if (typeof comment.message === 'string' && comment.message.trim().startsWith('```json')) { try { const jsonMatch = comment.message.match(/```json\n([\s\S]*?)\n```/); if (jsonMatch) { const jsonData = JSON.parse(jsonMatch[1] || '{}'); if (Array.isArray(jsonData)) { for (const item of jsonData) { console.log(` ${this.getSeverityColor((item.severity || comment.severity) as string, colorize)} [${colorize ? chalk.magenta(item.category || comment.category) : (item.category || comment.category)}] ${item.message || comment.message}`); if (item.suggestion) { console.log(` ${colorize ? chalk.green('๐Ÿ’ก Suggestion:') : '๐Ÿ’ก Suggestion:'} ${item.suggestion}`); } } } else { console.log(` ${this.getSeverityColor((jsonData.severity || comment.severity) as string, colorize)} [${colorize ? chalk.magenta(jsonData.category || comment.category) : (jsonData.category || comment.category)}] ${jsonData.message || comment.message}`); if (jsonData.suggestion) { console.log(` ${colorize ? chalk.green('๐Ÿ’ก Suggestion:') : '๐Ÿ’ก Suggestion:'} ${jsonData.suggestion}`); } } } else { // Fallback to original message if JSON parsing fails console.log(` ${this.getSeverityColor(comment.severity, colorize)} [${colorize ? chalk.magenta(comment.category) : comment.category}] ${comment.message}`); } } catch (error) { // Fallback to original message if JSON parsing fails console.log(` ${this.getSeverityColor(comment.severity, colorize)} [${colorize ? chalk.magenta(comment.category) : comment.category}] ${comment.message}`); } } else { // Regular message display console.log(` ${this.getSeverityColor(comment.severity, colorize)} [${colorize ? chalk.magenta(comment.category) : comment.category}] ${comment.message}`); } if (comment.suggestion && typeof comment.message !== 'string') { console.log(` ${colorize ? chalk.green('๐Ÿ’ก Suggestion:') : '๐Ÿ’ก Suggestion:'} ${comment.suggestion}`); } } } if (report.recommendations.length > 0) { console.log('\n' + (colorize ? chalk.bold('๐ŸŽฏ Recommendations') : 'Recommendations')); console.log('-'.repeat(20)); for (const rec of report.recommendations) { console.log(`โ€ข ${rec}`); } } } private async displaySecurityIssuesConsole(issues: SecurityIssue[], options: OutputOptions): Promise { const { colorize = true } = options; console.log('\n' + (colorize ? chalk.bold.red('๐Ÿ”’ Security Issues') : 'Security Issues')); console.log('=' .repeat(50)); if (issues.length === 0) { console.log(colorize ? chalk.green('โœ… No security issues found!') : 'โœ… No security issues found!'); return; } for (const issue of issues) { console.log(`\n${colorize ? chalk.bold.cyan(issue.filePath) : issue.filePath}${issue.lineNumber ? `:${colorize ? chalk.gray(issue.lineNumber.toString()) : issue.lineNumber}` : ''}`); // Parse JSON response if it's a JSON string if (typeof issue.description === 'string' && issue.description.trim().startsWith('```json')) { try { const jsonMatch = issue.description.match(/```json\n([\s\S]*?)\n```/); if (jsonMatch) { const jsonData = JSON.parse(jsonMatch[1] || '{}'); if (Array.isArray(jsonData)) { for (const item of jsonData) { console.log(` ${this.getSeverityColor((item.severity || issue.severity) as string, colorize)} [${colorize ? chalk.magenta(item.category || issue.category) : (item.category || issue.category)}] ${item.title || issue.title}`); console.log(` ${colorize ? chalk.yellow('Description:') : 'Description:'} ${item.description || issue.description}`); console.log(` ${colorize ? chalk.green('Remediation:') : 'Remediation:'} ${item.remediation || issue.remediation}`); if (item.references && item.references.length > 0) { console.log(` ${colorize ? chalk.blue('References:') : 'References:'}`); for (const ref of item.references) { console.log(` โ€ข ${ref}`); } } } } else { console.log(` ${this.getSeverityColor((jsonData.severity || issue.severity) as string, colorize)} [${colorize ? chalk.magenta(jsonData.category || issue.category) : (jsonData.category || issue.category)}] ${jsonData.title || issue.title}`); console.log(` ${colorize ? chalk.yellow('Description:') : 'Description:'} ${jsonData.description || issue.description}`); console.log(` ${colorize ? chalk.green('Remediation:') : 'Remediation:'} ${jsonData.remediation || issue.remediation}`); if (jsonData.references && jsonData.references.length > 0) { console.log(` ${colorize ? chalk.blue('References:') : 'References:'}`); for (const ref of jsonData.references) { console.log(` โ€ข ${ref}`); } } } } else { // Fallback to original description if JSON parsing fails console.log(` ${this.getSeverityColor(issue.severity, colorize)} [${colorize ? chalk.magenta(issue.category) : issue.category}] ${issue.title}`); console.log(` ${colorize ? chalk.yellow('Description:') : 'Description:'} ${issue.description}`); console.log(` ${colorize ? chalk.green('Remediation:') : 'Remediation:'} ${issue.remediation}`); } } catch (error) { // Fallback to original description if JSON parsing fails console.log(` ${this.getSeverityColor(issue.severity, colorize)} [${colorize ? chalk.magenta(issue.category) : issue.category}] ${issue.title}`); console.log(` ${colorize ? chalk.yellow('Description:') : 'Description:'} ${issue.description}`); console.log(` ${colorize ? chalk.green('Remediation:') : 'Remediation:'} ${issue.remediation}`); } } else { // Regular issue display console.log(` ${this.getSeverityColor(issue.severity, colorize)} [${colorize ? chalk.magenta(issue.category) : issue.category}] ${issue.title}`); console.log(` ${colorize ? chalk.yellow('Description:') : 'Description:'} ${issue.description}`); console.log(` ${colorize ? chalk.green('Remediation:') : 'Remediation:'} ${issue.remediation}`); } if (issue.references && issue.references.length > 0 && typeof issue.description !== 'string') { console.log(` ${colorize ? chalk.blue('References:') : 'References:'}`); for (const ref of issue.references) { console.log(` โ€ข ${ref}`); } } } } private async displayTestSuggestionsConsole(suggestions: TestSuggestion[], options: OutputOptions): Promise { const { colorize = true } = options; console.log('\n' + (colorize ? chalk.bold.green('๐Ÿงช Test Suggestions') : 'Test Suggestions')); console.log('=' .repeat(50)); for (const suggestion of suggestions) { console.log(`\n${colorize ? chalk.bold.cyan(suggestion.description) : suggestion.description}`); console.log(`${colorize ? chalk.yellow('Framework:') : 'Framework:'} ${colorize ? chalk.cyan(suggestion.framework) : suggestion.framework}`); console.log(`${colorize ? chalk.yellow('Type:') : 'Type:'} ${colorize ? chalk.cyan(suggestion.testType) : suggestion.testType}`); if (suggestion.targetFunction) { console.log(`${colorize ? chalk.yellow('Target:') : 'Target:'} ${colorize ? chalk.cyan(suggestion.targetFunction) : suggestion.targetFunction}`); } // Parse JSON response if it's a JSON string if (typeof suggestion.testCode === 'string' && suggestion.testCode.trim().startsWith('```json')) { try { const jsonMatch = suggestion.testCode.match(/```json\n([\s\S]*?)\n```/); if (jsonMatch) { const jsonData = JSON.parse(jsonMatch[1] || '{}'); console.log(`\n${colorize ? chalk.bold.green('Test Code:') : 'Test Code:'}`); // Display test code if present if (jsonData.testCode) { console.log(`${colorize ? chalk.gray('```') : '```'}${suggestion.framework}`); console.log(jsonData.testCode); console.log(`${colorize ? chalk.gray('```') : '```'}`); } // Display test cases if present if (jsonData.testCases && Array.isArray(jsonData.testCases) && jsonData.testCases.length > 0) { console.log(`\n${colorize ? chalk.bold.magenta('Test Cases:') : 'Test Cases:'}`); for (const testCase of jsonData.testCases) { console.log(` ${colorize ? chalk.green('โ€ข') : 'โ€ข'} ${colorize ? chalk.cyan(testCase.name || testCase.title) : (testCase.name || testCase.title)}: ${testCase.description || testCase.content}`); } } // Display description if present if (jsonData.description) { console.log(`\n${colorize ? chalk.bold.blue('Description:') : 'Description:'}`); console.log(` ${jsonData.description}`); } } else { // Fallback to original test code if JSON parsing fails console.log(`\n${colorize ? chalk.bold.green('Test Code:') : 'Test Code:'}`); console.log(suggestion.testCode); } } catch (error) { // Fallback to original test code if JSON parsing fails console.log(`\n${colorize ? chalk.bold.green('Test Code:') : 'Test Code:'}`); console.log(suggestion.testCode); } } else { // Regular test code display console.log(`\n${colorize ? chalk.bold.green('Test Code:') : 'Test Code:'}`); console.log(suggestion.testCode); } if (suggestion.testCases.length > 0 && typeof suggestion.testCode !== 'string') { console.log(`\n${colorize ? chalk.bold.magenta('Test Cases:') : 'Test Cases:'}`); for (const testCase of suggestion.testCases) { console.log(` ${colorize ? chalk.green('โ€ข') : 'โ€ข'} ${testCase.name}: ${testCase.description}`); } } } } private async displayDocSuggestionsConsole(suggestions: DocSuggestion[], options: OutputOptions): Promise { const { colorize = true } = options; console.log('\n' + (colorize ? chalk.bold.cyan('๐Ÿ“š Documentation Suggestions') : 'Documentation Suggestions')); console.log('=' .repeat(50)); for (const suggestion of suggestions) { console.log(`\n${colorize ? chalk.bold.cyan(suggestion.title) : suggestion.title}`); console.log(`${colorize ? chalk.yellow('Type:') : 'Type:'} ${suggestion.type}`); console.log(`${colorize ? chalk.yellow('Format:') : 'Format:'} ${suggestion.format}`); if (suggestion.targetFile) { console.log(`${colorize ? chalk.yellow('Target:') : 'Target:'} ${colorize ? chalk.cyan(suggestion.targetFile) : suggestion.targetFile}`); } // Parse JSON response if it's a JSON string if (typeof suggestion.content === 'string' && suggestion.content.trim().startsWith('```json')) { try { const jsonMatch = suggestion.content.match(/```json\n([\s\S]*?)\n```/); if (jsonMatch) { const jsonData = JSON.parse(jsonMatch[1] || '{}'); console.log(`\n${colorize ? chalk.bold('Content:') : 'Content:'}`); // Display title if present if (jsonData.title) { console.log(`${colorize ? chalk.bold.blue('Title:') : 'Title:'} ${jsonData.title}`); } // Display main content if (jsonData.content) { console.log(`\n${colorize ? chalk.bold('Description:') : 'Description:'}`); console.log(` ${jsonData.content}`); } // Display examples if present if (jsonData.examples && Array.isArray(jsonData.examples) && jsonData.examples.length > 0) { console.log(`\n${colorize ? chalk.bold.green('Examples:') : 'Examples:'}`); for (let i = 0; i < jsonData.examples.length; i++) { console.log(` ${colorize ? chalk.green(`${i + 1}.`) : `${i + 1}.`} ${jsonData.examples[i]}`); } } // Display parameters if present if (jsonData.parameters && Array.isArray(jsonData.parameters) && jsonData.parameters.length > 0) { console.log(`\n${colorize ? chalk.bold.magenta('Parameters:') : 'Parameters:'}`); for (const param of jsonData.parameters) { console.log(` ${colorize ? chalk.cyan(`โ€ข ${param.name}`) : `โ€ข ${param.name}`} ${colorize ? chalk.gray(`(${param.type})`) : `(${param.type})`}`); console.log(` ${colorize ? chalk.yellow('Required:') : 'Required:'} ${param.required ? (colorize ? chalk.red('Yes') : 'Yes') : (colorize ? chalk.green('No') : 'No')}`); if (param.description) { console.log(` ${colorize ? chalk.yellow('Description:') : 'Description:'} ${param.description}`); } } } // Display return type if present if (jsonData.returnType) { console.log(`\n${colorize ? chalk.bold.blue('Return Type:') : 'Return Type:'} ${colorize ? chalk.cyan(jsonData.returnType) : jsonData.returnType}`); } // Display see also if present if (jsonData.seeAlso && Array.isArray(jsonData.seeAlso) && jsonData.seeAlso.length > 0) { console.log(`\n${colorize ? chalk.bold.blue('See Also:') : 'See Also:'}`); for (const item of jsonData.seeAlso) { console.log(` โ€ข ${colorize ? chalk.blue(item) : item}`); } } } else { // Fallback to original content if JSON parsing fails console.log(`\n${colorize ? chalk.bold('Content:') : 'Content:'}`); console.log(suggestion.content); } } catch (error) { // Fallback to original content if JSON parsing fails console.log(`\n${colorize ? chalk.bold('Content:') : 'Content:'}`); console.log(suggestion.content); } } else { // Regular content display console.log(`\n${colorize ? chalk.bold('Content:') : 'Content:'}`); console.log(suggestion.content); } } } private async displayReviewReportMarkdown(report: ReviewReport, options: OutputOptions): Promise { let markdown = `# Review Report\n\n`; markdown += `**Summary:** ${report.summary}\n\n`; markdown += `**Overall Score:** ${report.overallScore}/100\n\n`; markdown += `**Timestamp:** ${report.timestamp.toISOString()}\n\n`; markdown += `## Metrics\n\n`; markdown += `- Total Comments: ${report.metrics.totalComments}\n`; markdown += `- Errors: ${report.metrics.errorCount}\n`; markdown += `- Warnings: ${report.metrics.warningCount}\n`; markdown += `- Info: ${report.metrics.infoCount}\n`; markdown += `- Suggestions: ${report.metrics.suggestionCount}\n`; markdown += `- Files Reviewed: ${report.metrics.filesReviewed}\n`; markdown += `- Lines Added: ${report.metrics.linesAdded}\n`; markdown += `- Lines Removed: ${report.metrics.linesRemoved}\n\n`; if (report.comments.length > 0) { markdown += `## Comments\n\n`; for (const comment of report.comments) { markdown += `### ${comment.filePath}${comment.lineNumber ? `:${comment.lineNumber}` : ''}\n\n`; markdown += `**Severity:** ${comment.severity}\n\n`; markdown += `**Category:** ${comment.category}\n\n`; markdown += `**Message:** ${comment.message}\n\n`; if (comment.suggestion) { markdown += `**Suggestion:** ${comment.suggestion}\n\n`; } markdown += `---\n\n`; } } if (report.recommendations.length > 0) { markdown += `## Recommendations\n\n`; for (const rec of report.recommendations) { markdown += `- ${rec}\n`; } } await this.displayMessage(markdown, options); } private async displaySecurityIssuesMarkdown(issues: SecurityIssue[], options: OutputOptions): Promise { let markdown = `# Security Issues\n\n`; if (issues.length === 0) { markdown += `โœ… No security issues found!\n`; } else { for (const issue of issues) { markdown += `## ${issue.title}\n\n`; markdown += `**Severity:** ${issue.severity}\n\n`; markdown += `**Category:** ${issue.category}\n\n`; markdown += `**File:** ${issue.filePath}${issue.lineNumber ? `:${issue.lineNumber}` : ''}\n\n`; markdown += `**Description:** ${issue.description}\n\n`; markdown += `**Remediation:** ${issue.remediation}\n\n`; if (issue.references && issue.references.length > 0) { markdown += `**References:**\n`; for (const ref of issue.references) { markdown += `- ${ref}\n`; } markdown += `\n`; } markdown += `---\n\n`; } } await this.displayMessage(markdown, options); } private async displayTestSuggestionsMarkdown(suggestions: TestSuggestion[], options: OutputOptions): Promise { let markdown = `# Test Suggestions\n\n`; for (const suggestion of suggestions) { markdown += `## ${suggestion.description}\n\n`; markdown += `**Framework:** ${suggestion.framework}\n\n`; markdown += `**Type:** ${suggestion.testType}\n\n`; if (suggestion.targetFunction) { markdown += `**Target Function:** ${suggestion.targetFunction}\n\n`; } markdown += `**Test Code:**\n\`\`\`${suggestion.framework}\n${suggestion.testCode}\n\`\`\`\n\n`; if (suggestion.testCases.length > 0) { markdown += `**Test Cases:**\n`; for (const testCase of suggestion.testCases) { markdown += `- **${testCase.name}:** ${testCase.description}\n`; } markdown += `\n`; } markdown += `---\n\n`; } await this.displayMessage(markdown, options); } private async displayDocSuggestionsMarkdown(suggestions: DocSuggestion[], options: OutputOptions): Promise { let markdown = `# Documentation Suggestions\n\n`; for (const suggestion of suggestions) { markdown += `## ${suggestion.title}\n\n`; markdown += `**Type:** ${suggestion.type}\n\n`; markdown += `**Format:** ${suggestion.format}\n\n`; if (suggestion.targetFile) { markdown += `**Target File:** ${suggestion.targetFile}\n\n`; } markdown += `**Content:**\n\n${suggestion.content}\n\n`; if (suggestion.examples && suggestion.examples.length > 0) { markdown += `**Examples:**\n`; for (const example of suggestion.examples) { markdown += `\`\`\`\n${example}\n\`\`\`\n`; } markdown += `\n`; } markdown += `---\n\n`; } await this.displayMessage(markdown, options); } private async displayReviewReportJSON(report: ReviewReport, options: OutputOptions): Promise { await this.displayMessage(JSON.stringify(report, null, 2), options); } private async displaySecurityIssuesJSON(issues: SecurityIssue[], options: OutputOptions): Promise { await this.displayMessage(JSON.stringify(issues, null, 2), options); } private async displayTestSuggestionsJSON(suggestions: TestSuggestion[], options: OutputOptions): Promise { await this.displayMessage(JSON.stringify(suggestions, null, 2), options); } private async displayDocSuggestionsJSON(suggestions: DocSuggestion[], options: OutputOptions): Promise { await this.displayMessage(JSON.stringify(suggestions, null, 2), options); } private async displayReviewReportHTML(report: ReviewReport, options: OutputOptions): Promise { const html = this.convertReviewReportToHTML(report); await this.displayMessage(html, options); } private async displaySecurityIssuesHTML(issues: SecurityIssue[], options: OutputOptions): Promise { const html = this.convertSecurityIssuesToHTML(issues); await this.displayMessage(html, options); } private async displayTestSuggestionsHTML(suggestions: TestSuggestion[], options: OutputOptions): Promise { const html = this.convertTestSuggestionsToHTML(suggestions); await this.displayMessage(html, options); } private async displayDocSuggestionsHTML(suggestions: DocSuggestion[], options: OutputOptions): Promise { const html = this.convertDocSuggestionsToHTML(suggestions); await this.displayMessage(html, options); } private getScoreColor(score: number, colorize: boolean): string { if (!colorize) return score.toString(); if (score >= 80) return chalk.green(score.toString()); if (score >= 60) return chalk.yellow(score.toString()); return chalk.red(score.toString()); } private getSeverityColor(severity: string, colorize: boolean): string { if (!colorize) return `[${severity}]`; switch (severity) { case 'error': return chalk.red(`[${severity}]`); case 'warning': return chalk.yellow(`[${severity}]`); case 'info': return chalk.blue(`[${severity}]`); case 'suggestion': return chalk.cyan(`[${severity}]`); default: return `[${severity}]`; } } private convertTableToMarkdown(data: Record[]): string { if (data.length === 0) return ''; const headers = Object.keys(data[0] || {}); let markdown = `| ${headers.join(' | ')} |\n`; markdown += `| ${headers.map(() => '---').join(' | ')} |\n`; for (const row of data) { const values = headers.map(header => String(row[header] || '')); markdown += `| ${values.join(' | ')} |\n`; } return markdown; } private convertToHTML(data: unknown): string { // Simple HTML conversion - in a real implementation, you'd want more sophisticated templating return ` AI Developer Assistant Output

AI Developer Assistant Output

Generated on ${new Date().toISOString()}

${JSON.stringify(data, null, 2)}
`; } private convertReviewReportToHTML(report: ReviewReport): string { return ` Review Report

๐Ÿ“‹ Review Report

Summary: ${report.summary}

Overall Score: ${report.overallScore}/100

Timestamp: ${report.timestamp.toISOString()}

๐Ÿ“Š Metrics

  • Total Comments: ${report.metrics.totalComments}
  • Errors: ${report.metrics.errorCount}
  • Warnings: ${report.metrics.warningCount}
  • Info: ${report.metrics.infoCount}
  • Suggestions: ${report.metrics.suggestionCount}
  • Files Reviewed: ${report.metrics.filesReviewed}
  • Lines Added: ${report.metrics.linesAdded}
  • Lines Removed: ${report.metrics.linesRemoved}

๐Ÿ’ฌ Comments

${report.comments.map(comment => `

${comment.filePath}${comment.lineNumber ? `:${comment.lineNumber}` : ''}

[${comment.severity}] [${comment.category}] ${comment.message}

${comment.suggestion ? `

๐Ÿ’ก Suggestion: ${comment.suggestion}

` : ''}
`).join('')}
${report.recommendations.length > 0 ? `

๐ŸŽฏ Recommendations

    ${report.recommendations.map(rec => `
  • ${rec}
  • `).join('')}
` : ''} `; } private convertSecurityIssuesToHTML(issues: SecurityIssue[]): string { return ` Security Issues

๐Ÿ”’ Security Issues

Found ${issues.length} security issue(s)

${issues.map(issue => `

${issue.title}

Severity: ${issue.severity}

Category: ${issue.category}

File: ${issue.filePath}${issue.lineNumber ? `:${issue.lineNumber}` : ''}

Description: ${issue.description}

Remediation: ${issue.remediation}

${issue.references && issue.references.length > 0 ? `

References:

    ${issue.references.map(ref => `
  • ${ref}
  • `).join('')}
` : ''}
`).join('')} `; } private convertTestSuggestionsToHTML(suggestions: TestSuggestion[]): string { return ` Test Suggestions

๐Ÿงช Test Suggestions

Generated ${suggestions.length} test suggestion(s)

${suggestions.map(suggestion => `

${suggestion.description}

Framework: ${suggestion.framework}

Type: ${suggestion.testType}

${suggestion.targetFunction ? `

Target Function: ${suggestion.targetFunction}

` : ''}

Test Code:

${suggestion.testCode}
${suggestion.testCases.length > 0 ? `

Test Cases:

    ${suggestion.testCases.map(testCase => `
  • ${testCase.name}: ${testCase.description}
  • `).join('')}
` : ''}
`).join('')} `; } private convertDocSuggestionsToHTML(suggestions: DocSuggestion[]): string { return ` Documentation Suggestions

๐Ÿ“š Documentation Suggestions

Generated ${suggestions.length} documentation suggestion(s)

${suggestions.map(suggestion => `

${suggestion.title}

Type: ${suggestion.type}

Format: ${suggestion.format}

${suggestion.targetFile ? `

Target File: ${suggestion.targetFile}

` : ''}

Content:

${suggestion.content}
${suggestion.examples && suggestion.examples.length > 0 ? `

Examples:

${suggestion.examples.map(example => `
${example}
`).join('')} ` : ''}
`).join('')} `; } }