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,115 @@
import {
filterValidValues,
isValidFontCategory,
isValidFontProvider,
isValidFontSubset,
} from '$entities/Font/lib/typeGuards';
import type { UnifiedFontStore } from '$entities/Font/model/store';
import { filterManager } from '$features/FilterFonts';
import type { Property } from '$shared/lib';
/**
* ============================================================================
* FILTER BRIDGE
* ============================================================================
*
* Bridges the UI filter state (filterManager from FilterFonts feature) with the
* unified font store (unifiedFontStore from Font entity).
*
* OPTIMIZATIONS (P1):
* - Runtime type validation using type guards
* - No more 'as any[]' casts - type-safe assignments
*/
// ... (comments)
// ============================================================================
// FILTER GROUP MAPPING
// ============================================================================
/**
* Get selected values from a filter manager group by ID
*/
function getSelectedFilterValues(groupId: string): string[] {
const group = filterManager.getGroup(groupId);
if (!group) return [];
return group.instance.selectedProperties.map((property: Property<string>) => property.value);
}
// ============================================================================
// SYNC LOGIC
// ============================================================================
/**
* Sync filter manager state to unified font store
*
* @param store - The unified font store instance
*/
export function syncFilters(store: UnifiedFontStore): void {
const providers = getSelectedFilterValues('providers');
const categories = getSelectedFilterValues('categories');
const subsets = getSelectedFilterValues('subsets');
// Validate and filter providers
const validProviders = filterValidValues(providers, isValidFontProvider);
// Validate and filter categories
const validCategories = filterValidValues(categories, isValidFontCategory);
// Validate and filter subsets
const validSubsets = filterValidValues(subsets, isValidFontSubset);
// Update unified store filters with validated, type-safe values
store.filters = {
providers: validProviders,
categories: validCategories,
subsets: validSubsets,
searchQuery: store.filters.searchQuery,
};
}
// ============================================================================
// PUBLIC API
// ============================================================================
/**
* Apply current filters and fetch fonts from providers
*
* @param store - The unified font store instance
*/
export async function applyFilters(store: UnifiedFontStore): Promise<void> {
await store.fetchFonts();
}
/**
* Reset all filters to their default state
*
* @param store - The unified font store instance
*/
export function resetFilters(store: UnifiedFontStore): void {
// Reset filter manager selections
filterManager.deselectAllGlobal();
// Clear unified store filters
store.clearFilters();
}
/**
* Apply current filter selections and fetch fonts
*
* @param store - The unified font store instance
*/
export async function applyFilterType(store: UnifiedFontStore): Promise<void> {
syncFilters(store);
await store.fetchFonts();
}
// ============================================================================
// RE-EXPORTS FOR CONVENIENCE
// ============================================================================
/**
* Re-export filter manager for direct access
*/
export { filterManager } from '$features/FilterFonts';