code-simplifier 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,760 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * AI-Powered Knowledge Base
5
+ * Automatically extracts and manages best practices from code analysis
6
+ * Provides intelligent Q&A and learning materials
7
+ */
8
+
9
+ const fs = require('fs-extra')
10
+ const path = require('path')
11
+ const chalk = require('chalk')
12
+ const { OpenAI } = require('openai')
13
+ const Anthropic = require('@anthropic-ai/sdk')
14
+
15
+ /**
16
+ * AI Knowledge Base - Manages best practices, patterns, and learning materials
17
+ */
18
+ class AIKnowledgeBase {
19
+ constructor(config = {}) {
20
+ this.config = {
21
+ dataDir: config.dataDir || path.join(process.cwd(), 'knowledge-base'),
22
+ casesFile: config.casesFile || 'cases.json',
23
+ patternsFile: config.patternsFile || 'patterns.json',
24
+ minCasesPerWeek: config.minCasesPerWeek || 10,
25
+ maxIterations: config.maxIterations || 50,
26
+ openaiApiKey: config.openaiApiKey || process.env.OPENAI_API_KEY,
27
+ anthropicApiKey: config.anthropicApiKey || process.env.ANTHROPIC_API_KEY,
28
+ ...config
29
+ }
30
+
31
+ this.cases = []
32
+ this.patterns = {}
33
+ this.statistics = {
34
+ totalCases: 0,
35
+ weeklyCases: 0,
36
+ tagAccuracy: 0,
37
+ lastUpdated: null
38
+ }
39
+
40
+ this.openai = this.config.openaiApiKey ? new OpenAI({ apiKey: this.config.openaiApiKey }) : null
41
+ this.anthropic = this.config.anthropicApiKey ? new Anthropic({ apiKey: this.config.anthropicApiKey }) : null
42
+
43
+ this.knowledgeDir = path.join(this.config.dataDir, 'knowledge')
44
+ this.examplesDir = path.join(this.config.dataDir, 'examples')
45
+ }
46
+
47
+ /**
48
+ * Initialize the knowledge base
49
+ */
50
+ async initialize() {
51
+ await fs.ensureDir(this.knowledgeDir)
52
+ await fs.ensureDir(this.examplesDir)
53
+ await this.loadKnowledgeBase()
54
+ }
55
+
56
+ /**
57
+ * Load knowledge base from files
58
+ */
59
+ async loadKnowledgeBase() {
60
+ try {
61
+ const casesPath = path.join(this.config.dataDir, this.config.casesFile)
62
+ const patternsPath = path.join(this.config.dataDir, this.config.patternsFile)
63
+
64
+ if (await fs.pathExists(casesPath)) {
65
+ this.cases = await fs.readJson(casesPath)
66
+ }
67
+
68
+ if (await fs.pathExists(patternsPath)) {
69
+ this.patterns = await fs.readJson(patternsPath)
70
+ }
71
+
72
+ this.updateStatistics()
73
+ } catch (error) {
74
+ console.error(chalk.red('Error loading knowledge base:'), error.message)
75
+ this.cases = []
76
+ this.patterns = {}
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Save knowledge base to files
82
+ */
83
+ async saveKnowledgeBase() {
84
+ try {
85
+ await fs.ensureDir(this.config.dataDir)
86
+ const casesPath = path.join(this.config.dataDir, this.config.casesFile)
87
+ const patternsPath = path.join(this.config.dataDir, this.config.patternsFile)
88
+
89
+ await fs.writeJson(casesPath, this.cases, { spaces: 2 })
90
+ await fs.writeJson(patternsPath, this.patterns, { spaces: 2 })
91
+
92
+ this.statistics.lastUpdated = new Date().toISOString()
93
+ } catch (error) {
94
+ console.error(chalk.red('Error saving knowledge base:'), error.message)
95
+ // Don't throw, just log the error
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Extract best practices from code analysis results
101
+ */
102
+ async extractBestPractices(analysisResult, metadata = {}) {
103
+ console.log(chalk.blue('Extracting best practices from analysis...'))
104
+
105
+ const cases = []
106
+
107
+ for (const fileResult of analysisResult.files || []) {
108
+ const issues = fileResult.issues || []
109
+
110
+ for (const issue of issues) {
111
+ if (issue.severity === 'error' || issue.severity === 'warning') {
112
+ const bestPractice = await this.generateBestPractice(issue, fileResult, metadata)
113
+ if (bestPractice) {
114
+ cases.push(bestPractice)
115
+ }
116
+ }
117
+ }
118
+ }
119
+
120
+ // Smart classification and tagging
121
+ for (const caseItem of cases) {
122
+ await this.classifyAndTagCase(caseItem)
123
+ }
124
+
125
+ // Add to knowledge base
126
+ this.cases.push(...cases)
127
+
128
+ // Ensure we meet weekly quota
129
+ await this.ensureWeeklyQuota()
130
+
131
+ // Update statistics
132
+ this.updateStatistics()
133
+
134
+ await this.saveKnowledgeBase()
135
+
136
+ return {
137
+ extracted: cases.length,
138
+ totalCases: this.cases.length,
139
+ weeklyCases: this.statistics.weeklyCases
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Generate best practice from an issue
145
+ */
146
+ async generateBestPractice(issue, fileResult, metadata) {
147
+ const prompt = `
148
+ Based on the following code issue, generate a comprehensive best practice case:
149
+
150
+ Issue: ${issue.type}
151
+ Description: ${issue.description}
152
+ File: ${fileResult.filePath}
153
+ Language: ${fileResult.language}
154
+ Severity: ${issue.severity}
155
+ Location: Line ${issue.line}
156
+
157
+ Code Context:
158
+ ${issue.codeSnippet || 'No code snippet available'}
159
+
160
+ Generate a best practice case in JSON format with:
161
+ 1. title: Clear, descriptive title
162
+ 2. problem: Detailed explanation of the problem
163
+ 3. whyItMatters: Why this issue is important
164
+ 4. solution: Step-by-step solution
165
+ 5. codeExample: Working code example
166
+ 6. tags: Relevant tags (3-5 tags)
167
+ 7. category: Main category
168
+ 8. language: Programming language
169
+ 9. difficulty: beginner/intermediate/advanced
170
+ 10. relatedPatterns: Array of related patterns
171
+ 11. preventionTips: Tips to prevent this issue
172
+
173
+ Return only valid JSON.
174
+ `
175
+
176
+ try {
177
+ const response = await this.generateWithAI(prompt)
178
+ const parsed = JSON.parse(response)
179
+
180
+ return {
181
+ id: this.generateCaseId(),
182
+ timestamp: new Date().toISOString(),
183
+ source: 'ai-analysis',
184
+ sourceFile: fileResult.filePath,
185
+ ...parsed,
186
+ metadata: {
187
+ originalIssue: issue,
188
+ fileLanguage: fileResult.language,
189
+ analysisMetadata: metadata
190
+ }
191
+ }
192
+ } catch (error) {
193
+ console.warn(chalk.yellow('Could not generate AI case, using template:'), error.message)
194
+ return this.createTemplateCase(issue, fileResult)
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Create a template case when AI is not available
200
+ */
201
+ createTemplateCase(issue, fileResult) {
202
+ return {
203
+ id: this.generateCaseId(),
204
+ timestamp: new Date().toISOString(),
205
+ source: 'template',
206
+ sourceFile: fileResult.filePath,
207
+ title: `${issue.type}: ${issue.description}`,
208
+ problem: issue.description,
209
+ whyItMatters: `This ${issue.severity} issue affects code quality and maintainability.`,
210
+ solution: this.getDefaultSolution(issue.type),
211
+ codeExample: issue.codeSnippet || '// Example code needed',
212
+ tags: this.extractTagsFromIssue(issue),
213
+ category: this.getCategoryFromIssue(issue),
214
+ language: fileResult.language || 'unknown',
215
+ difficulty: 'intermediate',
216
+ relatedPatterns: [],
217
+ preventionTips: ['Follow coding standards', 'Regular code reviews', 'Use linters'],
218
+ metadata: {
219
+ originalIssue: issue,
220
+ fileLanguage: fileResult.language
221
+ }
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Classify and tag a case intelligently
227
+ */
228
+ async classifyAndTagCase(caseItem) {
229
+ const prompt = `
230
+ Analyze this best practice case and provide smart classification:
231
+
232
+ Title: ${caseItem.title}
233
+ Problem: ${caseItem.problem}
234
+ Solution: ${caseItem.solution}
235
+
236
+ Provide enhanced tags (3-5 additional tags) and category refinements.
237
+ Focus on: design patterns, anti-patterns, best practices, language-specific idioms.
238
+
239
+ Return JSON with:
240
+ {
241
+ "enhancedTags": ["tag1", "tag2", "tag3"],
242
+ "confidence": 0.95,
243
+ "patternTypes": ["pattern1", "pattern2"]
244
+ }
245
+ `
246
+
247
+ try {
248
+ const response = await this.generateWithAI(prompt)
249
+ const parsed = JSON.parse(response)
250
+
251
+ caseItem.tags = [...new Set([...caseItem.tags, ...parsed.enhancedTags])]
252
+ caseItem.patternTypes = parsed.patternTypes
253
+ caseItem.classificationConfidence = parsed.confidence
254
+ } catch (error) {
255
+ console.warn(chalk.yellow('Classification failed, using defaults'))
256
+ caseItem.classificationConfidence = 0.7
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Generate learning materials and examples
262
+ */
263
+ async generateLearningMaterials(caseId) {
264
+ const caseItem = this.cases.find(c => c.id === caseId)
265
+ if (!caseItem) {
266
+ throw new Error(`Case ${caseId} not found`)
267
+ }
268
+
269
+ const materials = {
270
+ caseId,
271
+ generatedAt: new Date().toISOString(),
272
+ sections: []
273
+ }
274
+
275
+ // Generate different types of learning materials
276
+ materials.sections.push({
277
+ type: 'explanation',
278
+ title: 'Understanding the Problem',
279
+ content: await this.generateExplanation(caseItem)
280
+ })
281
+
282
+ materials.sections.push({
283
+ type: 'example',
284
+ title: 'Code Example',
285
+ content: await this.generateDetailedExample(caseItem)
286
+ })
287
+
288
+ materials.sections.push({
289
+ type: 'exercise',
290
+ title: 'Practice Exercise',
291
+ content: await this.generateExercise(caseItem)
292
+ })
293
+
294
+ materials.sections.push({
295
+ type: 'related',
296
+ title: 'Related Concepts',
297
+ content: await this.findRelatedConcepts(caseItem)
298
+ })
299
+
300
+ // Save materials
301
+ const materialsPath = path.join(this.knowledgeDir, `${caseId}-materials.md`)
302
+ await fs.writeFile(materialsPath, this.formatMaterialsAsMarkdown(materials))
303
+
304
+ return materials
305
+ }
306
+
307
+ /**
308
+ * Answer questions using natural language
309
+ */
310
+ async query(question, options = {}) {
311
+ console.log(chalk.blue(`Processing query: "${question}"`))
312
+
313
+ const prompt = `
314
+ Knowledge Base Query: ${question}
315
+
316
+ Available Cases: ${this.cases.length}
317
+ Categories: ${Object.keys(this.patterns).join(', ')}
318
+
319
+ Search through the knowledge base and provide a comprehensive answer.
320
+ Include:
321
+ 1. Direct answer to the question
322
+ 2. Relevant cases/examples
323
+ 3. Best practices
324
+ 4. Code snippets when applicable
325
+ 5. Related recommendations
326
+
327
+ Format as a helpful, informative response.
328
+ `
329
+
330
+ try {
331
+ const response = await this.generateWithAI(prompt)
332
+
333
+ // Also perform keyword search
334
+ const keywordResults = this.performKeywordSearch(question)
335
+
336
+ return {
337
+ question,
338
+ answer: response,
339
+ relevantCases: keywordResults.cases,
340
+ confidence: keywordResults.confidence,
341
+ timestamp: new Date().toISOString()
342
+ }
343
+ } catch (error) {
344
+ console.warn(chalk.yellow('AI query failed, using keyword search'))
345
+ return this.performKeywordSearch(question)
346
+ }
347
+ }
348
+
349
+ /**
350
+ * Perform keyword-based search
351
+ */
352
+ performKeywordSearch(query) {
353
+ const keywords = query.toLowerCase().split(/\s+/)
354
+ const scoredCases = []
355
+
356
+ for (const caseItem of this.cases) {
357
+ let score = 0
358
+ const searchableText = [
359
+ caseItem.title,
360
+ caseItem.problem,
361
+ caseItem.solution,
362
+ ...(caseItem.tags || [])
363
+ ].join(' ').toLowerCase()
364
+
365
+ for (const keyword of keywords) {
366
+ if (searchableText.includes(keyword)) {
367
+ score += 1
368
+ }
369
+ }
370
+
371
+ if (score > 0) {
372
+ scoredCases.push({
373
+ ...caseItem,
374
+ relevanceScore: score / keywords.length
375
+ })
376
+ }
377
+ }
378
+
379
+ scoredCases.sort((a, b) => b.relevanceScore - a.relevanceScore)
380
+
381
+ return {
382
+ cases: scoredCases.slice(0, 10),
383
+ confidence: scoredCases.length > 0 ? Math.min(scoredCases[0].relevanceScore, 1.0) : 0.0
384
+ }
385
+ }
386
+
387
+ /**
388
+ * Provide related case recommendations
389
+ */
390
+ async getRecommendations(caseId, limit = 5) {
391
+ const caseItem = this.cases.find(c => c.id === caseId)
392
+ if (!caseItem) {
393
+ return []
394
+ }
395
+
396
+ const recommendations = []
397
+
398
+ for (const otherCase of this.cases) {
399
+ if (otherCase.id === caseId) continue
400
+
401
+ let similarity = 0
402
+
403
+ // Check tag overlap
404
+ const commonTags = (caseItem.tags || []).filter(tag =>
405
+ (otherCase.tags || []).includes(tag)
406
+ )
407
+ similarity += commonTags.length * 0.3
408
+
409
+ // Check category match
410
+ if (caseItem.category === otherCase.category) {
411
+ similarity += 0.4
412
+ }
413
+
414
+ // Check language match
415
+ if (caseItem.language === otherCase.language) {
416
+ similarity += 0.2
417
+ }
418
+
419
+ // Check pattern type match
420
+ const commonPatterns = (caseItem.patternTypes || []).filter(pattern =>
421
+ (otherCase.patternTypes || []).includes(pattern)
422
+ )
423
+ similarity += commonPatterns.length * 0.1
424
+
425
+ if (similarity > 0) {
426
+ recommendations.push({
427
+ ...otherCase,
428
+ similarityScore: similarity,
429
+ commonTags,
430
+ commonPatterns
431
+ })
432
+ }
433
+ }
434
+
435
+ recommendations.sort((a, b) => b.similarityScore - a.similarityScore)
436
+
437
+ return recommendations.slice(0, limit)
438
+ }
439
+
440
+ /**
441
+ * Ensure minimum weekly case quota
442
+ */
443
+ async ensureWeeklyQuota() {
444
+ const oneWeekAgo = new Date()
445
+ oneWeekAgo.setDate(oneWeekAgo.getDate() - 7)
446
+
447
+ const recentCases = this.cases.filter(c =>
448
+ new Date(c.timestamp) > oneWeekAgo
449
+ )
450
+
451
+ this.statistics.weeklyCases = recentCases.length
452
+
453
+ if (recentCases.length < this.config.minCasesPerWeek) {
454
+ console.log(chalk.yellow(`Weekly quota not met. Extracting ${this.config.minCasesPerWeek - recentCases.length} more cases...`))
455
+
456
+ // This would typically trigger additional analysis or extraction
457
+ // For now, we'll mark it in statistics
458
+ this.statistics.quotaStatus = 'needs-attention'
459
+ } else {
460
+ this.statistics.quotaStatus = 'met'
461
+ }
462
+ }
463
+
464
+ /**
465
+ * Update statistics
466
+ */
467
+ updateStatistics() {
468
+ this.statistics.totalCases = this.cases.length
469
+
470
+ const oneWeekAgo = new Date()
471
+ oneWeekAgo.setDate(oneWeekAgo.getDate() - 7)
472
+
473
+ const recentCases = this.cases.filter(c =>
474
+ new Date(c.timestamp) > oneWeekAgo
475
+ )
476
+
477
+ this.statistics.weeklyCases = recentCases.length
478
+
479
+ // Calculate tag accuracy (mock implementation)
480
+ const classifiedCases = this.cases.filter(c => c.classificationConfidence)
481
+ if (classifiedCases.length > 0) {
482
+ const avgConfidence = classifiedCases.reduce((sum, c) =>
483
+ sum + (c.classificationConfidence || 0), 0
484
+ ) / classifiedCases.length
485
+ this.statistics.tagAccuracy = avgConfidence * 100
486
+ }
487
+ }
488
+
489
+ /**
490
+ * Generate with AI (OpenAI or Anthropic)
491
+ */
492
+ async generateWithAI(prompt) {
493
+ // Try OpenAI first
494
+ if (this.openai) {
495
+ try {
496
+ const response = await this.openai.chat.completions.create({
497
+ model: 'gpt-4',
498
+ messages: [{ role: 'user', content: prompt }],
499
+ temperature: 0.7,
500
+ max_tokens: 2000
501
+ })
502
+ return response.choices[0].message.content
503
+ } catch (error) {
504
+ console.warn(chalk.yellow('OpenAI failed, trying Anthropic...'))
505
+ }
506
+ }
507
+
508
+ // Try Anthropic
509
+ if (this.anthropic) {
510
+ try {
511
+ const response = await this.anthropic.messages.create({
512
+ model: 'claude-3-5-sonnet-20241022',
513
+ max_tokens: 2000,
514
+ messages: [{ role: 'user', content: prompt }]
515
+ })
516
+ return response.content[0].text
517
+ } catch (error) {
518
+ console.warn(chalk.yellow('Anthropic failed, using mock mode'))
519
+ }
520
+ }
521
+
522
+ // Mock mode
523
+ return this.generateMockResponse(prompt)
524
+ }
525
+
526
+ /**
527
+ * Generate mock response for testing
528
+ */
529
+ generateMockResponse(prompt) {
530
+ if (prompt.includes('best practice case')) {
531
+ return JSON.stringify({
532
+ title: 'Code Quality Best Practice',
533
+ problem: 'This is a mock problem description',
534
+ whyItMatters: 'Quality matters for maintainability',
535
+ solution: 'Follow best practices and coding standards',
536
+ codeExample: '// Example code here',
537
+ tags: ['best-practice', 'quality'],
538
+ category: 'best-practices',
539
+ language: 'javascript',
540
+ difficulty: 'intermediate',
541
+ relatedPatterns: ['clean-code'],
542
+ preventionTips: ['Use linters', 'Code reviews']
543
+ })
544
+ }
545
+
546
+ if (prompt.includes('enhanced tags')) {
547
+ return JSON.stringify({
548
+ enhancedTags: ['refactoring', 'clean-code'],
549
+ confidence: 0.85,
550
+ patternTypes: ['extract-method', 'rename-variable']
551
+ })
552
+ }
553
+
554
+ return 'This is a mock AI response for testing purposes.'
555
+ }
556
+
557
+ /**
558
+ * Generate explanation for learning materials
559
+ */
560
+ async generateExplanation(caseItem) {
561
+ return `
562
+ ## Understanding ${caseItem.title}
563
+
564
+ ### The Problem
565
+ ${caseItem.problem}
566
+
567
+ ### Why It Matters
568
+ ${caseItem.whyItMatters}
569
+
570
+ ### Impact
571
+ - Affects code maintainability
572
+ - Increases technical debt
573
+ - Makes debugging harder
574
+ - Reduces team productivity
575
+
576
+ ### Best Practices
577
+ ${caseItem.preventionTips.map(tip => `- ${tip}`).join('\n')}
578
+ `.trim()
579
+ }
580
+
581
+ /**
582
+ * Generate detailed example
583
+ */
584
+ async generateDetailedExample(caseItem) {
585
+ return `
586
+ ## Code Example (${caseItem.language})
587
+
588
+ ### Bad Example
589
+ \`\`\`${caseItem.language}
590
+ ${caseItem.codeExample}
591
+ \`\`\`
592
+
593
+ ### Good Example
594
+ \`\`\`${caseItem.language}
595
+ // Refactored code following best practices
596
+ // This demonstrates the solution
597
+ `.trim()
598
+ }
599
+
600
+ /**
601
+ * Generate practice exercise
602
+ */
603
+ async generateExercise(caseItem) {
604
+ return `
605
+ ## Practice Exercise
606
+
607
+ ### Task
608
+ Refactor the following code to address the ${caseItem.title} issue.
609
+
610
+ ### Hints
611
+ - Consider the single responsibility principle
612
+ - Follow naming conventions
613
+ - Keep functions small and focused
614
+
615
+ ### Expected Outcome
616
+ - Improved code quality
617
+ - Better maintainability
618
+ - Clearer intent
619
+ `.trim()
620
+ }
621
+
622
+ /**
623
+ * Find related concepts
624
+ */
625
+ async findRelatedConcepts(caseItem) {
626
+ const related = await this.getRecommendations(caseItem.id, 3)
627
+ return related.map(r => `
628
+ - **${r.title}** (${(r.similarityScore * 100).toFixed(0)}% similar)
629
+ ${r.problem.substring(0, 100)}...
630
+ `).join('\n')
631
+ }
632
+
633
+ /**
634
+ * Format materials as Markdown
635
+ */
636
+ formatMaterialsAsMarkdown(materials) {
637
+ return `# Learning Materials: ${materials.caseId}
638
+
639
+ Generated: ${materials.generatedAt}
640
+
641
+ ${materials.sections.map(section => `
642
+ ## ${section.title}
643
+
644
+ ${section.content}
645
+ `).join('\n')}
646
+ `
647
+ }
648
+
649
+ /**
650
+ * Generate case ID
651
+ */
652
+ generateCaseId() {
653
+ return `KB-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
654
+ }
655
+
656
+ /**
657
+ * Get default solution for issue type
658
+ */
659
+ getDefaultSolution(issueType) {
660
+ const solutions = {
661
+ 'longFunction': 'Extract smaller functions with single responsibilities',
662
+ 'badVariableNames': 'Use descriptive names that explain purpose',
663
+ 'highComplexity': 'Simplify logic and reduce decision points',
664
+ 'duplicateCode': 'Extract to a shared function or constant',
665
+ 'magicNumbers': 'Replace with named constants',
666
+ 'nestedConditionals': 'Use early returns and polymorphism'
667
+ }
668
+ return solutions[issueType] || 'Review and improve code structure'
669
+ }
670
+
671
+ /**
672
+ * Extract tags from issue
673
+ */
674
+ extractTagsFromIssue(issue) {
675
+ const tags = [issue.type, issue.severity]
676
+ if (issue.category) tags.push(issue.category)
677
+ return tags
678
+ }
679
+
680
+ /**
681
+ * Get category from issue
682
+ */
683
+ getCategoryFromIssue(issue) {
684
+ return issue.category || 'general'
685
+ }
686
+
687
+ /**
688
+ * Get statistics
689
+ */
690
+ getStatistics() {
691
+ this.updateStatistics()
692
+ return this.statistics
693
+ }
694
+
695
+ /**
696
+ * Export knowledge base
697
+ */
698
+ async export(format = 'json') {
699
+ const exportData = {
700
+ cases: this.cases,
701
+ patterns: this.patterns,
702
+ statistics: this.getStatistics(),
703
+ exportedAt: new Date().toISOString()
704
+ }
705
+
706
+ if (format === 'json') {
707
+ return JSON.stringify(exportData, null, 2)
708
+ }
709
+
710
+ if (format === 'markdown') {
711
+ return this.exportAsMarkdown(exportData)
712
+ }
713
+
714
+ throw new Error(`Unsupported export format: ${format}`)
715
+ }
716
+
717
+ /**
718
+ * Export as Markdown
719
+ */
720
+ exportAsMarkdown(data) {
721
+ let markdown = `# Knowledge Base Export
722
+
723
+ Generated: ${data.exportedAt}
724
+ Total Cases: ${data.statistics.totalCases}
725
+ Weekly Cases: ${data.statistics.weeklyCases}
726
+
727
+ ## Cases
728
+
729
+ `
730
+
731
+ for (const caseItem of data.cases) {
732
+ markdown += `
733
+ ### ${caseItem.title}
734
+
735
+ **Category:** ${caseItem.category}
736
+ **Language:** ${caseItem.language}
737
+ **Difficulty:** ${caseItem.difficulty}
738
+ **Tags:** ${caseItem.tags.join(', ')}
739
+
740
+ #### Problem
741
+ ${caseItem.problem}
742
+
743
+ #### Solution
744
+ ${caseItem.solution}
745
+
746
+ #### Code Example
747
+ \`\`\`${caseItem.language}
748
+ ${caseItem.codeExample}
749
+ \`\`\`
750
+
751
+ ---
752
+
753
+ `
754
+ }
755
+
756
+ return markdown
757
+ }
758
+ }
759
+
760
+ module.exports = AIKnowledgeBase