UNPKG

rework-mcp-server

Version:

Rework MCP Server - Integrate rework tasks with AI through Model Context Protocol

107 lines (106 loc) 3.88 kB
/** * Check if a name matches another name using a variety of matching strategies * Returns a structured result with match quality information rather than just a boolean * * @param actualName The actual name to check * @param searchName The name being searched for * @returns A structured result with match details */ export function isNameMatch(actualName, searchName) { if (!actualName || !searchName) { return { isMatch: true, score: 100, exactMatch: false, reason: 'The name is empty' }; } // Remove any extra whitespace const normalizedActualName = actualName.trim(); const normalizedSearchName = searchName.trim(); // Handle empty names after normalization if (normalizedActualName === '') { return { isMatch: false, score: 0, exactMatch: false, reason: 'Actual name is empty' }; } if (normalizedSearchName === '') { return { isMatch: false, score: 0, exactMatch: false, reason: 'Search name is empty' }; } // 1. Exact match (highest quality) if (normalizedActualName === normalizedSearchName) { return { isMatch: true, score: 100, exactMatch: true, reason: 'Exact match' }; } // 2. Case-insensitive exact match (high quality) if (normalizedActualName.toLowerCase() === normalizedSearchName.toLowerCase()) { return { isMatch: true, score: 90, exactMatch: true, reason: 'Case-insensitive exact match' }; } // 3. Match after removing emojis (moderate quality) const actualNameWithoutEmoji = normalizedActualName.replace(/[\p{Emoji}\u{FE00}-\u{FE0F}\u200d]+/gu, '').trim(); const searchNameWithoutEmoji = normalizedSearchName.replace(/[\p{Emoji}\u{FE00}-\u{FE0F}\u200d]+/gu, '').trim(); if (actualNameWithoutEmoji === searchNameWithoutEmoji) { return { isMatch: true, score: 80, exactMatch: false, reason: 'Exact match after removing emojis' }; } if (actualNameWithoutEmoji.toLowerCase() === searchNameWithoutEmoji.toLowerCase()) { return { isMatch: true, score: 70, exactMatch: false, reason: 'Case-insensitive match after removing emojis' }; } // 4. Substring matches (lower quality) const lowerActual = normalizedActualName.toLowerCase(); const lowerSearch = normalizedSearchName.toLowerCase(); // Full substring (term completely contained) if (lowerActual.includes(lowerSearch)) { return { isMatch: true, score: 60, exactMatch: false, reason: 'Search term found as substring in actual name' }; } if (lowerSearch.includes(lowerActual)) { return { isMatch: true, score: 50, exactMatch: false, reason: 'Actual name found as substring in search term' }; } // 5. Fuzzy emoji-less matches (lowest quality) const lowerActualNoEmoji = actualNameWithoutEmoji.toLowerCase(); const lowerSearchNoEmoji = searchNameWithoutEmoji.toLowerCase(); if (lowerActualNoEmoji.includes(lowerSearchNoEmoji)) { return { isMatch: true, score: 40, exactMatch: false, reason: 'Search term (without emoji) found as substring in actual name' }; } if (lowerSearchNoEmoji.includes(lowerActualNoEmoji)) { return { isMatch: true, score: 30, exactMatch: false, reason: 'Actual name (without emoji) found as substring in search term' }; } // No match found return { isMatch: false, score: 0, exactMatch: false, reason: 'No match found with any matching strategy' }; }