114 lines
3.1 KiB
TypeScript
114 lines
3.1 KiB
TypeScript
import * as plugins from './smartfuzzy.plugins.js';
|
|
|
|
/**
|
|
* Result of a fuzzy search on objects
|
|
*
|
|
* @typeParam T - The type of object being searched
|
|
*/
|
|
export interface IFuzzySearchResult<T> {
|
|
/** The matched object */
|
|
item: T;
|
|
|
|
/** The index of the object in the original array */
|
|
refIndex: number;
|
|
|
|
/** The match score (lower is better) */
|
|
score?: number;
|
|
}
|
|
|
|
/**
|
|
* Handles fuzzy searching and sorting of objects based on their properties
|
|
*
|
|
* @typeParam T - The type of objects to search through
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* interface User {
|
|
* name: string;
|
|
* email: string;
|
|
* }
|
|
*
|
|
* const users = [
|
|
* { name: 'John Smith', email: 'john@example.com' },
|
|
* { name: 'Jane Doe', email: 'jane@example.com' }
|
|
* ];
|
|
*
|
|
* const sorter = new ObjectSorter<User>(users);
|
|
* const results = sorter.sort('john', ['name', 'email']);
|
|
* ```
|
|
*/
|
|
export class ObjectSorter<T> {
|
|
/**
|
|
* The collection of objects to search through
|
|
*/
|
|
public objectDictionary: T[];
|
|
|
|
/**
|
|
* Creates a new ObjectSorter instance
|
|
*
|
|
* @param objectDictionaryArg - Array of objects to search through
|
|
*/
|
|
constructor(objectDictionaryArg: T[] = []) {
|
|
if (objectDictionaryArg !== undefined && !Array.isArray(objectDictionaryArg)) {
|
|
throw new Error('Object dictionary must be an array');
|
|
}
|
|
this.objectDictionary = objectDictionaryArg;
|
|
}
|
|
|
|
/**
|
|
* Searches and sorts objects based on how well they match the search string
|
|
* in the specified object properties
|
|
*
|
|
* @param stringArg - The search query string
|
|
* @param objectKeysArg - Array of object property names to search within
|
|
* @returns Array of results sorted by relevance (best matches first)
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* // Search for 'john' in both name and email fields
|
|
* const results = sorter.sort('john', ['name', 'email']);
|
|
*
|
|
* // First result is the best match
|
|
* console.log(results[0].item.name); // 'John Smith'
|
|
* ```
|
|
*/
|
|
public sort(stringArg: string, objectKeysArg: string[]): Array<IFuzzySearchResult<T>> {
|
|
if (typeof stringArg !== 'string') {
|
|
throw new Error('Search string must be a string');
|
|
}
|
|
|
|
if (!Array.isArray(objectKeysArg)) {
|
|
throw new Error('Object keys must be an array');
|
|
}
|
|
|
|
if (objectKeysArg.length === 0) {
|
|
throw new Error('At least one object key must be provided for searching');
|
|
}
|
|
|
|
// Verify all keys are strings
|
|
for (const key of objectKeysArg) {
|
|
if (typeof key !== 'string') {
|
|
throw new Error('All object keys must be strings');
|
|
}
|
|
}
|
|
|
|
// Empty dictionary should return empty results instead of error
|
|
if (this.objectDictionary.length === 0) {
|
|
return [];
|
|
}
|
|
|
|
const fuseOptions = {
|
|
shouldSort: true,
|
|
threshold: 0.6, // Lower values = more strict matching
|
|
location: 0, // Where to start searching in the string
|
|
distance: 100, // How far to search in the string
|
|
maxPatternLength: 32,
|
|
minMatchCharLength: 1,
|
|
keys: objectKeysArg,
|
|
};
|
|
const fuse = new plugins.fuseJs<T>(this.objectDictionary, fuseOptions);
|
|
const result = fuse.search(stringArg);
|
|
return result;
|
|
}
|
|
}
|