import * as plugins from './smartfuzzy.plugins.js'; export let standardExport = 'Hi there! :) This is an exported string'; /** * Type representing a dictionary of words mapped to their scores * Lower scores typically indicate better matches */ export type TDictionaryMap = { [key: string]: number }; /** * Main class for fuzzy string matching against a dictionary * * @example * ```typescript * const fuzzy = new Smartfuzzy(['apple', 'banana', 'orange']); * const result = fuzzy.findClosestMatch('aple'); // Returns 'apple' * ``` */ export class Smartfuzzy { /** * Array of words used for fuzzy matching */ public dictionary: string[]; /** * Creates a new Smartfuzzy instance * * @param dictionary - Initial array of words to use for matching */ constructor(dictionary: string[]) { if (!Array.isArray(dictionary)) { throw new Error('Dictionary must be an array of strings'); } this.dictionary = dictionary; } /** * Adds one or more words to the dictionary * * @param payloadArg - A single word or an array of words to add to the dictionary * @returns void * * @example * ```typescript * fuzzy.addToDictionary('pear'); * fuzzy.addToDictionary(['pear', 'grape', 'kiwi']); * ``` */ public addToDictionary(payloadArg: string | string[]): void { if (payloadArg === undefined || payloadArg === null) { throw new Error('Input cannot be null or undefined'); } if (Array.isArray(payloadArg)) { // Validate all items in array are strings for (const item of payloadArg) { if (typeof item !== 'string') { throw new Error('All items in array must be strings'); } } this.dictionary = this.dictionary.concat(payloadArg); } else if (typeof payloadArg === 'string') { this.dictionary.push(payloadArg); } else { throw new Error('Input must be a string or an array of strings'); } } /** * Calculates the Levenshtein distance (edit distance) between the input string * and each word in the dictionary * * @param stringArg - The string to compare against the dictionary * @returns A dictionary map where keys are words and values are edit distances * * @example * ```typescript * const scores = fuzzy.calculateScores('aple'); * // Returns: { 'apple': 1, 'banana': 5, 'orange': 5 } * ``` */ public calculateScores(stringArg: string): TDictionaryMap { if (typeof stringArg !== 'string') { throw new Error('Input must be a string'); } if (this.dictionary.length === 0) { throw new Error('Dictionary is empty'); } const dictionaryMap: TDictionaryMap = {}; for (const wordArg of this.dictionary) { dictionaryMap[wordArg] = plugins.leven(stringArg, wordArg); } return dictionaryMap; } /** * @deprecated Use calculateScores instead */ public getChangeScoreForString(stringArg: string): TDictionaryMap { return this.calculateScores(stringArg); } /** * Finds the closest matching word in the dictionary using fuzzy search * * @param stringArg - The string to find a match for * @returns The closest matching word, or null if no match is found or dictionary is empty * * @example * ```typescript * const match = fuzzy.findClosestMatch('oragne'); * // Returns: 'orange' * ``` */ public findClosestMatch(stringArg: string): string { if (typeof stringArg !== 'string') { throw new Error('Input must be a string'); } if (this.dictionary.length === 0) { return null; // Return null for empty dictionary instead of throwing error } const fuseDictionary: { name: string }[] = []; for (const wordArg of this.dictionary) { fuseDictionary.push({ name: wordArg, }); } const fuseOptions = { shouldSort: true, threshold: 0.6, location: 0, distance: 100, maxPatternLength: 32, minMatchCharLength: 1, keys: ['name'], }; const fuse = new plugins.fuseJs(fuseDictionary, fuseOptions); const fuzzyResult = fuse.search(stringArg); let closestMatch: string = null; if (fuzzyResult.length > 0) { closestMatch = fuzzyResult[0].item.name; } return closestMatch; } /** * @deprecated Use findClosestMatch instead */ public getClosestMatchForString(stringArg: string): string { return this.findClosestMatch(stringArg); } }