mushcode-mcp-server
Version:
A specialized Model Context Protocol server for MUSHCODE development assistance. Provides AI-powered code generation, validation, optimization, and examples for MUD development.
268 lines • 10.4 kB
JavaScript
/**
* Pattern matching algorithms for code generation and validation
*/
// Base pattern matcher implementation
/**
* Pattern matching service for MUSHCODE knowledge base
*/
export class PatternMatcher {
knowledgeBase;
constructor(knowledgeBase) {
this.knowledgeBase = knowledgeBase;
}
/**
* Find patterns matching a natural language description
*/
findPatternsForGeneration(description, serverType, functionType, difficulty) {
const query = {
query: description,
...(serverType && { serverType }),
...(functionType && { category: functionType }),
...(difficulty && { difficulty }),
includePatterns: true,
includeExamples: false,
fuzzyMatch: true,
limit: 10
};
const results = this.knowledgeBase.search(query);
return results.patterns;
}
/**
* Find security rules that match code patterns
*/
findSecurityViolations(code, serverType) {
const violations = [];
const codeLines = code.split('\n');
for (const rule of this.knowledgeBase.securityRules.values()) {
// Skip rules that don't apply to this server type
if (serverType && rule.affectedServers.length > 0 &&
!rule.affectedServers.includes(serverType)) {
continue;
}
try {
const pattern = new RegExp(rule.pattern, 'gi');
// Check each line for pattern matches
for (let i = 0; i < codeLines.length; i++) {
const line = codeLines[i];
if (line && pattern.test(line)) {
violations.push(rule);
break; // Don't add the same rule multiple times
}
}
}
catch (error) {
// Invalid regex pattern, skip this rule
console.warn(`Invalid regex pattern in security rule ${rule.ruleId}: ${rule.pattern}`);
}
}
return violations.sort((a, b) => {
const severityOrder = { critical: 4, high: 3, medium: 2, low: 1 };
return severityOrder[b.severity] - severityOrder[a.severity];
});
}
/**
* Find patterns similar to existing code for optimization suggestions
*/
findOptimizationPatterns(code, serverType) {
const matches = [];
// Extract key terms from the code for pattern matching
const codeTerms = this.extractCodeTerms(code);
for (const pattern of this.knowledgeBase.patterns.values()) {
// Skip patterns not compatible with server type
if (serverType && !pattern.serverCompatibility.includes(serverType)) {
continue;
}
const relevance = this.calculateCodePatternRelevance(codeTerms, pattern);
if (relevance > 0.3) { // Threshold for relevance
matches.push({
patternId: pattern.id,
confidence: relevance,
relevance,
matchedTerms: this.getCodeMatchedTerms(codeTerms, pattern)
});
}
}
return matches.sort((a, b) => b.relevance - a.relevance).slice(0, 5);
}
/**
* Find examples that demonstrate similar functionality
*/
findSimilarExamples(code, serverType, limit = 5) {
const codeTerms = this.extractCodeTerms(code);
const matches = [];
for (const example of this.knowledgeBase.examples.values()) {
// Skip examples not compatible with server type
if (serverType && !example.serverCompatibility.includes(serverType)) {
continue;
}
const relevance = this.calculateExampleCodeRelevance(codeTerms, example);
if (relevance > 0.2) {
matches.push({ example, relevance });
}
}
return matches
.sort((a, b) => b.relevance - a.relevance)
.slice(0, limit)
.map(match => match.example);
}
/**
* Extract meaningful terms from MUSHCODE for pattern matching
*/
extractCodeTerms(code) {
const terms = [];
// Extract function names (words followed by parentheses)
const functionMatches = code.match(/\b\w+(?=\()/g);
if (functionMatches) {
terms.push(...functionMatches);
}
// Extract attribute references (&attribute)
const attributeMatches = code.match(/&\w+/g);
if (attributeMatches) {
terms.push(...attributeMatches.map(attr => attr.substring(1)));
}
// Extract variable references (%variable)
const variableMatches = code.match(/%\w+/g);
if (variableMatches) {
terms.push(...variableMatches.map(var_ => var_.substring(1)));
}
// Extract command patterns (@command)
const commandMatches = code.match(/@\w+/g);
if (commandMatches) {
terms.push(...commandMatches.map(cmd => cmd.substring(1)));
}
// Extract quoted strings (potential messages or descriptions)
const stringMatches = code.match(/"[^"]*"/g);
if (stringMatches) {
terms.push(...stringMatches.map(str => str.slice(1, -1)));
}
// Extract common MUSHCODE keywords
const keywords = ['if', 'then', 'else', 'switch', 'case', 'default', 'for', 'while', 'do'];
const codeWords = code.toLowerCase().split(/\W+/);
terms.push(...codeWords.filter(word => keywords.includes(word)));
return [...new Set(terms)]; // Remove duplicates
}
/**
* Calculate relevance between code terms and a pattern
*/
calculateCodePatternRelevance(codeTerms, pattern) {
const patternContent = `${pattern.name} ${pattern.description} ${pattern.codeTemplate} ${pattern.tags.join(' ')}`.toLowerCase();
let matches = 0;
for (const term of codeTerms) {
if (patternContent.includes(term.toLowerCase())) {
matches++;
}
}
return codeTerms.length > 0 ? matches / codeTerms.length : 0;
}
/**
* Calculate relevance between code terms and an example
*/
calculateExampleCodeRelevance(codeTerms, example) {
const exampleContent = `${example.title} ${example.description} ${example.code} ${example.tags.join(' ')}`.toLowerCase();
let matches = 0;
for (const term of codeTerms) {
if (exampleContent.includes(term.toLowerCase())) {
matches++;
}
}
return codeTerms.length > 0 ? matches / codeTerms.length : 0;
}
/**
* Get matched terms between code and pattern
*/
getCodeMatchedTerms(codeTerms, pattern) {
const patternContent = `${pattern.name} ${pattern.description} ${pattern.codeTemplate} ${pattern.tags.join(' ')}`.toLowerCase();
return codeTerms.filter(term => patternContent.includes(term.toLowerCase()));
}
/**
* Find patterns by exact name match
*/
findPatternByName(name) {
for (const pattern of this.knowledgeBase.patterns.values()) {
if (pattern.name.toLowerCase() === name.toLowerCase()) {
return pattern;
}
}
return undefined;
}
/**
* Find patterns by tag
*/
findPatternsByTag(tag) {
const matches = [];
for (const pattern of this.knowledgeBase.patterns.values()) {
if (pattern.tags.some(t => t.toLowerCase() === tag.toLowerCase())) {
matches.push(pattern);
}
}
return matches;
}
/**
* Find patterns that are related to a given pattern
*/
findRelatedPatterns(patternId) {
const pattern = this.knowledgeBase.getPattern(patternId);
if (!pattern) {
return [];
}
const related = [];
// Find patterns explicitly marked as related
for (const relatedId of pattern.relatedPatterns) {
const relatedPattern = this.knowledgeBase.getPattern(relatedId);
if (relatedPattern) {
related.push(relatedPattern);
}
}
// Find patterns with similar tags
const similarByTags = this.findPatternsBySimilarTags(pattern.tags, pattern.id);
related.push(...similarByTags.slice(0, 3)); // Limit to 3 additional
return [...new Set(related)]; // Remove duplicates
}
/**
* Find patterns with similar tags
*/
findPatternsBySimilarTags(tags, excludeId) {
const matches = [];
for (const pattern of this.knowledgeBase.patterns.values()) {
if (pattern.id === excludeId)
continue;
const commonTags = pattern.tags.filter(tag => tags.some(t => t.toLowerCase() === tag.toLowerCase())).length;
if (commonTags > 0) {
matches.push({ pattern, commonTags });
}
}
return matches
.sort((a, b) => b.commonTags - a.commonTags)
.map(match => match.pattern);
}
/**
* Validate pattern template syntax
*/
validatePatternTemplate(template) {
const errors = [];
// Check for balanced braces
const braceCount = (template.match(/{/g) || []).length - (template.match(/}/g) || []).length;
if (braceCount !== 0) {
errors.push('Unbalanced braces in template');
}
// Check for valid parameter placeholders
const parameterMatches = template.match(/\{\{(\w+)\}\}/g);
if (parameterMatches) {
for (const match of parameterMatches) {
const paramName = match.slice(2, -2);
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(paramName)) {
errors.push(`Invalid parameter name: ${paramName}`);
}
}
}
// Check for common MUSHCODE syntax issues
if (template.includes('@@')) {
errors.push('Double @ symbols detected - potential syntax error');
}
return {
valid: errors.length === 0,
errors
};
}
}
//# sourceMappingURL=matcher.js.map