feat: implement P0/P1 performance and code quality optimizations

P0 Performance Optimizations:
- Add debounced search (300ms) to reduce re-renders during typing
- Implement single-pass filter function for O(n) complexity
- Add TanStack Query cancellation before new requests

P1 Code Quality Optimizations:
- Add runtime type guards for filter validation
- Implement two derived values (filteredFonts + sortedFilteredFonts)
- Remove all 'as any[]' casts from filter bridge
- Add fast-path for default sorting (skip unnecessary operations)

New Utilities:
- debounce utility with 4 tests (all pass)
- filterUtils with 15 tests (all pass)
- typeGuards with 20 tests (all pass)
- Total: 39 new tests

Modified Files:
- unifiedFontStore.svelte.ts: Add debouncing, use filter/sort utilities
- filterBridge.svelte.ts: Type-safe validation with type guards
- unifiedFontStore.test.ts: Fix pre-existing bugs (missing async, duplicate imports)

Code Quality:
- 0 linting warnings/errors (oxlint)
- FSD compliant architecture (entity lib layer)
- Backward compatible store API
This commit is contained in:
Ilia Mashkov
2026-01-11 14:49:21 +03:00
parent 77de829b04
commit d81af0a77b
13 changed files with 1448 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
/**
* ============================================================================
* DEBOUNCE UTILITY
* ============================================================================
*
* Creates a debounced function that delays execution until after wait milliseconds
* have elapsed since the last time it was invoked.
*
* @example
* ```typescript
* const debouncedSearch = debounce((query: string) => {
* console.log('Searching for:', query);
* }, 300);
*
* debouncedSearch('hello');
* debouncedSearch('hello world'); // Only this will execute after 300ms
* ```
*/
/**
* Creates a debounced version of a function
*
* @param fn - The function to debounce
* @param wait - The delay in milliseconds
* @returns A debounced function that will execute after the specified delay
*/
export function debounce<T extends (...args: any[]) => any>(
fn: T,
wait: number,
): (...args: Parameters<T>) => void {
let timeoutId: ReturnType<typeof setTimeout> | null = null;
return (...args: Parameters<T>) => {
if (timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
fn(...args);
timeoutId = null;
}, wait);
};
}