bc-code-intelligence-mcp
Version:
BC Code Intelligence MCP Server - Complete Specialist Bundle with AI-driven expert consultation, seamless handoffs, and context-preserving workflows
818 lines • 39 kB
JavaScript
import { getDomainList } from '../types/bc-knowledge.js';
/**
* AL Code Analysis Service
*
* Analyzes AL code for performance issues, anti-patterns, and optimization
* opportunities. Dynamically loads patterns from the layered knowledge system.
*/
export class CodeAnalysisService {
knowledgeService;
patternCache = null;
cacheExpiry = 0;
CACHE_TTL = 5 * 60 * 1000; // 5 minutes
constructor(knowledgeService) {
this.knowledgeService = knowledgeService;
}
/**
* Load AL code patterns dynamically from knowledge base
*/
async loadPatterns() {
// Check cache first
if (this.patternCache && Date.now() < this.cacheExpiry) {
return this.patternCache;
}
try {
// Get all code-pattern topics from the knowledge base
const patternTopics = await this.knowledgeService.findTopicsByType('code-pattern');
const patterns = patternTopics.map(topic => {
const frontmatter = topic.frontmatter || {};
return {
name: frontmatter.name || topic.id,
pattern_type: frontmatter.pattern_type || 'unknown',
regex_patterns: this.parseRegexPatterns(frontmatter.regex_patterns),
description: frontmatter.description || topic.title,
related_topics: frontmatter.related_topics || [],
severity: frontmatter.severity,
category: frontmatter.category,
impact_level: frontmatter.impact_level,
detection_confidence: frontmatter.detection_confidence
};
});
// Update cache
this.patternCache = patterns;
this.cacheExpiry = Date.now() + this.CACHE_TTL;
return patterns;
}
catch (error) {
console.warn('Failed to load code patterns from knowledge base:', error);
return this.getFallbackPatterns();
}
}
/**
* Parse regex patterns from YAML (can be strings or array)
*/
parseRegexPatterns(patterns) {
if (!patterns)
return [];
const patternArray = Array.isArray(patterns) ? patterns : [patterns];
return patternArray.map(pattern => {
try {
return new RegExp(pattern, 'gis');
}
catch (error) {
console.warn(`Invalid regex pattern: ${pattern}`);
return new RegExp('(?!)', 'g'); // Never-matching regex
}
});
}
/**
* Fallback patterns if knowledge base is unavailable
*/
getFallbackPatterns() {
return [
// Performance Anti-Patterns
{
name: 'manual-summation-instead-of-sift',
pattern_type: 'bad',
regex_patterns: [
/repeat\s+[\s\S]*?\+=[\s\S]*?until.*\.Next\(\)/gis,
/while.*\.Next\(\)\s*=\s*0[\s\S]*?\+=/gis
],
description: 'Manual record summation detected - consider using SIFT CalcSums for better performance',
related_topics: ['sift-technology-fundamentals', 'query-performance-patterns', 'flowfield-optimization']
},
{
name: 'missing-setloadfields',
pattern_type: 'bad',
regex_patterns: [
/FindSet\(\)[\s\S]*?repeat[\s\S]*?(\w+\."[^"]*"\s*[,;].*){3,}/gis
],
description: 'Multiple field access without SetLoadFields - this loads unnecessary data',
related_topics: ['setloadfields-optimization', 'memory-optimization', 'performance-patterns']
},
{
name: 'individual-calcfields-calls',
pattern_type: 'bad',
regex_patterns: [
/CalcFields\([^)]*\)[\s\S]*?CalcFields\([^)]*\)/gis
],
description: 'Multiple individual CalcFields calls - consider batching for better performance',
related_topics: ['flowfield-optimization', 'batch-processing-optimization']
},
{
name: 'inefficient-deleteall',
pattern_type: 'bad',
regex_patterns: [
/repeat[\s\S]*?Delete\((?:true)?\);[\s\S]*?until.*\.Next\(\)/gis
],
description: 'Individual record deletion in loop - consider using DeleteAll for better performance',
related_topics: ['deleteall-patterns', 'batch-processing-optimization', 'performance-optimization']
},
// Performance Good Patterns
{
name: 'sift-calcsum-usage',
pattern_type: 'good',
regex_patterns: [
/CalcSums\s*\(/gi,
/SumIndexFields.*=.*MaintainSIFTIndex.*=.*true/gis
],
description: 'Good use of SIFT CalcSums for aggregation',
related_topics: ['sift-technology-fundamentals', 'performance-monitoring']
},
{
name: 'setloadfields-optimization',
pattern_type: 'good',
regex_patterns: [
/SetLoadFields\s*\([^)]+\)[\s\S]*?FindSet\s*\(/gis
],
description: 'Excellent use of SetLoadFields for memory optimization',
related_topics: ['memory-optimization', 'performance-best-practices']
},
{
name: 'proper-key-usage',
pattern_type: 'good',
regex_patterns: [
/SetCurrentKey\s*\([^)]+\)[\s\S]*?SetRange\s*\([^)]+\)/gis
],
description: 'Good practice: setting appropriate key before filtering',
related_topics: ['index-optimization', 'query-performance-patterns']
},
// Validation Patterns
{
name: 'testfield-validation',
pattern_type: 'good',
regex_patterns: [
/TestField\s*\(/gi
],
description: 'Good use of TestField for validation',
related_topics: ['testfield-patterns', 'validation-strategies', 'error-handling']
},
{
name: 'fielderror-usage',
pattern_type: 'unknown',
regex_patterns: [
/FieldError\s*\(/gi
],
description: 'FieldError usage detected - ensure proper error message construction',
related_topics: ['fielderror-patterns', 'error-message-construction', 'user-experience']
},
{
name: 'missing-validation',
pattern_type: 'bad',
regex_patterns: [
/Insert\s*\(\s*(?:true)?\s*\);[\s\S]*?(?!TestField|FieldError|if.*=.*'')/gis
],
description: 'Record insertion without visible validation - consider adding validation',
related_topics: ['validation-patterns', 'data-integrity', 'business-rules']
},
// Security Patterns
{
name: 'missing-permission-check',
pattern_type: 'bad',
regex_patterns: [
/User\.Get\s*\([^)]+\)[^;]*?(?!UserPermissions\.Get|Permission\.)/gis,
/Database\.SelectLatestVersion\s*\([^)]+\)(?![\s\S]*?Permission)/gis
],
description: 'User or database access without permission validation',
related_topics: ['user-permissions', 'security-fundamentals', 'access-control']
},
{
name: 'hardcoded-credentials',
pattern_type: 'bad',
regex_patterns: [
/password\s*:=\s*'[^']+'/gi,
/token\s*:=\s*'[A-Za-z0-9]{20,}'/gi,
/(apikey|secret|pwd)\s*:=\s*'[^']+'/gi
],
description: 'Hardcoded credentials detected - use secure configuration',
related_topics: ['credential-management', 'security-configuration', 'secrets-handling']
},
{
name: 'sql-injection-risk',
pattern_type: 'bad',
regex_patterns: [
/Database\.Execute\s*\([^)]*\+[^)]*\)/gis,
/SELECTSQL\s*\([^)]*\+[^)]*\)/gis
],
description: 'SQL concatenation detected - potential injection risk',
related_topics: ['sql-injection-prevention', 'parameterized-queries', 'data-safety']
},
{
name: 'secure-communication',
pattern_type: 'good',
regex_patterns: [
/HttpClient\..*https:\/\//gi,
/WebServiceConnection.*SSL.*=.*true/gis
],
description: 'Good practice: using secure HTTPS communication',
related_topics: ['secure-communications', 'api-security', 'encryption-patterns']
},
// Enhanced Validation Patterns
{
name: 'weak-field-validation',
pattern_type: 'bad',
regex_patterns: [
/if\s+.*\."[^"]*"\s*=\s*''\s+then/gis,
/if\s+.*\."[^"]*"\s*<>\s*''\s+then[\s\S]*?else[\s\S]*?Error/gis
],
description: 'Weak field validation - consider using TestField for better UX',
related_topics: ['validation-patterns', 'testfield-patterns', 'user-experience']
},
{
name: 'missing-range-validation',
pattern_type: 'bad',
regex_patterns: [
/(?:Quantity|Amount|Price|Rate)\s*:=\s*[^;]*;(?![\s\S]*?if.*>.*0)/gis
],
description: 'Numeric field assignment without range validation',
related_topics: ['numeric-validation', 'business-rules', 'data-integrity']
},
{
name: 'comprehensive-validation',
pattern_type: 'good',
regex_patterns: [
/TestField\s*\([^)]+\);[\s\S]*?if.*in.*\[.*\].*then/gis,
/ValidateFields\s*\(/gi
],
description: 'Comprehensive validation with TestField and range checks',
related_topics: ['validation-best-practices', 'data-integrity', 'business-rules']
},
// Error Handling Patterns
{
name: 'silent-error-handling',
pattern_type: 'bad',
regex_patterns: [
/begin[\s\S]*?end;[\s\S]*?if.*GetLastError.*<>.*''.*then/gis,
/ClearLastError\s*\(\s*\);/gi
],
description: 'Silent error handling - consider proper error propagation',
related_topics: ['error-handling-patterns', 'error-propagation', 'debugging-strategies']
},
{
name: 'missing-transaction-handling',
pattern_type: 'bad',
regex_patterns: [
/(Insert|Modify|Delete)\s*\([^)]*\);[\s\S]*?(Insert|Modify|Delete)\s*\([^)]*\);(?![\s\S]*?Commit)/gis
],
description: 'Multiple data operations without transaction handling',
related_topics: ['transaction-patterns', 'data-consistency', 'error-recovery']
},
{
name: 'proper-error-handling',
pattern_type: 'good',
regex_patterns: [
/if.*not.*Codeunit\.Run\s*\([^)]+\).*then[\s\S]*?Error\s*\(/gis,
/try[\s\S]*?catch[\s\S]*?Error\s*\(/gis
],
description: 'Good practice: proper error handling with user feedback',
related_topics: ['error-handling-best-practices', 'user-experience', 'debugging-strategies']
},
// Data Safety Patterns
{
name: 'unsafe-bulk-operations',
pattern_type: 'bad',
regex_patterns: [
/DeleteAll\s*\(\s*\);(?![\s\S]*?SetRange)/gis,
/ModifyAll\s*\([^)]*\)(?![\s\S]*?SetRange)/gis
],
description: 'Bulk operations without filters - potential data loss risk',
related_topics: ['data-safety-patterns', 'bulk-operations', 'data-protection']
},
{
name: 'missing-backup-validation',
pattern_type: 'bad',
regex_patterns: [
/Delete\s*\((?:true)?\);(?![\s\S]*?Confirm\s*\(|[\s\S]*?if.*Count.*>)/gis
],
description: 'Record deletion without user confirmation or validation',
related_topics: ['data-protection', 'user-confirmation', 'deletion-patterns']
},
{
name: 'safe-data-operations',
pattern_type: 'good',
regex_patterns: [
/if.*Confirm\s*\([^)]*\).*then[\s\S]*?Delete/gis,
/SetRange\s*\([^)]+\);[\s\S]*?if.*FindSet.*then[\s\S]*?DeleteAll/gis
],
description: 'Safe data operations with confirmation and filtering',
related_topics: ['data-safety-best-practices', 'user-confirmation', 'filtering-patterns']
},
// Code Quality Patterns
{
name: 'excessive-nesting',
pattern_type: 'bad',
regex_patterns: [
/if[\s\S]*?if[\s\S]*?if[\s\S]*?if[\s\S]*?begin/gis
],
description: 'Excessive nesting detected - consider refactoring for readability',
related_topics: ['code-complexity', 'refactoring-patterns', 'maintainability']
},
{
name: 'magic-numbers',
pattern_type: 'bad',
regex_patterns: [
/(?