From 78896ff70f0e3aadf10f79aab2e34d310265b368 Mon Sep 17 00:00:00 2001
From: Miguelangel Cabrera
Date: Sat, 21 Mar 2026 19:34:10 -0300
Subject: [PATCH 1/4] refactor: remove Svelte integration and related
documentation
- Removed Svelte integration from the codebase, including all related files and tests.
- Updated documentation to reflect the removal of Svelte support, including changelog, cheatsheet, and contributing guidelines.
- Adjusted framework integration details to focus on React, Vue, Angular, SolidJS, and Preact.
- Cleaned up package.json and index.ts to eliminate references to Svelte.
---
.size-limit.json | 6 -
CLAUDE.md | 4 +-
__test__/modular-imports.test.ts | 10 -
docs/.vitepress/config.ts | 2 -
docs/CLAUDE.md | 2 +-
docs/README.md | 2 +-
docs/advanced/architecture.md | 58 +-
docs/advanced/bundle-size.md | 5 -
docs/advanced/type-system.md | 55 --
docs/api/reference.md | 13 -
docs/api/types.md | 160 -----
docs/frameworks/angular.md | 1 -
docs/frameworks/index.md | 281 +--------
docs/frameworks/react.md | 1 -
docs/frameworks/svelte.md | 295 ---------
docs/frameworks/sveltekit.md | 596 ------------------
docs/frameworks/vue.md | 1 -
docs/guide/best-practices.md | 40 --
docs/guide/comparison.md | 8 +-
docs/guide/faq.md | 20 +-
docs/guide/installation.md | 18 +-
docs/guide/migration-v2.md | 86 +--
docs/guide/modular-imports.md | 20 -
docs/guide/quick-start.md | 2 +-
docs/guide/troubleshooting.md | 33 -
docs/implementation/operators.md | 4 +-
docs/index.md | 15 +-
docs/project/changelog.md | 12 +-
docs/project/cheatsheet.md | 9 -
docs/project/contributing.md | 3 -
docs/project/roadmap.md | 41 +-
package.json | 12 -
src/index.ts | 15 -
src/integrations/svelte/index.ts | 12 -
src/integrations/svelte/svelte.constants.ts | 3 -
src/integrations/svelte/svelte.types.ts | 37 --
src/integrations/svelte/svelte.utils.ts | 21 -
.../svelte/use-debounced-filter.test.ts | 145 -----
.../svelte/use-debounced-filter.ts | 56 --
src/integrations/svelte/use-filter.test.ts | 107 ----
src/integrations/svelte/use-filter.ts | 35 -
.../svelte/use-filtered-state.test.ts | 116 ----
src/integrations/svelte/use-filtered-state.ts | 36 --
.../svelte/use-paginated-filter.test.ts | 195 ------
.../svelte/use-paginated-filter.ts | 103 ---
45 files changed, 30 insertions(+), 2666 deletions(-)
delete mode 100644 docs/frameworks/svelte.md
delete mode 100644 docs/frameworks/sveltekit.md
delete mode 100644 src/integrations/svelte/index.ts
delete mode 100644 src/integrations/svelte/svelte.constants.ts
delete mode 100644 src/integrations/svelte/svelte.types.ts
delete mode 100644 src/integrations/svelte/svelte.utils.ts
delete mode 100644 src/integrations/svelte/use-debounced-filter.test.ts
delete mode 100644 src/integrations/svelte/use-debounced-filter.ts
delete mode 100644 src/integrations/svelte/use-filter.test.ts
delete mode 100644 src/integrations/svelte/use-filter.ts
delete mode 100644 src/integrations/svelte/use-filtered-state.test.ts
delete mode 100644 src/integrations/svelte/use-filtered-state.ts
delete mode 100644 src/integrations/svelte/use-paginated-filter.test.ts
delete mode 100644 src/integrations/svelte/use-paginated-filter.ts
diff --git a/.size-limit.json b/.size-limit.json
index b592fe2..6678f41 100644
--- a/.size-limit.json
+++ b/.size-limit.json
@@ -65,12 +65,6 @@
"limit": "10 KB",
"gzip": true
},
- {
- "name": "Svelte integration",
- "path": "build/integrations/svelte/index.js",
- "limit": "10 KB",
- "gzip": true
- },
{
"name": "Angular integration",
"path": "build/integrations/angular/index.js",
diff --git a/CLAUDE.md b/CLAUDE.md
index 267e2d7..039f41b 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Project Overview
-**@mcabreradev/filter** is a TypeScript-first filtering engine for arrays with SQL-like wildcards, MongoDB-style operators, lazy evaluation, memoization, and framework integrations (React, Vue, Svelte, Angular, Preact, SolidJS). It provides 18+ operators for advanced filtering with zero dependencies (except Zod for validation).
+**@mcabreradev/filter** is a TypeScript-first filtering engine for arrays with SQL-like wildcards, MongoDB-style operators, lazy evaluation, memoization, and framework integrations (React, Vue, Angular, Preact, SolidJS). It provides 18+ operators for advanced filtering with zero dependencies (except Zod for validation).
## Development Commands
@@ -132,7 +132,6 @@ pnpm run docs:api
- **`src/integrations/`** - Framework integrations (all optional peer deps)
- `react/` - React hooks (useFilter, useDebouncedFilter, useFilteredState, usePaginatedFilter)
- `vue/` - Vue composables with reactivity
- - `svelte/` - Svelte stores
- `angular/` - Angular integration
- `preact/` - Preact hooks
- `solidjs/` - SolidJS integration
@@ -213,7 +212,6 @@ To add new operators:
Framework-specific code lives in `src/integrations//`:
- React uses hooks pattern
- Vue uses Composition API
-- Svelte uses stores
- Angular, Preact, SolidJS also supported
- Shared utilities in `src/integrations/shared/`
- All optional peer dependencies
diff --git a/__test__/modular-imports.test.ts b/__test__/modular-imports.test.ts
index ac52d8a..0bfc3bf 100644
--- a/__test__/modular-imports.test.ts
+++ b/__test__/modular-imports.test.ts
@@ -20,15 +20,6 @@ describe('Modular Imports', () => {
expect(vueModule.usePaginatedFilter).toBeDefined();
});
- it('should import Svelte stores from svelte path', async () => {
- const svelteModule = await import('../src/integrations/svelte/index.js');
-
- expect(svelteModule.useFilter).toBeDefined();
- expect(svelteModule.useFilteredState).toBeDefined();
- expect(svelteModule.useDebouncedFilter).toBeDefined();
- expect(svelteModule.usePaginatedFilter).toBeDefined();
- });
-
it('should import React hooks from main index', async () => {
const mainModule = await import('../src/index.js');
@@ -43,7 +34,6 @@ describe('Modular Imports', () => {
expect(mainModule.useFilterReact).toBeDefined();
expect(mainModule.useFilterVue).toBeDefined();
- expect(mainModule.useFilterSvelte).toBeDefined();
});
});
diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts
index 029c2fd..b3560c4 100644
--- a/docs/.vitepress/config.ts
+++ b/docs/.vitepress/config.ts
@@ -118,7 +118,6 @@ export default defineConfig({
{ text: 'Overview', link: '/frameworks/' },
{ text: 'React', link: '/frameworks/react' },
{ text: 'Vue', link: '/frameworks/vue' },
- { text: 'Svelte', link: '/frameworks/svelte' },
{ text: 'Angular', link: '/frameworks/angular' },
{ text: 'SolidJS', link: '/frameworks/solidjs' },
{ text: 'Preact', link: '/frameworks/preact' },
@@ -130,7 +129,6 @@ export default defineConfig({
items: [
{ text: 'Next.js', link: '/frameworks/nextjs' },
{ text: 'Nuxt', link: '/frameworks/nuxt' },
- { text: 'SvelteKit', link: '/frameworks/sveltekit' },
],
},
{
diff --git a/docs/CLAUDE.md b/docs/CLAUDE.md
index e8c15a4..a98d4b7 100644
--- a/docs/CLAUDE.md
+++ b/docs/CLAUDE.md
@@ -37,7 +37,7 @@ docs/
│ └── theme/ # Custom theme (index.ts, style.css, components/)
├── guide/ # Getting started, core features, configuration
├── operators/ # Operator reference pages
-├── frameworks/ # React, Vue, Svelte, Angular, SolidJS, Preact, Next.js, Nuxt, etc.
+├── frameworks/ # React, Vue, Angular, SolidJS, Preact, Next.js, Nuxt, etc.
├── api/ # API reference (reference.md, operators.md, types.md)
├── advanced/ # Architecture, type system, performance, migration
├── implementation/ # Deep-dive implementation details
diff --git a/docs/README.md b/docs/README.md
index 7a057aa..0476882 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -42,7 +42,7 @@ pnpm run docs:api
- `.vitepress/` - VitePress configuration and theme
- `guide/` - Getting started and core feature guides
-- `frameworks/` - Framework integration guides (React, Vue, Svelte)
+- `frameworks/` - Framework integration guides (React, Vue)
- `examples/` - Code examples and use cases
- `api/` - API reference documentation
- `public/` - Static assets (images, logos, etc.)
diff --git a/docs/advanced/architecture.md b/docs/advanced/architecture.md
index eb49988..2e393f6 100644
--- a/docs/advanced/architecture.md
+++ b/docs/advanced/architecture.md
@@ -4,7 +4,7 @@ Deep dive into the architecture of @mcabreradev/filter.
## Overview
-@mcabreradev/filter is built with a modular architecture that separates concerns and enables tree-shaking for optimal bundle sizes. The library has evolved through multiple versions, with v5.8.2 featuring MongoDB-style operators, framework integrations (React, Vue, Svelte, Angular, SolidJS, Preact), lazy evaluation, memoization, geospatial operators, datetime operators, and visual debugging.
+@mcabreradev/filter is built with a modular architecture that separates concerns and enables tree-shaking for optimal bundle sizes. The library has evolved through multiple versions, with v5.8.2 featuring MongoDB-style operators, framework integrations (React, Vue, Angular, SolidJS, Preact), lazy evaluation, memoization, geospatial operators, datetime operators, and visual debugging.
## Data Flow
@@ -84,7 +84,6 @@ src/
└── integrations/ # Framework integrations (v5.3.0+)
├── react/ # useFilter, useFilteredState, useDebouncedFilter, usePaginatedFilter
├── vue/ # Same 4 composables with Composition API
- ├── svelte/ # Same 4 patterns with Svelte stores
├── angular/ # Angular integration (v5.7.0+)
├── preact/ # Preact hooks (v5.7.0+)
├── solidjs/ # SolidJS integration (v5.7.0+)
@@ -863,54 +862,6 @@ export function useFilter(
}
```
-### Svelte Integration
-
-Uses Svelte stores for reactive state management.
-
-```typescript
-export function useFilter(
- data: Writable | Readable,
- expression: MaybeStore>,
- options?: FilterOptions,
-): UseFilterResult {
- const expressionStore = toStore(expression);
-
- const filtered = derived(
- [data, expressionStore],
- ([$data, $expression]) => {
- if (!$data || $data.length === 0) {
- return [];
- }
-
- try {
- return filter($data, $expression, options);
- } catch {
- return [];
- }
- }
- );
-
- const isFiltering = derived(
- [data, filtered],
- ([$data, $filtered]) => {
- return $filtered.length !== $data.length;
- }
- );
-
- return {
- filtered,
- isFiltering,
- };
-}
-
-function toStore(value: MaybeStore): Readable {
- if (isStore(value)) {
- return value;
- }
- return readable(value);
-}
-```
-
## Type System
### Generic Type Constraints with Operator Autocomplete
@@ -1347,7 +1298,6 @@ export { filterDebug } from './debug/debug-filter';
// Framework integrations in separate entry points
export { useFilter, useDebouncedFilter } from './integrations/react';
export { useFilter as useFilterVue } from './integrations/vue';
-export { useFilter as useFilterSvelte } from './integrations/svelte';
```
### Code Splitting Configuration
@@ -1368,10 +1318,6 @@ export { useFilter as useFilterSvelte } from './integrations/svelte';
"import": "./dist/integrations/vue/index.js",
"types": "./dist/integrations/vue/index.d.ts"
},
- "./svelte": {
- "import": "./dist/integrations/svelte/index.js",
- "types": "./dist/integrations/svelte/index.d.ts"
- }
}
}
```
@@ -1518,7 +1464,7 @@ describe('performance', () => {
- **v5.1.0**: Lazy evaluation with generators
- **v5.2.0**: Multi-layer memoization, logical operators
- **v5.3.0**: Initial framework integrations
-- **v5.4.0**: Full React, Vue, Svelte support
+- **v5.4.0**: Full React, Vue support
- **v5.5.0**: Array OR syntax, visual debugging, playground
- **v5.6.0**: Geospatial operators, datetime operators
- **v5.7.0**: Angular, SolidJS, Preact integrations
diff --git a/docs/advanced/bundle-size.md b/docs/advanced/bundle-size.md
index 3cca90e..3ae1b84 100644
--- a/docs/advanced/bundle-size.md
+++ b/docs/advanced/bundle-size.md
@@ -19,7 +19,6 @@ For detailed import syntax and examples, see the [Modular Imports Guide](/guide/
| Operators (granular) | ~5 KB | 58% | Specific operators |
| React integration | ~3 KB | 75% | React hooks only |
| Vue integration | ~3 KB | 75% | Vue composables only |
-| Svelte integration | ~3 KB | 75% | Svelte stores only |
| Lazy evaluation | ~2 KB | 83% | Large dataset processing |
## Import Strategies
@@ -106,10 +105,6 @@ import { useFilter, useDebouncedFilter } from '@mcabreradev/filter/react';
// Vue
import { useFilter } from '@mcabreradev/filter/vue';
// Bundle: ~3 KB (gzipped) - 70% reduction
-
-// Svelte
-import { filterStore } from '@mcabreradev/filter/svelte';
-// Bundle: ~3 KB (gzipped) - 70% reduction
```
**Use when:**
diff --git a/docs/advanced/type-system.md b/docs/advanced/type-system.md
index eff5070..5208e0b 100644
--- a/docs/advanced/type-system.md
+++ b/docs/advanced/type-system.md
@@ -699,61 +699,6 @@ const { filtered: searchResults, isPending } = useDebouncedFilter(
);
```
-### Svelte Types
-
-```typescript
-import type { Readable, Writable } from 'svelte/store';
-
-type MaybeStore = T | Readable | Writable;
-
-interface UseFilterResult {
- filtered: Readable;
- isFiltering: Readable;
-}
-
-interface UseFilteredStateResult {
- data: Writable;
- expression: Writable>;
- filtered: Readable;
- isFiltering: Readable;
-}
-
-interface UseDebouncedFilterResult {
- filtered: Readable;
- isFiltering: Readable;
- isPending: Readable;
-}
-
-interface UsePaginatedFilterResult {
- filtered: Readable;
- isFiltering: Readable;
- currentPage: Writable;
- totalPages: Readable;
- pageSize: Writable;
- totalItems: Readable;
- hasNextPage: Readable;
- hasPreviousPage: Readable;
- nextPage: () => void;
- previousPage: () => void;
- goToPage: (page: number) => void;
- setPageSize: (size: number) => void;
-}
-```
-
-**Example**:
-```typescript
-import { writable } from 'svelte/store';
-import { useFilter } from '@mcabreradev/filter/svelte';
-
-const users = writable([...]);
-const searchTerm = writable('');
-
-const { filtered, isFiltering } = useFilter(
- users,
- { name: { $contains: searchTerm } }
-);
-```
-
## Type Guards
### Expression Type Guard
diff --git a/docs/api/reference.md b/docs/api/reference.md
index 2de049b..ed4b82e 100644
--- a/docs/api/reference.md
+++ b/docs/api/reference.md
@@ -858,19 +858,6 @@ function useFilter(
}
```
-### Svelte Stores
-
-```typescript
-function useFilter(
- data: T[] | Readable,
- expression: Expression | Readable>,
- options?: FilterOptions
-): {
- filtered: Readable;
- isFiltering: Readable;
-}
-```
-
## Validation
### validateExpression
diff --git a/docs/api/types.md b/docs/api/types.md
index 6145980..ed598b9 100644
--- a/docs/api/types.md
+++ b/docs/api/types.md
@@ -633,96 +633,6 @@ const {
}: UsePaginatedFilterResult = usePaginatedFilter(products, expression);
```
-## Svelte Types
-
-### UseFilterResult (Svelte)
-
-Return type for Svelte `useFilter` store.
-
-```typescript
-interface UseFilterResult {
- filtered: Readable;
- isFiltering: Readable;
-}
-```
-
-**Usage**:
-```typescript
-import type { Readable } from 'svelte/store';
-
-const { filtered, isFiltering }: {
- filtered: Readable;
- isFiltering: Readable;
-} = useFilter(users, expression);
-```
-
-### UseFilteredStateResult (Svelte)
-
-Return type for Svelte `useFilteredState` store.
-
-```typescript
-interface UseFilteredStateResult {
- data: Writable;
- expression: Writable>;
- filtered: Readable;
- isFiltering: Readable;
-}
-```
-
-**Usage**:
-```typescript
-import type { Readable, Writable } from 'svelte/store';
-
-const {
- data,
- expression,
- filtered,
- isFiltering
-}: UseFilteredStateResult = useFilteredState(initialProducts);
-```
-
-### UseDebouncedFilterResult (Svelte)
-
-Return type for Svelte `useDebouncedFilter` store.
-
-```typescript
-interface UseDebouncedFilterResult {
- filtered: Readable;
- isFiltering: Readable;
- isPending: Readable;
-}
-```
-
-**Usage**:
-```typescript
-const {
- filtered,
- isFiltering,
- isPending
-}: UseDebouncedFilterResult = useDebouncedFilter(users, expression);
-```
-
-### UsePaginatedFilterResult (Svelte)
-
-Return type for Svelte `usePaginatedFilter` store.
-
-```typescript
-interface UsePaginatedFilterResult {
- filtered: Readable;
- isFiltering: Readable;
- currentPage: Writable;
- totalPages: Readable;
- pageSize: Writable;
- totalItems: Readable;
- hasNextPage: Readable;
- hasPreviousPage: Readable;
- nextPage: () => void;
- previousPage: () => void;
- goToPage: (page: number) => void;
- setPageSize: (size: number) => void;
-}
-```
-
## Angular Types
### FilterService``
@@ -1625,75 +1535,6 @@ interface UsePaginatedFilterResult {
}
```
-## Svelte Types
-
-### UseFilterResult (Svelte)
-
-Return type for Svelte `useFilter` store.
-
-```typescript
-interface UseFilterResult {
- filtered: Readable;
- isFiltering: Readable;
-}
-```
-
-**Usage**:
-```typescript
-import type { Readable } from 'svelte/store';
-
-const { filtered, isFiltering }: {
- filtered: Readable;
- isFiltering: Readable;
-} = useFilter(users, expression);
-```
-
-### UseFilteredStateResult (Svelte)
-
-Return type for Svelte `useFilteredState` store.
-
-```typescript
-interface UseFilteredStateResult {
- data: Writable;
- expression: Writable>;
- filtered: Readable;
- isFiltering: Readable;
-}
-```
-
-### UseDebouncedFilterResult (Svelte)
-
-Return type for Svelte `useDebouncedFilter` store.
-
-```typescript
-interface UseDebouncedFilterResult {
- filtered: Readable;
- isFiltering: Readable;
- isPending: Readable;
-}
-```
-
-### UsePaginatedFilterResult (Svelte)
-
-Return type for Svelte `usePaginatedFilter` store.
-
-```typescript
-interface UsePaginatedFilterResult {
- filtered: Readable;
- isFiltering: Readable;
- currentPage: Writable;
- totalPages: Readable;
- pageSize: Writable;
- totalItems: Readable;
- hasNextPage: Readable;
- hasPreviousPage: Readable;
- nextPage: () => void;
- previousPage: () => void;
- goToPage: (page: number) => void;
- setPageSize: (size: number) => void;
-}
-```
-
## Utility Types
### Operator
@@ -1895,5 +1736,4 @@ const activeUsers = activeUserFilter(users);
- [Basic Filtering](/guide/basic-filtering)
- [React Integration](/frameworks/react)
- [Vue Integration](/frameworks/vue)
-- [Svelte Integration](/frameworks/svelte)
diff --git a/docs/frameworks/angular.md b/docs/frameworks/angular.md
index 7a6c2c9..588cc15 100644
--- a/docs/frameworks/angular.md
+++ b/docs/frameworks/angular.md
@@ -1438,6 +1438,5 @@ filterService.setOptions({ enableCache: true });
- [React Integration](./react.md)
- [Vue Integration](./vue.md)
-- [Svelte Integration](./svelte.md)
- [API Reference](../api/reference.md)
diff --git a/docs/frameworks/index.md b/docs/frameworks/index.md
index eca48ab..b9f3810 100644
--- a/docs/frameworks/index.md
+++ b/docs/frameworks/index.md
@@ -1,6 +1,6 @@
---
title: Framework Integrations
-description: Complete guide for React, Vue, Svelte, Angular, SolidJS, and Preact integrations
+description: Complete guide for React, Vue, Angular, SolidJS, and Preact integrations
---
# Framework Integrations
@@ -8,7 +8,7 @@ description: Complete guide for React, Vue, Svelte, Angular, SolidJS, and Preact
> **Version**: 5.8.2
> **Status**: Stable
-Complete guide for using `@mcabreradev/filter` with 6 major frameworks.
+Complete guide for using `@mcabreradev/filter` with 5 major frameworks.
---
@@ -18,7 +18,6 @@ Complete guide for using `@mcabreradev/filter` with 6 major frameworks.
- [Installation](#installation)
- [React Integration](#react-integration)
- [Vue Integration](#vue-integration)
-- [Svelte Integration](#svelte-integration)
- [Angular Integration](#angular-integration) ⭐ NEW
- [SolidJS Integration](#solidjs-integration) ⭐ NEW
- [Preact Integration](#preact-integration) ⭐ NEW
@@ -37,7 +36,6 @@ The framework integrations provide idiomatic hooks, composables, services, and s
- ⚛️ **[React](/frameworks/react)** - Hooks with automatic re-rendering
- 🟢 **[Vue](/frameworks/vue)** - Composition API with reactivity
-- 🔴 **[Svelte](/frameworks/svelte)** - Store-based reactive filtering
- 🅰️ **[Angular](/frameworks/angular)** - Services and Pipes with Signals ⭐ NEW
- 🔷 **[SolidJS](/frameworks/solidjs)** - Signal-based reactive hooks ⭐ NEW
- ⚡ **[Preact](/frameworks/preact)** - Lightweight hooks API ⭐ NEW
@@ -46,13 +44,12 @@ The framework integrations provide idiomatic hooks, composables, services, and s
- **React Hooks**: `useFilter`, `useFilteredState`, `useDebouncedFilter`, `usePaginatedFilter`
- **Vue Composables**: Composition API-first with full reactivity
-- **Svelte Stores**: Reactive stores with derived state
- **Angular Services**: `FilterService`, `DebouncedFilterService`, `PaginatedFilterService`, `FilterPipe`
- **SolidJS Hooks**: `useFilter`, `useDebouncedFilter`, `usePaginatedFilter`
- **Preact Hooks**: `useFilter`, `useFilteredState`, `useDebouncedFilter`, `usePaginatedFilter`
- **Shared Utilities**: Debouncing, pagination, and performance optimizations
- **TypeScript**: Full type safety with generics
-- **SSR Compatible**: Works with Next.js, Nuxt, SvelteKit, Angular Universal, and SolidStart
+- **SSR Compatible**: Works with Next.js, Nuxt, Angular Universal, and SolidStart
---
@@ -64,7 +61,6 @@ npm install @mcabreradev/filter
# Install peer dependencies for your framework
npm install react # For React
npm install vue # For Vue
-npm install svelte # For Svelte
npm install @angular/core # For Angular 17+
npm install solid-js # For SolidJS
npm install preact # For Preact
@@ -488,185 +484,6 @@ function usePaginatedFilter(
---
-## Svelte Integration
-
-### useFilter
-
-Svelte store-based filtering.
-
-```svelte
-
-
-
-
Showing {$filtered.length} active users
- {#each $filtered as user (user.id)}
-
{user.name}
- {/each}
-
-```
-
-**API**:
-```typescript
-function useFilter(
- data: T[] | Readable,
- expression: Expression | Readable>,
- options?: FilterOptions
-): {
- filtered: Readable;
- isFiltering: Readable;
-}
-```
-
-### useFilteredState
-
-Stateful filtering with Svelte stores.
-
-```svelte
-
-```
-
-**API**:
-```typescript
-function useFilteredState(
- initialData?: T[],
- initialExpression?: Expression,
- options?: FilterOptions
-): {
- data: Writable;
- expression: Writable>;
- filtered: Readable;
- isFiltering: Readable;
-}
-```
-
-### useDebouncedFilter
-
-Debounced filtering for Svelte.
-
-```svelte
-
-
-
-
- {#if $isPending}
- Searching...
- {/if}
-
-
-```
-
-**API**:
-```typescript
-function useDebouncedFilter(
- data: T[] | Readable,
- expression: Expression | Readable>,
- options?: UseDebouncedFilterOptions
-): {
- filtered: Readable;
- isFiltering: Readable;
- isPending: Readable;
-}
-```
-
-### usePaginatedFilter
-
-Pagination support for Svelte.
-
-```svelte
-
-
-
-
-
-
- Page {$pagination.currentPage} of {$pagination.totalPages}
-
-
-
-```
-
-**API**:
-```typescript
-function usePaginatedFilter(
- data: T[] | Readable,
- expression: Expression | Readable>,
- initialPageSize?: number,
- options?: FilterOptions
-): {
- filtered: Readable;
- isFiltering: Readable;
- pagination: Readable>;
- currentPage: Writable;
- pageSize: Writable;
- nextPage: () => void;
- previousPage: () => void;
- goToPage: (page: number) => void;
- setPageSize: (size: number) => void;
-}
-```
-
----
-
## Angular Integration
⭐ **New in v5.7.0**: Full Angular support with Services, Pipes, and Signals!
@@ -1352,22 +1169,6 @@ const expression = computed(() => ({
useFilter(data, expression, { enableCache: true });
```
-### Svelte
-
-1. **Use derived stores**: For computed values
-```typescript
-const filtered = derived([data, expression], ([$data, $expr]) => {
- return filter($data, $expr);
-});
-```
-
-2. **Avoid store subscriptions in loops**: Subscribe once at the top level
-
-3. **Enable caching**: For large datasets
-```typescript
-useFilter(data, expression, { enableCache: true });
-```
-
### Angular
1. **Use Signals**: Leverage Angular's fine-grained reactivity
@@ -1430,10 +1231,6 @@ const { filtered } = useFilter(users, { active: true });
const { filtered } = useFilter(users, expression);
// filtered is ComputedRef
-// Svelte
-const { filtered } = useFilter(users, expression);
-// filtered is Readable
-
// Angular
filterService.setData(users);
// filtered is Signal
@@ -1563,58 +1360,6 @@ const {
```
-### Real-World Svelte Example
-
-```svelte
-
-
-
-
-
-
-
-
-
-
-```
-
---
## SSR Compatibility
@@ -1623,7 +1368,6 @@ All framework integrations are compatible with server-side rendering:
- **Next.js**: Works with App Router and Pages Router
- **Nuxt**: Compatible with Nuxt 3
-- **SvelteKit**: Full SSR support
- **Angular Universal**: Server-side rendering support
- **SolidStart**: SSR and streaming support
@@ -1652,19 +1396,6 @@ const { filtered } = useFilter(users, { active: true });
```
-### SvelteKit Example
-
-```svelte
-
-```
-
### Angular Universal Example
```typescript
@@ -1718,9 +1449,6 @@ const { filtered } = useFilter(users, { active: true });
// After (Vue)
const { filtered } = useFilter(users, { active: true });
-// After (Svelte)
-const { filtered } = useFilter(users, { active: true });
-
// After (Angular)
this.filterService.setExpression({ active: true });
@@ -1763,9 +1491,6 @@ const { filtered } = useFilter(users, { active: true });
// After (Vue)
const { filtered } = useFilter(users, { active: true });
-
-// After (Svelte)
-const { filtered } = useFilter(users, { active: true });
```
### From Custom Hooks
diff --git a/docs/frameworks/react.md b/docs/frameworks/react.md
index 59f4646..e172d30 100644
--- a/docs/frameworks/react.md
+++ b/docs/frameworks/react.md
@@ -1055,6 +1055,5 @@ export default function Loading() {
## Next Steps
- [Vue Integration](./vue.md)
-- [Svelte Integration](./svelte.md)
- [API Reference](../api/reference.md)
- [Examples](../examples/)
diff --git a/docs/frameworks/svelte.md b/docs/frameworks/svelte.md
deleted file mode 100644
index 8041f7d..0000000
--- a/docs/frameworks/svelte.md
+++ /dev/null
@@ -1,295 +0,0 @@
----
-title: Svelte Integration
-description: Svelte Stores for filtering with @mcabreradev/filter
----
-
-# Svelte Integration
-
-Complete guide for using `@mcabreradev/filter` with Svelte.
-
-## Installation
-
-```bash
-npm install @mcabreradev/filter
-```
-
-## Import
-
-```typescript
-import {
- useFilter,
- useFilteredState,
- useDebouncedFilter,
- usePaginatedFilter
-} from '@mcabreradev/filter/svelte';
-```
-
-## Available Functions
-
-- [`useFilter`](#usefilter) - Basic filtering with Svelte stores
-- [`useFilteredState`](#usefilteredstate) - Filtering with writable state
-- [`useDebouncedFilter`](#usedebouncedfilter) - Debounced filtering for search
-- [`usePaginatedFilter`](#usepaginatedfilter) - Filtering with pagination
-
-## useFilter
-
-Basic filtering with Svelte stores.
-
-```svelte
-
-
-
-
Showing {$filtered.length} active users
- {#each $filtered as user (user.id)}
-
{user.name}
- {/each}
-
-```
-
-### API Reference
-
-```typescript
-function useFilter(
- data: Readable | T[],
- expression: Readable | null> | Expression | null,
- options?: FilterOptions
-): UseFilterResult
-
-interface UseFilterResult {
- filtered: Readable;
- isFiltering: Readable;
-}
-```
-
-## useFilteredState
-
-Filtering with writable state management.
-
-```svelte
-
-
-
-
-
Found {$filtered.length} products
-
-```
-
-### API Reference
-
-```typescript
-function useFilteredState(
- data: Readable | T[],
- initialExpression: Expression | null,
- options?: FilterOptions
-): UseFilteredStateResult
-
-interface UseFilteredStateResult {
- filtered: Readable;
- expression: Writable | null>;
- setExpression: (expression: Expression | null) => void;
- isFiltering: Readable;
-}
-```
-
-## useDebouncedFilter
-
-Debounced filtering for search inputs.
-
-```svelte
-
-
-
-
- {#if $isPending}
-
Searching...
- {/if}
-
Found {$filtered.length} users
-
-```
-
-### API Reference
-
-```typescript
-function useDebouncedFilter(
- data: Readable | T[],
- expression: (() => Expression | null) | Readable | null> | Expression | null,
- options?: UseDebouncedFilterOptions
-): UseDebouncedFilterResult
-
-interface UseDebouncedFilterOptions extends FilterOptions {
- delay?: number; // Default: 300ms
-}
-
-interface UseDebouncedFilterResult {
- filtered: Readable;
- isPending: Readable;
-}
-```
-
-## usePaginatedFilter
-
-Filtering with built-in pagination.
-
-```svelte
-
-
-
- {#each $paginatedResults as product (product.id)}
-
{product.name} - ${product.price}
- {/each}
-
-
- Page {$currentPage} of {$totalPages}
-
-
-
-```
-
-### API Reference
-
-```typescript
-function usePaginatedFilter(
- data: Readable | T[],
- expression: Readable | null> | Expression | null,
- options?: {
- pageSize?: number;
- initialPage?: number;
- filterOptions?: FilterOptions;
- }
-): UsePaginatedFilterResult
-
-interface UsePaginatedFilterResult {
- paginatedResults: Readable;
- currentPage: Readable;
- totalPages: Readable;
- totalItems: Readable;
- pageSize: Writable;
- nextPage: () => void;
- prevPage: () => void;
- goToPage: (page: number) => void;
- setPageSize: (size: number) => void;
-}
-```
-
-## TypeScript Support
-
-Full type safety with generics:
-
-```typescript
-interface Product {
- id: number;
- name: string;
- price: number;
-}
-
-const { filtered } = useFilter(
- products,
- { price: { $gte: 100 } }
-);
-// filtered is typed as Readable
-```
-
-## SSR Support
-
-Works with SvelteKit:
-
-```svelte
-
-```
-
-## Next Steps
-
-- [React Integration](./react.md)
-- [Vue Integration](./vue.md)
-- [SvelteKit Integration](./sveltekit.md)
-- [API Reference](../api/reference.md)
-
-
diff --git a/docs/frameworks/sveltekit.md b/docs/frameworks/sveltekit.md
deleted file mode 100644
index e863398..0000000
--- a/docs/frameworks/sveltekit.md
+++ /dev/null
@@ -1,596 +0,0 @@
-# SvelteKit Integration
-
-Guide for using @mcabreradev/filter with SvelteKit.
-
-## Overview
-
-@mcabreradev/filter integrates seamlessly with SvelteKit, supporting both client-side and server-side filtering with Svelte stores.
-
-## Installation
-
-```bash
-# Using npm
-npm install @mcabreradev/filter
-
-# Using yarn
-yarn add @mcabreradev/filter
-
-# Using pnpm
-pnpm add @mcabreradev/filter
-
-## Basic Usage
-
-### Client-Side Filtering
-
-```svelte
-
-
-
-
-{#if $isFiltering}
- Loading...
-{:else}
-
- {#each $filtered as product (product.id)}
-
{product.name}
- {/each}
-
-{/if}
-```
-
-## Server-Side Rendering
-
-### Using `load` Function
-
-```typescript
-import { filter } from '@mcabreradev/filter';
-import type { PageLoad } from './$types';
-
-interface Product {
- id: number;
- name: string;
- price: number;
- category: string;
-}
-
-export const load: PageLoad = async ({ url, fetch }) => {
- const category = url.searchParams.get('category') || '';
- const minPrice = Number(url.searchParams.get('minPrice')) || 0;
-
- const response = await fetch('/api/products');
- const products: Product[] = await response.json();
-
- const expression = {
- $and: [
- category && { category: { $eq: category } },
- minPrice > 0 && { price: { $gte: minPrice } }
- ].filter(Boolean)
- };
-
- return {
- products: filter(products, expression)
- };
-};
-```
-
-```svelte
-
-
-Products
-
- {#each data.products as product (product.id)}
-
-
{product.name}
-
${product.price}
-
- {/each}
-
-```
-
-### Server Load Function
-
-```typescript
-import { filter } from '@mcabreradev/filter';
-import type { PageServerLoad } from './$types';
-
-export const load: PageServerLoad = async ({ url }) => {
- const category = url.searchParams.get('category') || '';
-
- const products = await getProducts();
-
- const expression = {
- category: { $eq: category }
- };
-
- return {
- products: filter(products, expression)
- };
-};
-```
-
-## API Routes
-
-### GET Endpoint
-
-```typescript
-import { json } from '@sveltejs/kit';
-import { filter } from '@mcabreradev/filter';
-import type { RequestHandler } from './$types';
-
-interface Product {
- id: number;
- name: string;
- price: number;
- category: string;
-}
-
-export const GET: RequestHandler = async ({ url }) => {
- const category = url.searchParams.get('category');
- const minPrice = url.searchParams.get('minPrice');
-
- const products: Product[] = await getProducts();
-
- const expression = {
- $and: [
- category && { category: { $eq: category } },
- minPrice && { price: { $gte: Number(minPrice) } }
- ].filter(Boolean)
- };
-
- const filtered = filter(products, expression);
-
- return json({ products: filtered });
-};
-```
-
-### POST Endpoint
-
-```typescript
-import { json } from '@sveltejs/kit';
-import { filter } from '@mcabreradev/filter';
-import type { RequestHandler } from './$types';
-import type { Expression } from '@mcabreradev/filter';
-
-export const POST: RequestHandler = async ({ request }) => {
- const { expression } = await request.json() as { expression: Expression };
-
- const products = await getProducts();
- const filtered = filter(products, expression);
-
- return json({
- products: filtered,
- total: filtered.length
- });
-};
-```
-
-## Advanced Patterns
-
-### Search with Pagination
-
-```svelte
-
-
-
-
-
-
- {#each $filtered as product (product.id)}
-
{product.name}
- {/each}
-
-
-
-
- Page {$currentPage} of {$totalPages}
-
-
-```
-
-### Debounced Search
-
-```svelte
-
-
-
-{#if $isPending}
- Searching...
-{/if}
-
-
- {#each $filtered as product (product.id)}
-
{product.name}
- {/each}
-
-```
-
-### URL Query Parameters
-
-```svelte
-
-
-
-
- updateFilter('minPrice', e.target.value)}
- placeholder="Min price"
-/>
-
-
- {#each $filtered as product (product.id)}
-
{product.name}
- {/each}
-
-```
-
-### Custom Store Pattern
-
-Create a reusable store:
-
-```typescript
-import { derived, writable, type Readable, type Writable } from 'svelte/store';
-import { filter } from '@mcabreradev/filter';
-import type { Expression } from '@mcabreradev/filter';
-
-interface Product {
- id: number;
- name: string;
- price: number;
- category: string;
-}
-
-interface ProductFilters {
- searchTerm: string;
- category: string;
- minPrice: number;
- maxPrice: number;
-}
-
-export function createProductFilterStore(initialProducts: Product[] = []) {
- const products: Writable = writable(initialProducts);
- const filters: Writable = writable({
- searchTerm: '',
- category: '',
- minPrice: 0,
- maxPrice: 0
- });
-
- const filtered: Readable = derived(
- [products, filters],
- ([$products, $filters]) => {
- const conditions = [];
-
- if ($filters.searchTerm) {
- conditions.push({
- name: { $regex: new RegExp($filters.searchTerm, 'i') }
- });
- }
-
- if ($filters.category) {
- conditions.push({
- category: { $eq: $filters.category }
- });
- }
-
- if ($filters.minPrice > 0) {
- conditions.push({
- price: { $gte: $filters.minPrice }
- });
- }
-
- if ($filters.maxPrice > 0) {
- conditions.push({
- price: { $lte: $filters.maxPrice }
- });
- }
-
- const expression: Expression =
- conditions.length > 0 ? { $and: conditions } : {};
-
- return filter($products, expression);
- }
- );
-
- return {
- products,
- filters,
- filtered,
- setProducts: (newProducts: Product[]) => products.set(newProducts),
- updateFilters: (newFilters: Partial) =>
- filters.update(f => ({ ...f, ...newFilters })),
- resetFilters: () => filters.set({
- searchTerm: '',
- category: '',
- minPrice: 0,
- maxPrice: 0
- })
- };
-}
-```
-
-Usage:
-
-```svelte
-
-
- updateFilters({ searchTerm: e.target.value })}
- placeholder="Search..."
-/>
-
-
-
-
- {#each $filtered as product (product.id)}
-
{product.name}
- {/each}
-
-```
-
-## Form Actions
-
-### Using Form Actions
-
-```typescript
-import { fail } from '@sveltejs/kit';
-import { filter } from '@mcabreradev/filter';
-import type { Actions } from './$types';
-
-export const actions: Actions = {
- filter: async ({ request }) => {
- const data = await request.formData();
- const category = data.get('category') as string;
- const minPrice = Number(data.get('minPrice'));
-
- const products = await getProducts();
-
- const expression = {
- $and: [
- category && { category: { $eq: category } },
- minPrice > 0 && { price: { $gte: minPrice } }
- ].filter(Boolean)
- };
-
- const filtered = filter(products, expression);
-
- return {
- products: filtered
- };
- }
-};
-```
-
-```svelte
-
-
-
-
-{#if form?.products}
-
- {#each form.products as product (product.id)}
-
{product.name}
- {/each}
-
-{/if}
-```
-
-## Performance Tips
-
-### 1. Use Reactive Statements
-
-```typescript
-$: expression = {
- status: { $eq: status }
-};
-```
-
-### 2. Enable Memoization
-
-```typescript
-const { filtered } = useFilter(data, expression, {
- memoize: true
-});
-```
-
-### 3. Use Server Load Functions
-
-Filter data on the server when possible:
-
-```typescript
-export const load: PageServerLoad = async () => {
- const products = await getProducts();
- return {
- products: filter(products, expression)
- };
-};
-```
-
-### 4. Implement Pagination
-
-```typescript
-const { filtered } = usePaginatedFilter(data, expression, 50);
-```
-
-## TypeScript Support
-
-Ensure proper TypeScript configuration in `svelte.config.js`:
-
-```javascript
-import adapter from '@sveltejs/adapter-auto';
-import { vitePreprocess } from '@sveltejs/kit/vite';
-
-export default {
- preprocess: vitePreprocess(),
- kit: {
- adapter: adapter()
- }
-};
-```
-
-And in `tsconfig.json`:
-
-```json
-{
- "extends": "./.svelte-kit/tsconfig.json",
- "compilerOptions": {
- "strict": true,
- "esModuleInterop": true,
- "skipLibCheck": true
- }
-}
-```
-
-## Related Resources
-
-- [Svelte Integration](/frameworks/svelte)
-- [Best Practices](/guide/best-practices)
-- [Examples](/examples/basic-usage)
-- [API Reference](/api/core)
-
diff --git a/docs/frameworks/vue.md b/docs/frameworks/vue.md
index 2f9e9bc..69b36a6 100644
--- a/docs/frameworks/vue.md
+++ b/docs/frameworks/vue.md
@@ -1197,7 +1197,6 @@ const { filtered } = useFilter(products, { inStock: true });
## Next Steps
- [React Integration](./react.md)
-- [Svelte Integration](./svelte.md)
- [Nuxt Integration](./nuxt.md)
- [API Reference](../api/reference.md)
diff --git a/docs/guide/best-practices.md b/docs/guide/best-practices.md
index 8a3499d..ab248b6 100644
--- a/docs/guide/best-practices.md
+++ b/docs/guide/best-practices.md
@@ -242,46 +242,6 @@ watch(filtered, (newFiltered) => {
});
```
-## Svelte Best Practices
-
-### Use Stores
-
-Leverage Svelte stores for reactivity:
-
-```typescript
-import { writable } from 'svelte/store';
-import { useFilter } from '@mcabreradev/filter/svelte';
-
-const users = writable([]);
-const expression = writable({ status: { $eq: 'active' } });
-
-const { filtered } = useFilter(users, expression);
-```
-
-### Reactive Statements
-
-Use reactive statements for derived values:
-
-```svelte
-
-
-
-
-{#each $filtered as user}
- {user.name}
-{/each}
-```
-
## Performance Optimization
### Enable Memoization for Large Datasets
diff --git a/docs/guide/comparison.md b/docs/guide/comparison.md
index f143c3d..cfd9a41 100644
--- a/docs/guide/comparison.md
+++ b/docs/guide/comparison.md
@@ -12,7 +12,7 @@ This guide compares @mcabreradev/filter with popular alternatives to help you ch
|---------|-------------------|--------|----------------|---------|---------|
| Bundle Size | ~3KB | ~70KB | 0KB (native) | ~12KB | ~5KB |
| TypeScript | ✅ Full support | ⚠️ @types required | ✅ Native | ⚠️ @types required | ❌ Limited |
-| Framework Integration | ✅ React, Vue, Svelte | ❌ None | ❌ None | ❌ None | ❌ None |
+| Framework Integration | ✅ React, Vue | ❌ None | ❌ None | ❌ None | ❌ None |
| Operator-Based | ✅ Yes | ❌ No | ❌ No | ❌ No | ✅ Yes |
| Nested Objects | ✅ Yes | ✅ Yes | ⚠️ Manual | ❌ No | ✅ Yes |
| Fuzzy Search | ❌ No | ❌ No | ❌ No | ✅ Yes | ❌ No |
@@ -109,7 +109,7 @@ const { filtered } = useFilter(data, {
**2. Framework Integration**
-Built-in hooks for React, Vue, and Svelte.
+Built-in hooks for React and Vue.
**3. Advanced Operators**
@@ -181,7 +181,7 @@ Better type inference and safety.
**4. Modern API**
-Designed for modern React, Vue, and Svelte.
+Designed for modern React and Vue.
#### When to Use Sift.js
@@ -373,7 +373,7 @@ const { filtered } = useFilter(data, {
### Choose @mcabreradev/filter if you need:
-✅ Framework integration (React, Vue, Svelte)
+✅ Framework integration (React, Vue)
✅ Type-safe filtering
✅ Complex logical operations
✅ Built-in pagination
diff --git a/docs/guide/faq.md b/docs/guide/faq.md
index 5018ed2..0d38be9 100644
--- a/docs/guide/faq.md
+++ b/docs/guide/faq.md
@@ -6,7 +6,7 @@ Common questions about @mcabreradev/filter.
### What is @mcabreradev/filter?
-A TypeScript-first filtering library that provides powerful, type-safe filtering capabilities for JavaScript arrays with framework integrations for React, Vue, and Svelte.
+A TypeScript-first filtering library that provides powerful, type-safe filtering capabilities for JavaScript arrays with framework integrations for React and Vue.
### Why use this instead of Array.filter()?
@@ -36,7 +36,6 @@ Yes. The library is:
- Core: ~3KB gzipped
- React integration: ~1KB additional
- Vue integration: ~1KB additional
-- Svelte integration: ~1KB additional
Tree-shaking ensures you only bundle what you use.
@@ -65,13 +64,10 @@ No, but it's recommended. The library works with JavaScript but provides excelle
**Vue**: `vue ^3.0.0`
-**Svelte**: `svelte ^3.0.0 || ^4.0.0`
-
-### Can I use it with older React/Vue/Svelte versions?
+### Can I use it with older React/Vue versions?
- React 16/17: May work but not officially supported
- Vue 2: Not supported (use Vue 3)
-- Svelte 3: Supported
## Usage Questions
@@ -530,18 +526,6 @@ const { filtered } = useFilter(data, expression);
```
-### Does it work with SvelteKit?
-
-Yes, use in components:
-
-```svelte
-
-```
-
### Can I use it with React Native?
Yes, the React integration works with React Native:
diff --git a/docs/guide/installation.md b/docs/guide/installation.md
index fb79615..44e93b7 100644
--- a/docs/guide/installation.md
+++ b/docs/guide/installation.md
@@ -83,9 +83,6 @@ import { useFilter } from '@mcabreradev/filter/react';
// Vue composables
import { useFilter } from '@mcabreradev/filter/vue';
-// Svelte stores
-import { useFilter } from '@mcabreradev/filter/svelte';
-
// Lazy evaluation
import { filterLazy } from '@mcabreradev/filter/lazy';
@@ -150,19 +147,6 @@ const searchTerm = ref('');
const { filtered, isFiltering } = useFilter(users, searchTerm);
```
-### Svelte
-
-```typescript
-// Classic import
-import { useFilter } from '@mcabreradev/filter';
-
-// Modular import (recommended)
-import { useFilter } from '@mcabreradev/filter/svelte';
-
-const searchTerm = writable('');
-const { filtered, isFiltering } = useFilter(users, searchTerm);
-```
-
## CDN Usage
For quick prototyping without a build step:
@@ -238,7 +222,7 @@ console.log(adults); // [{ name: 'Alice', age: 30 }, { name: 'Bob', age: 25 }]
- [Quick Start](/guide/quick-start) - Get started in minutes
- [Modular Imports](/guide/modular-imports) - Optimize bundle size
- [Basic Filtering](/guide/basic-filtering) - Learn core concepts
-- [Framework Integrations](/frameworks/) - React, Vue, Svelte guides
+- [Framework Integrations](/frameworks/) - React, Vue guides
## Troubleshooting
diff --git a/docs/guide/migration-v2.md b/docs/guide/migration-v2.md
index 9f78531..7a89165 100644
--- a/docs/guide/migration-v2.md
+++ b/docs/guide/migration-v2.md
@@ -6,10 +6,10 @@ This guide helps you migrate to the latest version of `@mcabreradev/filter` and
### What's New in v5.4.0
-- **Stable Framework Integrations**: Production-ready React, Vue, and Svelte support
+- **Stable Framework Integrations**: Production-ready React, Vue, Angular, SolidJS, and Preact support
- **Improved Type Safety**: Better TypeScript inference for framework hooks
- **Bug Fixes**: Stability improvements across all integrations
-- **SSR Compatibility**: Full support for Next.js, Nuxt, and SvelteKit
+- **SSR Compatibility**: Full support for Next.js and Nuxt
---
@@ -328,51 +328,6 @@ interface UsePaginatedFilterResult {
---
-### Svelte Stores
-
-Svelte integration uses stores for reactive state management.
-
-#### useFilter
-
-```typescript
-import { writable } from 'svelte/store';
-import { useFilter } from '@mcabreradev/filter';
-
-const users = writable([...]);
-const searchTerm = writable('');
-
-const { filtered, isFiltering } = useFilter(users, {
- name: { $contains: searchTerm }
-});
-```
-
-**Usage in Svelte component:**
-```svelte
-
-
-{#if $isFiltering}
- Filtering active...
-{/if}
-
-{#each $filtered as user (user.id)}
- {user.name}
-{/each}
-```
-
-**Return Type:**
-```typescript
-interface UseFilterResult {
- filtered: Readable;
- isFiltering: Readable;
-}
-```
-
#### useFilteredState
```typescript
@@ -503,26 +458,6 @@ const { filtered, isPending } = useDebouncedFilter(
```
-**Svelte:**
-```svelte
-
-
-
-{#if $isPending}
- Typing...
-{/if}
-```
-
### Pagination with Filtering
All frameworks follow the same pattern - filter first, then paginate the results.
@@ -575,9 +510,6 @@ const { filtered } = useFilter(products, { price: { $gte: 100 } });
const { filtered } = useFilter(products, { price: { $gte: 100 } });
// filtered is ComputedRef
-// Svelte
-const { filtered } = useFilter(products, { price: { $gte: 100 } });
-// filtered is Readable
```
---
@@ -588,8 +520,6 @@ All framework integrations are SSR-compatible:
- **Next.js**: Works in both App Router and Pages Router
- **Nuxt**: Compatible with Nuxt 3
-- **SvelteKit**: Full SSR support
-
Example with Next.js App Router:
```typescript
@@ -661,17 +591,6 @@ const searchTerm = ref(''); // Not const searchTerm = '';
const { filtered } = useFilter(data, { name: { $contains: searchTerm } });
```
-### Svelte: "Store is not reactive"
-
-**Problem:** Not using `$` prefix to access store values.
-
-**Solution:** Use `$` prefix:
-```svelte
-{#each $filtered as item}
- {item.name}
-{/each}
-```
-
---
## Support
@@ -688,5 +607,4 @@ Check out the framework-specific guides:
- [React Integration Guide](../frameworks/react.md)
- [Vue Integration Guide](../frameworks/vue.md)
-- [Svelte Integration Guide](../frameworks/svelte.md)
diff --git a/docs/guide/modular-imports.md b/docs/guide/modular-imports.md
index a2cdbf7..ae3a191 100644
--- a/docs/guide/modular-imports.md
+++ b/docs/guide/modular-imports.md
@@ -90,25 +90,6 @@ const { filtered, isFiltering } = useFilter(users, searchTerm);
- `useDebouncedFilter` - Debounced filtering
- `usePaginatedFilter` - Pagination support
-### Svelte
-
-```typescript
-// Classic import - exports useFilter for compatibility
-import { useFilter } from '@mcabreradev/filter';
-
-// Modular import (recommended)
-import { useFilter } from '@mcabreradev/filter/svelte';
-
-const searchTerm = writable('');
-const { filtered, isFiltering } = useFilter(users, searchTerm);
-```
-
-**Available stores:**
-- `useFilter` - Basic filtering store
-- `useFilteredState` - Filtered state store
-- `useDebouncedFilter` - Debounced filtering store
-- `usePaginatedFilter` - Pagination store
-
## Operators
### Comparison Operators
@@ -285,7 +266,6 @@ The package is configured with granular exports in `package.json`:
"./core": "./build/core/index.js",
"./react": "./build/integrations/react/index.js",
"./vue": "./build/integrations/vue/index.js",
- "./svelte": "./build/integrations/svelte/index.js",
"./operators/comparison": "./build/operators/comparison.js",
"./operators/array": "./build/operators/array.js",
"./operators/string": "./build/operators/string.js",
diff --git a/docs/guide/quick-start.md b/docs/guide/quick-start.md
index a78f540..7113fed 100644
--- a/docs/guide/quick-start.md
+++ b/docs/guide/quick-start.md
@@ -290,7 +290,7 @@ Now that you know the basics, explore more advanced features:
- [Lazy Evaluation](/guide/lazy-evaluation) - Efficient processing for large datasets
- [Memoization](/guide/memoization) - 530x performance boost with caching
- [Configuration](/guide/configuration) - All options including orderBy and limit
-- [Framework Integration](/frameworks/) - React, Vue, Svelte, Angular, SolidJS, Preact support ⭐
+- [Framework Integration](/frameworks/) - React, Vue, Angular, SolidJS, Preact support ⭐
## Interactive Playground
diff --git a/docs/guide/troubleshooting.md b/docs/guide/troubleshooting.md
index c1817ca..1d653e7 100644
--- a/docs/guide/troubleshooting.md
+++ b/docs/guide/troubleshooting.md
@@ -100,39 +100,6 @@ import type { ComputedRef } from 'vue';
const { filtered }: { filtered: ComputedRef } = useFilter(data, expression);
```
-## Svelte Integration Issues
-
-### Store Not Updating
-
-**Problem**: `$filtered` doesn't update in template.
-
-**Cause**: Not subscribing to store properly.
-
-**Solution**:
-```svelte
-
-
-{#each $filtered as item}
- {item.name}
-{/each}
-```
-
-### TypeScript Errors with Stores
-
-**Problem**: Type errors when using Svelte stores.
-
-**Solution**:
-```typescript
-import type { Readable } from 'svelte/store';
-import type { User } from './types';
-
-const { filtered }: { filtered: Readable } = useFilter(data, expression);
-```
-
## Performance Issues
### Slow Filtering on Large Datasets
diff --git a/docs/implementation/operators.md b/docs/implementation/operators.md
index 33d483c..18dc26f 100644
--- a/docs/implementation/operators.md
+++ b/docs/implementation/operators.md
@@ -682,7 +682,7 @@ All success criteria from the original plan and subsequent releases were met:
- ✅ 100% test coverage for operators module
- ✅ Intelligent TypeScript autocomplete
- ✅ Visual debugging capabilities
-- ✅ Framework integrations (React, Vue, Svelte)
+- ✅ Framework integrations (React, Vue)
- ✅ Zero dependencies (except Zod for validation)
## Build & Release
@@ -770,7 +770,7 @@ The MongoDB-style operators feature has been successfully evolved from v5.0.0 to
- Multi-layer memoization (530x-1520x faster)
- Lazy evaluation (500x faster for early exit)
- Visual debugging with expression trees
- - Framework integrations (React, Vue, Svelte)
+ - Framework integrations (React, Vue)
- Array OR syntax
- Geospatial distance calculations
- Datetime utilities
diff --git a/docs/index.md b/docs/index.md
index 740212f..88ec389 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -62,7 +62,7 @@ features:
- icon: 🎨
title: Framework Integration
- details: React Hooks, Vue Composables, and Svelte Stores. First-class framework support.
+ details: React Hooks, Vue Composables, Angular Services, SolidJS, and Preact. First-class framework support.
- icon: 🧪
title: Battle-Tested
@@ -175,17 +175,6 @@ const { filtered, isFiltering } = useFilter(users, searchTerm);
```
-### Svelte
-
-```svelte
-
-```
## Why Choose This Library?
@@ -242,7 +231,7 @@ const { filtered, isFiltering } = useFilter(users, searchTerm);
🎨
Framework Agnostic
- Works everywhere: React, Vue, Svelte, Angular, Node.js, Deno, Bun. First-class hooks and composables included.
+ Works everywhere: React, Vue, Angular, Node.js, Deno, Bun. First-class hooks and composables included.
diff --git a/docs/project/changelog.md b/docs/project/changelog.md
index 2368bc1..fcd3779 100644
--- a/docs/project/changelog.md
+++ b/docs/project/changelog.md
@@ -15,7 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added exhaustive examples for all 40+ operators (comparison, array, string, logical, geospatial, datetime)
- Documented all Performance Monitoring, Type Helpers, and DateTime utilities
- Completed configuration guide with orderBy and limit options
- - Updated framework integration guides for React, Vue, Svelte, Angular, SolidJS, and Preact
+ - Updated framework integration guides for React, Vue, Angular, SolidJS, and Preact
- **Performance Documentation**: Added detailed performance considerations section
- Operator performance rankings (fastest to slowest)
- Best practices for optimization
@@ -117,7 +117,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Applied after filtering and sorting for predictable results
- Works with all expression types and operators
- Compatible with caching and debug modes
- - Full framework integration support (React, Vue, Svelte, Angular, SolidJS, Preact)
+ - Full framework integration support (React, Vue, Angular, SolidJS, Preact)
- **Complete Documentation**:
- Angular integration guide with services, pipes, and SSR examples
- SolidJS integration guide with signal patterns and SolidStart SSR
@@ -294,7 +294,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Updated React integration documentation
- Updated Vue integration documentation
-- Updated Svelte integration documentation
- Improved API reference clarity
### Fixed
@@ -308,7 +307,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Pagination support for all framework integrations
- `usePaginatedFilter` hook for React
- `usePaginatedFilter` composable for Vue
-- `usePaginatedFilter` store for Svelte
- Pagination state management (`currentPage`, `totalPages`, `pageSize`)
- Pagination actions (`nextPage`, `previousPage`, `goToPage`, `setPageSize`)
@@ -326,21 +324,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Debounced filtering support
- `useDebouncedFilter` hook for React
- `useDebouncedFilter` composable for Vue
-- `useDebouncedFilter` store for Svelte
- `isPending` state for debounced operations
- Configurable delay option
### Changed
- Optimized re-render behavior in React
- Improved reactivity in Vue
-- Enhanced store updates in Svelte
-
## [5.1.0] - 2024-07-05
### Added
- `useFilteredState` hook for React
- `useFilteredState` composable for Vue
-- `useFilteredState` store for Svelte
- State management for data and expressions
- Setter functions for dynamic updates
@@ -446,7 +440,7 @@ See [Migration Guide v5.4](/guide/migration-v2) for detailed migration instructi
### Added
- Modern operator-based API
- TypeScript support
-- Framework integrations (React, Vue, Svelte)
+- Framework integrations (React, Vue)
- Comprehensive test suite
### Changed
diff --git a/docs/project/cheatsheet.md b/docs/project/cheatsheet.md
index 5fa2fc8..c81c31e 100644
--- a/docs/project/cheatsheet.md
+++ b/docs/project/cheatsheet.md
@@ -462,15 +462,6 @@ const searchTerm = ref('');
const { filtered, isFiltering } = useFilter(users, searchTerm);
```
-### Svelte Stores
-```typescript
-import { writable } from 'svelte/store';
-import { useFilter } from '@mcabreradev/filter/svelte';
-
-const searchTerm = writable('');
-const { filtered, isFiltering } = useFilter(users, searchTerm);
-```
-
---
## Performance Tips
diff --git a/docs/project/contributing.md b/docs/project/contributing.md
index c358bf2..9f07c1e 100644
--- a/docs/project/contributing.md
+++ b/docs/project/contributing.md
@@ -109,7 +109,6 @@ filter/
│ ├── integrations/ # Framework integrations
│ │ ├── react/
│ │ ├── vue/
-│ │ ├── svelte/
│ │ └── shared/
│ ├── predicate/ # Predicate functions
│ ├── types/ # TypeScript type definitions
@@ -441,7 +440,6 @@ When adding framework integrations:
**React**: Use hooks, avoid class components
**Vue**: Use Composition API
-**Svelte**: Use stores
### 2. Maintain Type Safety
@@ -485,7 +483,6 @@ console.timeEnd('filter');
- Implement lazy evaluation where appropriate
- Avoid unnecessary re-renders in React
- Minimize reactivity overhead in Vue
-- Optimize store updates in Svelte
### Memory Management
diff --git a/docs/project/roadmap.md b/docs/project/roadmap.md
index e53e312..1b4d361 100644
--- a/docs/project/roadmap.md
+++ b/docs/project/roadmap.md
@@ -257,7 +257,7 @@ console.log('Execution time:', result.stats.executionTime);
### 🔴 Critical Priority - Completed
#### Framework Integrations ✅
-**Epic**: React, Vue, Svelte Hooks
+**Epic**: React, Vue Hooks
**Effort**: 5-6 days
**Impact**: 🔥 High
**Status**: ✅ Completed
@@ -265,11 +265,10 @@ console.log('Execution time:', result.stats.executionTime);
**Deliverables**:
- ✅ React integration (useFilter, useFilteredState, useDebouncedFilter, usePaginatedFilter)
- ✅ Vue integration (Composition API composables)
-- ✅ Svelte integration (Store-based filtering)
- ✅ TypeScript support with full generics
- ✅ 100% test coverage
- ✅ Comprehensive documentation
-- ✅ SSR compatibility (Next.js, Nuxt, SvelteKit)
+- ✅ SSR compatibility (Next.js, Nuxt)
**Success Metrics**:
- ✅ All framework integrations completed
@@ -670,7 +669,7 @@ docs/
### 🔴 Critical Priority
#### 13. Framework Integrations ✅
-**Epic**: React, Vue, Svelte Hooks
+**Epic**: React, Vue Hooks
**Effort**: 5-6 days
**Impact**: 🔥 High
**Status**: ✅ Completed
@@ -694,15 +693,6 @@ docs/
- TypeScript support
- Comprehensive tests
- Examples and docs
-- ✅ Svelte integration
- - Store-based filtering
- - `useFilter` store
- - `useFilteredState` store
- - `useDebouncedFilter` store
- - `usePaginatedFilter` store
- - TypeScript support
- - Comprehensive tests
- - Examples and docs
- ✅ Framework comparison guide
- ✅ Comprehensive documentation
@@ -744,19 +734,6 @@ src/
vue.constants.ts
vue.utils.ts
index.ts
- svelte/
- use-filter.ts
- use-filter.test.ts
- use-filtered-state.ts
- use-filtered-state.test.ts
- use-debounced-filter.ts
- use-debounced-filter.test.ts
- use-paginated-filter.ts
- use-paginated-filter.test.ts
- svelte.types.ts
- svelte.constants.ts
- svelte.utils.ts
- index.ts
docs/
FRAMEWORK_INTEGRATIONS.md
```
@@ -777,18 +754,11 @@ import { useFilter, usePaginatedFilter } from '@mcabreradev/filter';
const searchTerm = ref('');
const { filtered, isFiltering } = useFilter(users, searchTerm);
-// Svelte
-import { writable } from 'svelte/store';
-import { useFilter } from '@mcabreradev/filter';
-
-const searchTerm = writable('');
-const { filtered, isFiltering } = useFilter(users, searchTerm);
```
**Success Metrics**:
- ✅ React hooks implemented and tested (100% coverage)
- ✅ Vue composables implemented and tested (100% coverage)
-- ✅ Svelte stores implemented and tested (100% coverage)
- ✅ Comprehensive documentation created
- ✅ TypeScript support with full generics
- ✅ SSR compatibility verified
@@ -1042,7 +1012,7 @@ const mongoQuery = adapter.translate({
- **NPM Downloads**: 10K/month by Q4 2026
- **GitHub Stars**: 500+ by Q4 2026
- **Contributors**: 10+ active contributors
-- **Framework Integrations**: ✅ React, Vue, Svelte (Completed)
+- **Framework Integrations**: ✅ React, Vue (Completed)
### Quality Metrics
- **Test Coverage**: ✅ Maintain 100%
@@ -1090,10 +1060,9 @@ Features are prioritized based on:
- ✅ v5.5.0: Array OR Syntax
- ✅ v5.5.0: Visual Debugging (debug mode, tree visualization, performance metrics)
- ✅ v5.5.0: Interactive Playground
-- ✅ v5.4.0: Framework Integrations (React, Vue, Svelte)
+- ✅ v5.4.0: Framework Integrations (React, Vue)
- ✅ v5.4.0: React Hooks with full feature set
- ✅ v5.4.0: Vue Composables with Composition API
-- ✅ v5.4.0: Svelte Stores with reactivity
- ✅ v5.4.0: Comprehensive framework documentation
- ✅ v5.2.0: Enhanced memoization (530x-1520x faster)
- ✅ v5.2.0: Logical operators ($and, $or, $not)
diff --git a/package.json b/package.json
index f1eb1cc..c9e5b73 100644
--- a/package.json
+++ b/package.json
@@ -74,7 +74,6 @@
"performance",
"react",
"vue",
- "svelte",
"framework-integration",
"type-safe",
"zero-dependencies",
@@ -99,7 +98,6 @@
"temporal-query",
"react-hooks",
"vue-composables",
- "svelte-stores",
"nextjs",
"node",
"nodejs",
@@ -142,7 +140,6 @@
"rxjs": "^7.8.1",
"size-limit": "^11.2.0",
"solid-js": "^1.9.11",
- "svelte": "^5.54.1",
"tsd": "^0.33.0",
"tsx": "^4.20.6",
"typedoc": "^0.28.17",
@@ -158,7 +155,6 @@
"preact": ">=10.0.0",
"react": ">=18.0.0",
"solid-js": ">=1.8.0",
- "svelte": ">=4.0.0 || >=5.0.0",
"vue": ">=3.0.0",
"zod": ">=3.0.0"
},
@@ -175,9 +171,6 @@
"solid-js": {
"optional": true
},
- "svelte": {
- "optional": true
- },
"vue": {
"optional": true
},
@@ -247,11 +240,6 @@
"import": "./build/integrations/vue/index.js",
"default": "./build/integrations/vue/index.js"
},
- "./svelte": {
- "types": "./build/integrations/svelte/index.d.ts",
- "import": "./build/integrations/svelte/index.js",
- "default": "./build/integrations/svelte/index.js"
- },
"./angular": {
"types": "./build/integrations/angular/index.d.ts",
"import": "./build/integrations/angular/index.js",
diff --git a/src/index.ts b/src/index.ts
index 0167025..5bb6477 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -172,21 +172,6 @@ export type {
UsePaginatedFilterResult as UsePaginatedFilterResultVue,
} from './integrations/vue/index.js';
-export {
- useFilter as useFilterSvelte,
- useFilteredState as useFilteredStateSvelte,
- useDebouncedFilter as useDebouncedFilterSvelte,
- usePaginatedFilter as usePaginatedFilterSvelte,
-} from './integrations/svelte/index.js';
-
-export type {
- UseFilterResult as UseFilterResultSvelte,
- UseFilteredStateResult as UseFilteredStateResultSvelte,
- UseDebouncedFilterOptions as UseDebouncedFilterOptionsSvelte,
- UseDebouncedFilterResult as UseDebouncedFilterResultSvelte,
- UsePaginatedFilterResult as UsePaginatedFilterResultSvelte,
-} from './integrations/svelte/index.js';
-
export {
useFilter,
useFilteredState,
diff --git a/src/integrations/svelte/index.ts b/src/integrations/svelte/index.ts
deleted file mode 100644
index 58601b9..0000000
--- a/src/integrations/svelte/index.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-export { useFilter } from './use-filter';
-export { useFilteredState } from './use-filtered-state';
-export { useDebouncedFilter } from './use-debounced-filter';
-export { usePaginatedFilter } from './use-paginated-filter';
-
-export type {
- UseFilterResult,
- UseFilteredStateResult,
- UseDebouncedFilterOptions,
- UseDebouncedFilterResult,
- UsePaginatedFilterResult,
-} from './svelte.types';
diff --git a/src/integrations/svelte/svelte.constants.ts b/src/integrations/svelte/svelte.constants.ts
deleted file mode 100644
index 962143e..0000000
--- a/src/integrations/svelte/svelte.constants.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export const DEFAULT_DEBOUNCE_DELAY = 300;
-export const DEFAULT_PAGE_SIZE = 10;
-export const DEFAULT_INITIAL_PAGE = 1;
diff --git a/src/integrations/svelte/svelte.types.ts b/src/integrations/svelte/svelte.types.ts
deleted file mode 100644
index 2110491..0000000
--- a/src/integrations/svelte/svelte.types.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import type { Readable, Writable } from 'svelte/store';
-import type { Expression, FilterOptions } from '../../types';
-import type { PaginationResult } from '../shared';
-
-export interface UseFilterResult {
- filtered: Readable;
- isFiltering: Readable;
-}
-
-export interface UseFilteredStateResult {
- data: Writable;
- expression: Writable>;
- filtered: Readable;
- isFiltering: Readable;
-}
-
-export interface UseDebouncedFilterOptions extends FilterOptions {
- delay?: number;
-}
-
-export interface UseDebouncedFilterResult {
- filtered: Readable;
- isFiltering: Readable;
- isPending: Readable;
-}
-
-export interface UsePaginatedFilterResult {
- filtered: Readable;
- isFiltering: Readable;
- pagination: Readable>;
- currentPage: Writable;
- pageSize: Writable;
- nextPage: () => void;
- previousPage: () => void;
- goToPage: (page: number) => void;
- setPageSize: (size: number) => void;
-}
diff --git a/src/integrations/svelte/svelte.utils.ts b/src/integrations/svelte/svelte.utils.ts
deleted file mode 100644
index f891ce8..0000000
--- a/src/integrations/svelte/svelte.utils.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import type { Readable } from 'svelte/store';
-
-export function isStore(value: unknown): value is Readable {
- return (
- value !== null &&
- typeof value === 'object' &&
- 'subscribe' in value &&
- typeof (value as { subscribe: unknown }).subscribe === 'function'
- );
-}
-
-export function getValue(value: T | Readable): T {
- if (isStore(value)) {
- let currentValue: T = undefined as never;
- value.subscribe((v) => {
- currentValue = v;
- })();
- return currentValue;
- }
- return value;
-}
diff --git a/src/integrations/svelte/use-debounced-filter.test.ts b/src/integrations/svelte/use-debounced-filter.test.ts
deleted file mode 100644
index 733c60c..0000000
--- a/src/integrations/svelte/use-debounced-filter.test.ts
+++ /dev/null
@@ -1,145 +0,0 @@
-import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
-import { writable, get } from 'svelte/store';
-import { useDebouncedFilter } from './use-debounced-filter';
-
-interface TestItem {
- id: number;
- name: string;
- active: boolean;
-}
-
-describe('useDebouncedFilter', () => {
- const testData: TestItem[] = [
- { id: 1, name: 'Alice', active: true },
- { id: 2, name: 'Bob', active: false },
- { id: 3, name: 'Charlie', active: true },
- ];
-
- beforeEach(() => {
- vi.useFakeTimers();
- });
-
- afterEach(() => {
- vi.restoreAllMocks();
- });
-
- it('should debounce filter expression changes', () => {
- const data = writable(testData);
- const expression = writable('Alice');
- const { filtered, isPending } = useDebouncedFilter(data, expression, {
- delay: 300,
- });
-
- expect(get(isPending)).toBe(true);
-
- vi.advanceTimersByTime(300);
-
- expect(get(isPending)).toBe(false);
- expect(get(filtered)).toHaveLength(1);
-
- expression.set('Bob');
- expect(get(isPending)).toBe(true);
-
- vi.advanceTimersByTime(300);
-
- expect(get(isPending)).toBe(false);
- expect(get(filtered)).toHaveLength(1);
- expect(get(filtered)[0].name).toBe('Bob');
- });
-
- it('should use default delay', () => {
- const data = writable(testData);
- const expression = writable('Alice');
- const { filtered, isPending } = useDebouncedFilter(data, expression);
-
- expect(get(isPending)).toBe(true);
-
- vi.advanceTimersByTime(300);
-
- expect(get(isPending)).toBe(false);
- expect(get(filtered)).toHaveLength(1);
- });
-
- it('should handle rapid expression changes', () => {
- const data = writable(testData);
- const expression = writable('Alice');
- const { filtered, isPending } = useDebouncedFilter(data, expression, {
- delay: 300,
- });
-
- expression.set('Bob');
- vi.advanceTimersByTime(100);
-
- expression.set('Charlie');
- vi.advanceTimersByTime(100);
-
- expression.set('Alice');
- vi.advanceTimersByTime(300);
-
- expect(get(isPending)).toBe(false);
- expect(get(filtered)).toHaveLength(1);
- expect(get(filtered)[0].name).toBe('Alice');
- });
-
- it('should handle object expressions', () => {
- const data = writable(testData);
- const expression = writable({ active: true });
- const { filtered } = useDebouncedFilter(data, expression, { delay: 300 });
-
- vi.advanceTimersByTime(300);
-
- expect(get(filtered)).toHaveLength(2);
- });
-
- it('should handle predicate functions', () => {
- const data = writable(testData);
- const expression = writable((item: TestItem) => item.id > 1);
- const { filtered } = useDebouncedFilter(data, expression, { delay: 300 });
-
- vi.advanceTimersByTime(300);
-
- expect(get(filtered)).toHaveLength(2);
- });
-
- it('should respect filter options', () => {
- const data = writable(testData);
- const expression = writable('ALICE');
- const { filtered } = useDebouncedFilter(data, expression, {
- delay: 300,
- caseSensitive: true,
- });
-
- vi.advanceTimersByTime(300);
-
- expect(get(filtered)).toEqual([]);
- });
-
- it('should handle empty data', () => {
- const data = writable([]);
- const expression = writable('test');
- const { filtered } = useDebouncedFilter(data, expression, { delay: 300 });
-
- vi.advanceTimersByTime(300);
-
- expect(get(filtered)).toEqual([]);
- });
-
- it('should indicate filtering status', () => {
- const data = writable(testData);
- const expression = writable({ active: true });
- const { isFiltering } = useDebouncedFilter(data, expression, { delay: 300 });
-
- vi.advanceTimersByTime(300);
-
- expect(get(isFiltering)).toBe(true);
- });
-
- it('should work with non-store values', () => {
- const expression = writable('Alice');
- const { filtered } = useDebouncedFilter(testData, expression, { delay: 300 });
-
- vi.advanceTimersByTime(300);
-
- expect(get(filtered)).toHaveLength(1);
- });
-});
diff --git a/src/integrations/svelte/use-debounced-filter.ts b/src/integrations/svelte/use-debounced-filter.ts
deleted file mode 100644
index 0e968dc..0000000
--- a/src/integrations/svelte/use-debounced-filter.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import { writable, derived, readable, type Readable } from 'svelte/store';
-import { filter } from '../../core';
-import type { Expression } from '../../types';
-import type { UseDebouncedFilterOptions, UseDebouncedFilterResult } from './svelte.types';
-import { DEFAULT_DEBOUNCE_DELAY } from './svelte.constants';
-import { debounce } from '../shared';
-import { isStore } from './svelte.utils';
-
-export function useDebouncedFilter(
- data: T[] | Readable,
- expression: Expression | Readable>,
- options?: UseDebouncedFilterOptions,
-): UseDebouncedFilterResult {
- const { delay = DEFAULT_DEBOUNCE_DELAY, ...filterOptions } = options || {};
- const debouncedExpression = writable>(
- isStore(expression) ? ((() => true) as Expression) : expression,
- );
- const isPending = writable(false);
-
- const dataStore = isStore(data) ? data : readable(data);
- const expressionStore = isStore(expression) ? expression : readable(expression);
-
- const debouncedUpdate = debounce((expr: Expression) => {
- debouncedExpression.set(expr);
- isPending.set(false);
- }, delay) as ((expr: Expression) => void) & { cancel: () => void };
-
- if (isStore(expression)) {
- expressionStore.subscribe((expr) => {
- isPending.set(true);
- debouncedUpdate(expr);
- });
- }
-
- const filtered = derived([dataStore, debouncedExpression], ([$data, $expression]) => {
- if (!$data || $data.length === 0) {
- return [] as T[];
- }
-
- try {
- return filter($data, $expression, filterOptions);
- } catch {
- return [] as T[];
- }
- }) as Readable;
-
- const isFiltering = derived([dataStore, filtered], ([$data, $filtered]) => {
- return $filtered.length !== $data.length;
- }) as Readable;
-
- return {
- filtered,
- isFiltering,
- isPending: { subscribe: isPending.subscribe },
- };
-}
diff --git a/src/integrations/svelte/use-filter.test.ts b/src/integrations/svelte/use-filter.test.ts
deleted file mode 100644
index a10c7c3..0000000
--- a/src/integrations/svelte/use-filter.test.ts
+++ /dev/null
@@ -1,107 +0,0 @@
-import { describe, it, expect } from 'vitest';
-import { writable, get } from 'svelte/store';
-import { useFilter } from './use-filter';
-
-interface TestItem {
- id: number;
- name: string;
- active: boolean;
-}
-
-describe('useFilter', () => {
- const testData: TestItem[] = [
- { id: 1, name: 'Alice', active: true },
- { id: 2, name: 'Bob', active: false },
- { id: 3, name: 'Charlie', active: true },
- ];
-
- it('should filter data with string expression', () => {
- const data = writable(testData);
- const expression = writable('Alice');
- const { filtered, isFiltering } = useFilter(data, expression);
-
- expect(get(filtered)).toEqual([{ id: 1, name: 'Alice', active: true }]);
- expect(get(isFiltering)).toBe(true);
- });
-
- it('should filter data with object expression', () => {
- const data = writable(testData);
- const expression = writable({ active: true });
- const { filtered, isFiltering } = useFilter(data, expression);
-
- expect(get(filtered)).toHaveLength(2);
- expect(get(isFiltering)).toBe(true);
- });
-
- it('should filter data with predicate function', () => {
- const data = writable(testData);
- const expression = writable((item: TestItem) => item.id > 1);
- const { filtered } = useFilter(data, expression);
-
- expect(get(filtered)).toHaveLength(2);
- });
-
- it('should return empty array for empty data', () => {
- const data = writable([]);
- const expression = writable('test');
- const { filtered, isFiltering } = useFilter(data, expression);
-
- expect(get(filtered)).toEqual([]);
- expect(get(isFiltering)).toBe(false);
- });
-
- it('should handle invalid expression gracefully', () => {
- const data = writable(testData);
- const expression = writable(null as never);
- const { filtered } = useFilter(data, expression);
-
- expect(get(filtered)).toEqual([]);
- });
-
- it('should react to data changes', () => {
- const data = writable(testData);
- const expression = writable({ active: true });
- const { filtered } = useFilter(data, expression);
-
- expect(get(filtered)).toHaveLength(2);
-
- data.set([...testData, { id: 4, name: 'David', active: true }]);
-
- expect(get(filtered)).toHaveLength(3);
- });
-
- it('should react to expression changes', () => {
- const data = writable(testData);
- const expression = writable>({ active: true });
- const { filtered } = useFilter(data, expression);
-
- expect(get(filtered)).toHaveLength(2);
-
- expression.set({ active: false });
-
- expect(get(filtered)).toHaveLength(1);
- });
-
- it('should respect filter options', () => {
- const data = writable(testData);
- const expression = writable('ALICE');
- const { filtered } = useFilter(data, expression, { caseSensitive: true });
-
- expect(get(filtered)).toEqual([]);
- });
-
- it('should work with non-store values', () => {
- const { filtered } = useFilter(testData, 'Alice');
-
- expect(get(filtered)).toHaveLength(1);
- });
-
- it('should indicate when not filtering', () => {
- const data = writable(testData);
- const expression = writable(() => true);
- const { filtered, isFiltering } = useFilter(data, expression);
-
- expect(get(filtered)).toHaveLength(3);
- expect(get(isFiltering)).toBe(false);
- });
-});
diff --git a/src/integrations/svelte/use-filter.ts b/src/integrations/svelte/use-filter.ts
deleted file mode 100644
index 441010c..0000000
--- a/src/integrations/svelte/use-filter.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import { derived, readable, type Readable } from 'svelte/store';
-import { filter } from '../../core';
-import type { Expression, FilterOptions } from '../../types';
-import type { UseFilterResult } from './svelte.types';
-import { isStore } from './svelte.utils';
-
-export function useFilter(
- data: T[] | Readable,
- expression: Expression | Readable>,
- options?: FilterOptions,
-): UseFilterResult {
- const dataStore = isStore(data) ? data : readable(data);
- const expressionStore = isStore(expression) ? expression : readable(expression);
-
- const filtered = derived([dataStore, expressionStore], ([$data, $expression]) => {
- if (!$data || $data.length === 0) {
- return [] as T[];
- }
-
- try {
- return filter($data, $expression, options);
- } catch {
- return [] as T[];
- }
- }) as Readable;
-
- const isFiltering = derived([dataStore, filtered], ([$data, $filtered]) => {
- return $filtered.length !== $data.length;
- }) as Readable;
-
- return {
- filtered,
- isFiltering,
- };
-}
diff --git a/src/integrations/svelte/use-filtered-state.test.ts b/src/integrations/svelte/use-filtered-state.test.ts
deleted file mode 100644
index 3904f98..0000000
--- a/src/integrations/svelte/use-filtered-state.test.ts
+++ /dev/null
@@ -1,116 +0,0 @@
-import { describe, it, expect } from 'vitest';
-import { get } from 'svelte/store';
-import { useFilteredState } from './use-filtered-state';
-
-interface TestItem {
- id: number;
- name: string;
- active: boolean;
-}
-
-describe('useFilteredState', () => {
- const testData: TestItem[] = [
- { id: 1, name: 'Alice', active: true },
- { id: 2, name: 'Bob', active: false },
- { id: 3, name: 'Charlie', active: true },
- ];
-
- it('should initialize with default values', () => {
- const { data, filtered, isFiltering } = useFilteredState();
-
- expect(get(data)).toEqual([]);
- expect(get(filtered)).toEqual([]);
- expect(get(isFiltering)).toBe(false);
- });
-
- it('should initialize with provided data', () => {
- const { data, filtered } = useFilteredState(testData);
-
- expect(get(data)).toEqual(testData);
- expect(get(filtered)).toEqual(testData);
- });
-
- it('should filter data with initial expression', () => {
- const { filtered, isFiltering } = useFilteredState(testData, { active: true });
-
- expect(get(filtered)).toHaveLength(2);
- expect(get(isFiltering)).toBe(true);
- });
-
- it('should update data', () => {
- const { data, filtered } = useFilteredState(testData);
-
- data.set([{ id: 4, name: 'David', active: false }]);
-
- expect(get(data)).toHaveLength(1);
- expect(get(data)[0].name).toBe('David');
- expect(get(filtered)).toHaveLength(1);
- });
-
- it('should update expression', () => {
- const { expression, filtered } = useFilteredState(testData, { active: true });
-
- expect(get(filtered)).toHaveLength(2);
-
- expression.set({ active: false });
-
- expect(get(filtered)).toHaveLength(1);
- });
-
- it('should update filtered results when data changes', () => {
- const { data, filtered } = useFilteredState(testData, { active: true });
-
- expect(get(filtered)).toHaveLength(2);
-
- data.set([...testData, { id: 4, name: 'David', active: true }]);
-
- expect(get(filtered)).toHaveLength(3);
- });
-
- it('should update filtered results when expression changes', () => {
- const { expression, filtered } = useFilteredState(testData);
-
- expect(get(filtered)).toHaveLength(3);
-
- expression.set('Alice');
-
- expect(get(filtered)).toHaveLength(1);
- });
-
- it('should handle predicate function expressions', () => {
- const { expression, filtered } = useFilteredState(testData, (item) => item.id > 1);
-
- expect(get(filtered)).toHaveLength(2);
-
- expression.set((item) => item.id === 1);
-
- expect(get(filtered)).toHaveLength(1);
- });
-
- it('should respect filter options', () => {
- const { filtered } = useFilteredState(testData, 'ALICE', {
- caseSensitive: true,
- });
-
- expect(get(filtered)).toEqual([]);
- });
-
- it('should handle empty data gracefully', () => {
- const { filtered, isFiltering } = useFilteredState([], 'test');
-
- expect(get(filtered)).toEqual([]);
- expect(get(isFiltering)).toBe(false);
- });
-
- it('should be reactive', () => {
- const { data, expression, filtered } = useFilteredState(testData);
-
- expect(get(filtered)).toHaveLength(3);
-
- expression.set({ active: true });
- expect(get(filtered)).toHaveLength(2);
-
- data.set(testData.slice(0, 1));
- expect(get(filtered)).toHaveLength(1);
- });
-});
diff --git a/src/integrations/svelte/use-filtered-state.ts b/src/integrations/svelte/use-filtered-state.ts
deleted file mode 100644
index 935db3c..0000000
--- a/src/integrations/svelte/use-filtered-state.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { writable, derived } from 'svelte/store';
-import { filter } from '../../core';
-import type { Expression, FilterOptions } from '../../types';
-import type { UseFilteredStateResult } from './svelte.types';
-
-export function useFilteredState(
- initialData: T[] = [],
- initialExpression: Expression = () => true,
- options?: FilterOptions,
-): UseFilteredStateResult {
- const data = writable(initialData);
- const expression = writable>(initialExpression);
-
- const filtered = derived([data, expression], ([$data, $expression]) => {
- if (!$data || $data.length === 0) {
- return [];
- }
-
- try {
- return filter($data, $expression, options);
- } catch {
- return [];
- }
- });
-
- const isFiltering = derived([data, filtered], ([$data, $filtered]) => {
- return $filtered.length !== $data.length;
- });
-
- return {
- data,
- expression,
- filtered,
- isFiltering,
- };
-}
diff --git a/src/integrations/svelte/use-paginated-filter.test.ts b/src/integrations/svelte/use-paginated-filter.test.ts
deleted file mode 100644
index 9325bee..0000000
--- a/src/integrations/svelte/use-paginated-filter.test.ts
+++ /dev/null
@@ -1,195 +0,0 @@
-import { describe, it, expect } from 'vitest';
-import { writable, get } from 'svelte/store';
-import { usePaginatedFilter } from './use-paginated-filter';
-
-interface TestItem {
- id: number;
- name: string;
- active: boolean;
-}
-
-describe('usePaginatedFilter', () => {
- const testData: TestItem[] = Array.from({ length: 25 }, (_, i) => ({
- id: i + 1,
- name: `User ${i + 1}`,
- active: i % 2 === 0,
- }));
-
- it('should paginate filtered data', () => {
- const data = writable(testData);
- const expression = writable(() => true);
- const { pagination } = usePaginatedFilter(data, expression, 10);
-
- const paginationValue = get(pagination);
- expect(paginationValue.data).toHaveLength(10);
- expect(paginationValue.currentPage).toBe(1);
- expect(paginationValue.totalPages).toBe(3);
- expect(paginationValue.totalItems).toBe(25);
- });
-
- it('should navigate to next page', () => {
- const data = writable(testData);
- const expression = writable(() => true);
- const { pagination, nextPage, currentPage } = usePaginatedFilter(data, expression, 10);
-
- nextPage();
-
- expect(get(currentPage)).toBe(2);
- expect(get(pagination).data[0].id).toBe(11);
- });
-
- it('should navigate to previous page', () => {
- const data = writable(testData);
- const expression = writable(() => true);
- const { previousPage, nextPage, currentPage } = usePaginatedFilter(data, expression, 10);
-
- nextPage();
- previousPage();
-
- expect(get(currentPage)).toBe(1);
- });
-
- it('should go to specific page', () => {
- const data = writable(testData);
- const expression = writable(() => true);
- const { pagination, goToPage, currentPage } = usePaginatedFilter(data, expression, 10);
-
- goToPage(3);
-
- expect(get(currentPage)).toBe(3);
- expect(get(pagination).data).toHaveLength(5);
- });
-
- it('should not exceed total pages', () => {
- const data = writable(testData);
- const expression = writable(() => true);
- const { goToPage, currentPage } = usePaginatedFilter(data, expression, 10);
-
- goToPage(10);
-
- expect(get(currentPage)).toBe(3);
- });
-
- it('should not go below page 1', () => {
- const data = writable(testData);
- const expression = writable(() => true);
- const { previousPage, currentPage } = usePaginatedFilter(data, expression, 10);
-
- previousPage();
-
- expect(get(currentPage)).toBe(1);
- });
-
- it('should change page size', () => {
- const data = writable(testData);
- const expression = writable(() => true);
- const { pagination, setPageSize, currentPage, pageSize } = usePaginatedFilter(
- data,
- expression,
- 10,
- );
-
- setPageSize(5);
-
- expect(get(pageSize)).toBe(5);
- expect(get(pagination).data).toHaveLength(5);
- expect(get(pagination).totalPages).toBe(5);
- expect(get(currentPage)).toBe(1);
- });
-
- it('should filter and paginate', () => {
- const data = writable(testData);
- const expression = writable({ active: true });
- const { pagination, isFiltering } = usePaginatedFilter(data, expression, 5);
-
- const paginationValue = get(pagination);
- expect(paginationValue.totalItems).toBe(13);
- expect(paginationValue.totalPages).toBe(3);
- expect(get(isFiltering)).toBe(true);
- });
-
- it('should update pagination when filter changes', () => {
- const data = writable(testData);
- const expression = writable<{ active: boolean }>({ active: true });
- const { pagination } = usePaginatedFilter(data, expression, 5);
-
- expect(get(pagination).totalItems).toBe(13);
-
- expression.set({ active: false });
-
- expect(get(pagination).totalItems).toBe(12);
- });
-
- it('should indicate next page availability', () => {
- const data = writable(testData);
- const expression = writable(() => true);
- const { pagination, goToPage } = usePaginatedFilter(data, expression, 10);
-
- expect(get(pagination).hasNextPage).toBe(true);
-
- goToPage(3);
-
- expect(get(pagination).hasNextPage).toBe(false);
- });
-
- it('should indicate previous page availability', () => {
- const data = writable(testData);
- const expression = writable(() => true);
- const { pagination, nextPage } = usePaginatedFilter(data, expression, 10);
-
- expect(get(pagination).hasPreviousPage).toBe(false);
-
- nextPage();
-
- expect(get(pagination).hasPreviousPage).toBe(true);
- });
-
- it('should handle empty data', () => {
- const data = writable([]);
- const expression = writable(() => true);
- const { pagination } = usePaginatedFilter(data, expression, 10);
-
- const paginationValue = get(pagination);
- expect(paginationValue.data).toEqual([]);
- expect(paginationValue.totalPages).toBe(0);
- expect(paginationValue.totalItems).toBe(0);
- });
-
- it('should handle single page', () => {
- const smallData = testData.slice(0, 5);
- const data = writable(smallData);
- const expression = writable(() => true);
- const { pagination } = usePaginatedFilter(data, expression, 10);
-
- const paginationValue = get(pagination);
- expect(paginationValue.data).toHaveLength(5);
- expect(paginationValue.totalPages).toBe(1);
- expect(paginationValue.hasNextPage).toBe(false);
- expect(paginationValue.hasPreviousPage).toBe(false);
- });
-
- it('should validate page size', () => {
- const data = writable(testData);
- const expression = writable(() => true);
- const { pageSize } = usePaginatedFilter(data, expression, -5);
-
- expect(get(pageSize)).toBe(1);
- });
-
- it('should reset to page 1 when changing page size', () => {
- const data = writable(testData);
- const expression = writable(() => true);
- const { goToPage, setPageSize, currentPage } = usePaginatedFilter(data, expression, 10);
-
- goToPage(2);
- setPageSize(5);
-
- expect(get(currentPage)).toBe(1);
- });
-
- it('should work with non-store values', () => {
- const { pagination } = usePaginatedFilter(testData, () => true, 10);
-
- expect(get(pagination).data).toHaveLength(10);
- });
-});
diff --git a/src/integrations/svelte/use-paginated-filter.ts b/src/integrations/svelte/use-paginated-filter.ts
deleted file mode 100644
index 0a58983..0000000
--- a/src/integrations/svelte/use-paginated-filter.ts
+++ /dev/null
@@ -1,103 +0,0 @@
-import { writable, derived, readable, get, type Readable } from 'svelte/store';
-import { filter } from '../../core';
-import type { Expression, FilterOptions } from '../../types';
-import type { UsePaginatedFilterResult } from './svelte.types';
-import { DEFAULT_PAGE_SIZE, DEFAULT_INITIAL_PAGE } from './svelte.constants';
-import {
- getPageData,
- createPaginationResult,
- validatePageNumber,
- validatePageSize,
- type PaginationResult,
-} from '../shared';
-import { isStore } from './svelte.utils';
-
-export function usePaginatedFilter(
- data: T[] | Readable,
- expression: Expression | Readable>,
- initialPageSize: number = DEFAULT_PAGE_SIZE,
- options?: FilterOptions,
-): UsePaginatedFilterResult {
- const currentPage = writable(DEFAULT_INITIAL_PAGE);
- const pageSize = writable(validatePageSize(initialPageSize));
-
- const dataStore = isStore(data) ? data : readable(data);
- const expressionStore = isStore(expression) ? expression : readable(expression);
-
- const filtered = derived([dataStore, expressionStore], ([$data, $expression]) => {
- if (!$data || $data.length === 0) {
- return [] as T[];
- }
-
- try {
- return filter($data, $expression, options);
- } catch {
- return [] as T[];
- }
- }) as Readable;
-
- const isFiltering = derived([dataStore, filtered], ([$data, $filtered]) => {
- return $filtered.length !== $data.length;
- }) as Readable;
-
- const paginationState = derived(
- [currentPage, pageSize, filtered],
- ([$currentPage, $pageSize, $filtered]) => ({
- currentPage: $currentPage,
- pageSize: $pageSize,
- totalItems: ($filtered as T[]).length,
- }),
- );
-
- const pageData = derived(
- [filtered, currentPage, pageSize],
- ([$filtered, $currentPage, $pageSize]) => {
- return getPageData($filtered as T[], $currentPage, $pageSize);
- },
- );
-
- const pagination = derived(
- [pageData, filtered, paginationState],
- ([$pageData, $filtered, $paginationState]) => {
- return createPaginationResult($pageData, $filtered as T[], $paginationState);
- },
- ) as Readable>;
-
- const nextPage = (): void => {
- currentPage.update((page) => {
- const totalPages = get(pagination).totalPages;
- return validatePageNumber(page + 1, totalPages);
- });
- };
-
- const previousPage = (): void => {
- currentPage.update((page) => {
- const totalPages = get(pagination).totalPages;
- return validatePageNumber(page - 1, totalPages);
- });
- };
-
- const goToPage = (page: number): void => {
- const totalPages = get(pagination).totalPages;
- const validated = validatePageNumber(page, totalPages);
- currentPage.set(validated);
- };
-
- const setPageSize = (size: number): void => {
- const validated = validatePageSize(size);
- pageSize.set(validated);
- currentPage.set(DEFAULT_INITIAL_PAGE);
- };
-
- return {
- filtered,
- isFiltering,
- pagination,
- currentPage,
- pageSize,
- nextPage,
- previousPage,
- goToPage,
- setPageSize,
- };
-}
From d996095deb341c4d9942c6f7ba5e32fb88b1a5c4 Mon Sep 17 00:00:00 2001
From: Miguelangel Cabrera
Date: Sat, 21 Mar 2026 19:37:48 -0300
Subject: [PATCH 2/4] refactor: streamline pre-commit checks and update
package.json scripts
---
.husky/pre-commit | 2 ++
package.json | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/.husky/pre-commit b/.husky/pre-commit
index 87c6b93..f6e6e4e 100755
--- a/.husky/pre-commit
+++ b/.husky/pre-commit
@@ -5,5 +5,7 @@ pnpm exec lint-staged
echo "📝 Type checking..."
pnpm run typecheck
+pnpm run test
+pnpm run test:docs
echo "✅ Pre-commit checks passed!"
diff --git a/package.json b/package.json
index c9e5b73..6da0eb7 100644
--- a/package.json
+++ b/package.json
@@ -22,7 +22,7 @@
"size": "size-limit",
"size:why": "size-limit --why",
"analyze": "pnpm run size:why",
- "check": "pnpm exec lint-staged && pnpm run test && pnpm run test:types && pnpm run typecheck && pnpm run lint && pnpm run test:docs",
+ "check": "pnpm exec lint-staged && pnpm run test:types && pnpm run typecheck && pnpm run lint",
"prepare": "husky",
"prepublish": "pnpm run check",
"version": "pnpm run format && git add src/",
From 20cc26a942ff7ca3123ad69e853f68753d33c184 Mon Sep 17 00:00:00 2001
From: Miguelangel Cabrera
Date: Sat, 21 Mar 2026 19:43:43 -0300
Subject: [PATCH 3/4] chore: sync pnpm lockfile after svelte removal
---
pnpm-lock.yaml | 32 +++++++++++++++++++++-----------
1 file changed, 21 insertions(+), 11 deletions(-)
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 85994a9..1df2b76 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -107,9 +107,6 @@ importers:
solid-js:
specifier: ^1.9.11
version: 1.9.11
- svelte:
- specifier: ^5.54.1
- version: 5.54.1
tsd:
specifier: ^0.33.0
version: 0.33.0
@@ -3651,6 +3648,7 @@ snapshots:
dependencies:
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
+ optional: true
'@jridgewell/resolve-uri@3.1.2': {}
@@ -3833,6 +3831,7 @@ snapshots:
'@sveltejs/acorn-typescript@1.0.6(acorn@8.15.0)':
dependencies:
acorn: 8.15.0
+ optional: true
'@testing-library/dom@10.4.1':
dependencies:
@@ -3945,7 +3944,8 @@ snapshots:
'@types/prop-types': 15.7.15
csstype: 3.1.3
- '@types/trusted-types@2.0.7': {}
+ '@types/trusted-types@2.0.7':
+ optional: true
'@types/unist@2.0.11': {}
@@ -4318,7 +4318,8 @@ snapshots:
dependencies:
dequal: 2.0.3
- aria-query@5.3.1: {}
+ aria-query@5.3.1:
+ optional: true
array-buffer-byte-length@1.0.2:
dependencies:
@@ -4347,7 +4348,8 @@ snapshots:
dependencies:
possible-typed-array-names: 1.1.0
- axobject-query@4.1.0: {}
+ axobject-query@4.1.0:
+ optional: true
bail@1.0.5: {}
@@ -4443,7 +4445,8 @@ snapshots:
slice-ansi: 7.1.2
string-width: 8.1.0
- clsx@2.1.1: {}
+ clsx@2.1.1:
+ optional: true
color-convert@2.0.1:
dependencies:
@@ -4558,7 +4561,8 @@ snapshots:
dequal@2.0.3: {}
- devalue@5.6.4: {}
+ devalue@5.6.4:
+ optional: true
devlop@1.1.0:
dependencies:
@@ -4822,7 +4826,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
- esm-env@1.2.2: {}
+ esm-env@1.2.2:
+ optional: true
espree@10.4.0:
dependencies:
@@ -4838,6 +4843,7 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
'@typescript-eslint/types': 8.57.1
+ optional: true
esrecurse@4.3.0:
dependencies:
@@ -5220,6 +5226,7 @@ snapshots:
is-reference@3.0.3:
dependencies:
'@types/estree': 1.0.8
+ optional: true
is-regex@1.2.1:
dependencies:
@@ -5391,7 +5398,8 @@ snapshots:
rfdc: 1.4.1
wrap-ansi: 9.0.2
- locate-character@3.0.0: {}
+ locate-character@3.0.0:
+ optional: true
locate-path@5.0.0:
dependencies:
@@ -6280,6 +6288,7 @@ snapshots:
locate-character: 3.0.0
magic-string: 0.30.21
zimmerframe: 1.1.4
+ optional: true
symbol-tree@3.2.4: {}
@@ -6741,7 +6750,8 @@ snapshots:
yocto-queue@0.1.0: {}
- zimmerframe@1.1.4: {}
+ zimmerframe@1.1.4:
+ optional: true
zod@4.1.12: {}
From 60fc69e933c172c8325e473e81d58bcd62d025eb Mon Sep 17 00:00:00 2001
From: Miguelangel Cabrera
Date: Sat, 21 Mar 2026 19:51:42 -0300
Subject: [PATCH 4/4] chore: update changelog for Svelte removal and workflow
improvements
---
README.md | 307 +++++++++++++++++++++-----------------
docs/project/changelog.md | 76 +++++++++-
2 files changed, 246 insertions(+), 137 deletions(-)
diff --git a/README.md b/README.md
index b7ac547..3a872cf 100644
--- a/README.md
+++ b/README.md
@@ -32,63 +32,66 @@
---
+
+
## Table of Contents
-- [@mcabreradev/filter](#mcabreradevfilter)
- - [The Problem](#the-problem)
- - [Quick Start](#quick-start)
- - [Install](#install)
- - [Your First Filter](#your-first-filter)
- - [Why You'll Love It](#why-youll-love-it)
- - [🚀 **Blazing Fast**](#-blazing-fast)
- - [🎯 **Developer Friendly**](#-developer-friendly)
- - [🔧 **Incredibly Flexible**](#-incredibly-flexible)
- - [📦 **Production Ready**](#-production-ready)
- - [🪶 **Ultra Lightweight**](#-ultra-lightweight)
- - [🔒 **Type-Safe by Default**](#-type-safe-by-default)
- - [🎨 **Framework Agnostic**](#-framework-agnostic)
- - [📊 **Handles Big Data**](#-handles-big-data)
- - [Examples](#examples)
- - [Basic Filtering](#basic-filtering)
- - [MongoDB-Style Operators](#mongodb-style-operators)
- - [Array OR Syntax (Intuitive!)](#array-or-syntax-intuitive)
- - [Geospatial Queries](#geospatial-queries)
- - [Datetime Filtering](#datetime-filtering)
- - [Performance Optimization](#performance-optimization)
- - [Real-World: E-commerce Search](#real-world-e-commerce-search)
- - [Framework Integrations](#framework-integrations)
- - [React](#react)
- - [Vue](#vue)
- - [Svelte](#svelte)
- - [Angular](#angular)
- - [SolidJS](#solidjs)
- - [Preact](#preact)
- - [Core Features](#core-features)
- - [Supported Operators](#supported-operators)
- - [TypeScript Support](#typescript-support)
- - [Configuration Options](#configuration-options)
- - [Advanced Features](#advanced-features)
- - [Lazy Evaluation](#lazy-evaluation)
- - [Memoization & Caching](#memoization--caching)
- - [Visual Debugging](#visual-debugging)
- - [Documentation](#documentation)
- - [📖 Complete Guides](#-complete-guides)
- - [🎯 Quick Links](#-quick-links)
- - [Performance](#performance)
- - [Bundle Size](#bundle-size)
- - [Browser Support](#browser-support)
- - [Migration from v3.x](#migration-from-v3x)
- - [Changelog](#changelog)
- - [v5.8.2 (Current)](#v582-current)
- - [v5.8.0](#v580)
- - [v5.7.0](#v570)
- - [v5.6.0](#v560)
- - [v5.5.0](#v550)
- - [Contributing](#contributing)
- - [License](#license)
- - [Support](#support)
+- [The Problem](#the-problem)
+- [Quick Start](#quick-start)
+ - [Install](#install)
+ - [Your First Filter](#your-first-filter)
+- [Why You'll Love It](#why-youll-love-it)
+ - [🚀 **Blazing Fast**](#-blazing-fast)
+ - [🎯 **Developer Friendly**](#-developer-friendly)
+ - [🔧 **Incredibly Flexible**](#-incredibly-flexible)
+ - [📦 **Production Ready**](#-production-ready)
+ - [🪶 **Ultra Lightweight**](#-ultra-lightweight)
+ - [🔒 **Type-Safe by Default**](#-type-safe-by-default)
+ - [🎨 **Framework Agnostic**](#-framework-agnostic)
+ - [📊 **Handles Big Data**](#-handles-big-data)
+- [Examples](#examples)
+ - [Basic Filtering](#basic-filtering)
+ - [MongoDB-Style Operators](#mongodb-style-operators)
+ - [Array OR Syntax (Intuitive!)](#array-or-syntax-intuitive)
+ - [Geospatial Queries](#geospatial-queries)
+ - [Datetime Filtering](#datetime-filtering)
+ - [Performance Optimization](#performance-optimization)
+ - [Real-World: E-commerce Search](#real-world-e-commerce-search)
+- [Framework Integrations](#framework-integrations)
+ - [React](#react)
+ - [Vue](#vue)
+ - [Svelte](#svelte)
+ - [Angular](#angular)
+ - [SolidJS](#solidjs)
+ - [Preact](#preact)
+- [Core Features](#core-features)
+ - [Supported Operators](#supported-operators)
+ - [TypeScript Support](#typescript-support)
+ - [Configuration Options](#configuration-options)
+- [Advanced Features](#advanced-features)
+ - [Lazy Evaluation](#lazy-evaluation)
+ - [Memoization & Caching](#memoization--caching)
+ - [Visual Debugging](#visual-debugging)
+- [Documentation](#documentation)
+ - [📖 Complete Guides](#-complete-guides)
+ - [🎯 Quick Links](#-quick-links)
+- [Performance](#performance)
+- [Bundle Size](#bundle-size)
+- [Browser Support](#browser-support)
+- [Migration from v3.x](#migration-from-v3x)
+- [Changelog](#changelog)
+ - [v5.9.2 (Current)](#v592-current)
+ - [v5.9.1](#v591)
+ - [v5.8.2](#v582)
+ - [v5.8.0](#v580)
+ - [v5.7.0](#v570)
+ - [v5.6.0](#v560)
+ - [v5.5.0](#v550)
+- [Contributing](#contributing)
+- [License](#license)
+- [Support](#support)
@@ -99,24 +102,27 @@
**Tired of writing complex filter logic?** Stop wrestling with nested `Array.filter()` chains and verbose conditionals. Write clean, declarative filters that read like queries.
**Before — the usual mess:**
+
```typescript
-const results = data.filter(item =>
- item.age >= 18 &&
- item.status === 'active' &&
- (item.role === 'admin' || item.role === 'moderator') &&
- item.email.endsWith('@company.com') &&
- item.createdAt >= thirtyDaysAgo
+const results = data.filter(
+ (item) =>
+ item.age >= 18 &&
+ item.status === 'active' &&
+ (item.role === 'admin' || item.role === 'moderator') &&
+ item.email.endsWith('@company.com') &&
+ item.createdAt >= thirtyDaysAgo,
);
```
**After — clean and declarative:**
+
```typescript
const results = filter(data, {
age: { $gte: 18 },
status: 'active',
role: ['admin', 'moderator'],
email: { $endsWith: '@company.com' },
- createdAt: { $gte: thirtyDaysAgo }
+ createdAt: { $gte: thirtyDaysAgo },
});
```
@@ -146,7 +152,7 @@ import { filter } from '@mcabreradev/filter';
const users = [
{ name: 'Alice', age: 30, city: 'Berlin', active: true },
{ name: 'Bob', age: 25, city: 'London', active: false },
- { name: 'Charlie', age: 35, city: 'Berlin', active: true }
+ { name: 'Charlie', age: 35, city: 'Berlin', active: true },
];
// Simple string search — scans all fields
@@ -173,43 +179,51 @@ const startsWithAl = filter(users, 'Al%');
## Why You'll Love It
### 🚀 **Blazing Fast**
+
- **530x faster** on repeated queries with optional LRU caching
- **500x faster** with lazy evaluation for large datasets
- Compiled predicates and regex patterns cached automatically
### 🎯 **Developer Friendly**
+
- Intuitive API — reads like English
- SQL-like wildcards (`%`, `_`) you already know
- Full TypeScript generics with intelligent autocomplete
### 🔧 **Incredibly Flexible**
+
- Four filtering strategies: strings, objects, operators, predicates
- Combine them seamlessly in a single expression
- Works with any data shape — flat, nested, arrays
### 📦 **Production Ready**
+
- **1,004+ tests** ensuring bulletproof reliability
- Zero runtime dependencies (only Zod for optional validation)
- Battle-tested in production applications
- MIT licensed
### 🪶 **Ultra Lightweight**
+
- Full package: **12KB gzipped**
- Core only: **8.4KB gzipped**
- Zero mandatory dependencies
- Tree-shakeable — only pay for what you use
### 🔒 **Type-Safe by Default**
+
- Built with strict TypeScript
- Catch errors at compile time, not runtime
- Full IntelliSense for operators based on field types
### 🎨 **Framework Agnostic**
+
- First-class hooks: React, Vue, Svelte, Angular, SolidJS, Preact
- Debounced search, pagination, and reactive state out of the box
- SSR compatible: Next.js, Nuxt, SvelteKit
### 📊 **Handles Big Data**
+
- Generator-based lazy evaluation for millions of records
- Early exit — stop processing when you have enough results
- LRU caches with TTL prevent memory leaks in long-running apps
@@ -228,10 +242,10 @@ filter(products, 'Laptop');
filter(products, { category: 'Electronics', price: { $lt: 1000 } });
// SQL wildcard patterns
-filter(users, '%alice%'); // contains 'alice'
-filter(users, 'Al%'); // starts with 'Al'
-filter(users, '%son'); // ends with 'son'
-filter(users, 'J_hn'); // single-char wildcard
+filter(users, '%alice%'); // contains 'alice'
+filter(users, 'Al%'); // starts with 'Al'
+filter(users, '%son'); // ends with 'son'
+filter(users, 'J_hn'); // single-char wildcard
// Predicate functions — full control
filter(users, (u) => u.score > 90 && u.verified);
@@ -253,15 +267,12 @@ filter(products, { sizes: { $size: 3 } });
filter(users, {
email: { $endsWith: '@company.com' },
name: { $startsWith: 'John' },
- bio: { $regex: /developer/i }
+ bio: { $regex: /developer/i },
});
// Logical combinators
filter(products, {
- $and: [
- { inStock: true },
- { $or: [{ rating: { $gte: 4.5 } }, { price: { $lt: 50 } }] }
- ]
+ $and: [{ inStock: true }, { $or: [{ rating: { $gte: 4.5 } }, { price: { $lt: 50 } }] }],
});
// Negate with $not
@@ -278,7 +289,7 @@ filter(products, { category: ['Electronics', 'Books'] });
// Combine across fields
filter(users, {
city: ['Berlin', 'Paris', 'London'],
- role: ['admin', 'moderator']
+ role: ['admin', 'moderator'],
});
```
@@ -292,7 +303,7 @@ const userLocation: GeoPoint = { lat: 52.52, lng: 13.405 };
// Find restaurants within 5km rated 4.5+
filter(restaurants, {
location: { $near: { center: userLocation, maxDistanceMeters: 5000 } },
- rating: { $gte: 4.5 }
+ rating: { $gte: 4.5 },
});
// Bounding box search
@@ -300,9 +311,9 @@ filter(places, {
location: {
$geoBox: {
topLeft: { lat: 53.0, lng: 13.0 },
- bottomRight: { lat: 52.0, lng: 14.0 }
- }
- }
+ bottomRight: { lat: 52.0, lng: 14.0 },
+ },
+ },
});
```
@@ -317,8 +328,8 @@ filter(logs, { createdAt: { $recent: { hours: 24 } } });
// Weekday events during business hours
filter(events, {
- date: { $dayOfWeek: [1, 2, 3, 4, 5] }, // Mon–Fri
- startTime: { $timeOfDay: { start: 9, end: 17 } } // 9am–5pm
+ date: { $dayOfWeek: [1, 2, 3, 4, 5] }, // Mon–Fri
+ startTime: { $timeOfDay: { start: 9, end: 17 } }, // 9am–5pm
});
// Users of age 18–65
@@ -338,15 +349,15 @@ filter(tasks, { dueDate: { $isBefore: new Date('2025-12-31') } });
const results = filter(largeDataset, expression, {
enableCache: true,
orderBy: { field: 'price', direction: 'desc' },
- limit: 100
+ limit: 100,
});
// Lazy evaluation — process millions of records without loading all into memory
import { filterFirst, filterExists, filterCount, filterLazy } from '@mcabreradev/filter';
const first10 = filterFirst(millionRecords, { premium: true }, 10);
-const hasAdmin = filterExists(users, { role: 'admin' }); // exits on first match
-const activeCount = filterCount(users, { active: true }); // no array allocated
+const hasAdmin = filterExists(users, { role: 'admin' }); // exits on first match
+const activeCount = filterCount(users, { active: true }); // no array allocated
```
### Real-World: E-commerce Search
@@ -368,24 +379,28 @@ const results = filter(products, {
category: 'Electronics',
price: { $lte: 1000 },
rating: { $gte: 4.5 },
- inStock: true
+ inStock: true,
});
// Full-text search with brand filter
const searchResults = filter(products, {
name: { $contains: 'laptop' },
brand: ['Apple', 'Dell', 'HP'],
- price: { $gte: 500, $lte: 2000 }
+ price: { $gte: 500, $lte: 2000 },
});
// Sorted and paginated results
-const page1 = filter(products, { category: 'Electronics', inStock: true }, {
- orderBy: [
- { field: 'price', direction: 'asc' },
- { field: 'rating', direction: 'desc' }
- ],
- limit: 20
-});
+const page1 = filter(
+ products,
+ { category: 'Electronics', inStock: true },
+ {
+ orderBy: [
+ { field: 'price', direction: 'asc' },
+ { field: 'rating', direction: 'desc' },
+ ],
+ limit: 20,
+ },
+);
```
---
@@ -468,7 +483,7 @@ import { FilterService } from '@mcabreradev/filter/angular';
@for (user of filterService.filtered(); track user.id) {
{{ user.name }}
}
- `
+ `,
})
export class UserListComponent {
filterService = inject(FilterService);
@@ -483,7 +498,7 @@ import { useFilter } from '@mcabreradev/filter/solidjs';
function UserList() {
const { filtered } = useFilter(
() => users,
- () => ({ active: true })
+ () => ({ active: true }),
);
return {(u) => {u.name}
};
}
@@ -496,11 +511,18 @@ import { useFilter } from '@mcabreradev/filter/preact';
function UserList() {
const { filtered } = useFilter(users, { active: true });
- return {filtered.map(u =>
{u.name}
)}
;
+ return (
+
+ {filtered.map((u) => (
+
{u.name}
+ ))}
+
+ );
}
```
**Every integration includes:**
+
- ✅ Full TypeScript generics
- ✅ Debounced search hook with `isPending` state
- ✅ Pagination hook with `nextPage`, `prevPage`, `goToPage`
@@ -515,14 +537,14 @@ function UserList() {
### Supported Operators
-| Category | Operators |
-|----------|-----------|
-| **Comparison** | `$gt` `$gte` `$lt` `$lte` `$eq` `$ne` |
-| **Array** | `$in` `$nin` `$contains` `$size` |
-| **String** | `$startsWith` `$endsWith` `$contains` `$regex` `$match` |
-| **Logical** | `$and` `$or` `$not` |
-| **Geospatial** | `$near` `$geoBox` `$geoPolygon` |
-| **Datetime** | `$recent` `$upcoming` `$dayOfWeek` `$timeOfDay` `$age` `$isWeekday` `$isWeekend` `$isBefore` `$isAfter` |
+| Category | Operators |
+| -------------- | ------------------------------------------------------------------------------------------------------- |
+| **Comparison** | `$gt` `$gte` `$lt` `$lte` `$eq` `$ne` |
+| **Array** | `$in` `$nin` `$contains` `$size` |
+| **String** | `$startsWith` `$endsWith` `$contains` `$regex` `$match` |
+| **Logical** | `$and` `$or` `$not` |
+| **Geospatial** | `$near` `$geoBox` `$geoPolygon` |
+| **Datetime** | `$recent` `$upcoming` `$dayOfWeek` `$timeOfDay` `$age` `$isWeekday` `$isWeekend` `$isBefore` `$isAfter` |
> 18+ operators covering every filtering scenario you'll encounter.
@@ -538,10 +560,10 @@ interface Product {
}
filter(products, {
- price: { $gte: 100 }, // ✅ number operators
+ price: { $gte: 100 }, // ✅ number operators
name: { $contains: '' }, // ✅ string operators
- tags: { $size: 3 }, // ✅ array operators
- price: { $contains: '' } // ❌ TypeScript error — string op on number field
+ tags: { $size: 3 }, // ✅ array operators
+ price: { $contains: '' }, // ❌ TypeScript error — string op on number field
});
```
@@ -549,15 +571,15 @@ filter(products, {
```typescript
filter(data, expression, {
- caseSensitive: false, // default: false
- maxDepth: 3, // nested object traversal depth (1–10)
- enableCache: true, // LRU result caching (530x speedup)
- orderBy: 'price', // sort field or array of fields
- limit: 10, // cap result count
- debug: true, // print expression tree to console
- verbose: true, // detailed per-item evaluation logs
- showTimings: true, // execution time per operator
- enablePerformanceMonitoring: true, // collect performance metrics
+ caseSensitive: false, // default: false
+ maxDepth: 3, // nested object traversal depth (1–10)
+ enableCache: true, // LRU result caching (530x speedup)
+ orderBy: 'price', // sort field or array of fields
+ limit: 10, // cap result count
+ debug: true, // print expression tree to console
+ verbose: true, // detailed per-item evaluation logs
+ showTimings: true, // execution time per operator
+ enablePerformanceMonitoring: true, // collect performance metrics
});
```
@@ -589,11 +611,11 @@ const hasBanned = filterExists(users, { role: 'banned' });
const total = filterCount(orders, { status: 'pending' });
```
-| Scenario | Array.filter | filterLazy / filterFirst |
-|----------|-------------|--------------------------|
-| First match in 1M items | ~50ms | **~0.1ms** |
-| Memory for 1M items | ~80MB | **~0KB** |
-| Early exit | ❌ | ✅ |
+| Scenario | Array.filter | filterLazy / filterFirst |
+| ----------------------- | ------------ | ------------------------ |
+| First match in 1M items | ~50ms | **~0.1ms** |
+| Memory for 1M items | ~80MB | **~0KB** |
+| Early exit | ❌ | ✅ |
📖 **[Lazy Evaluation Guide →](./docs/guide/lazy-evaluation.md)**
@@ -609,11 +631,11 @@ const results = filter(largeDataset, { age: { $gte: 18 } }, { enableCache: true
const same = filter(largeDataset, { age: { $gte: 18 } }, { enableCache: true });
```
-| Scenario | Without Cache | With Cache | Speedup |
-|----------|--------------|------------|---------|
-| Simple query, 10K items | 5.3ms | 0.01ms | **530x** |
-| Regex pattern | 12.1ms | 0.02ms | **605x** |
-| Complex nested query | 15.2ms | 0.01ms | **1520x** |
+| Scenario | Without Cache | With Cache | Speedup |
+| ----------------------- | ------------- | ---------- | --------- |
+| Simple query, 10K items | 5.3ms | 0.01ms | **530x** |
+| Regex pattern | 12.1ms | 0.02ms | **605x** |
+| Complex nested query | 15.2ms | 0.01ms | **1520x** |
Caches are bounded (LRU, max 500 entries each) and auto-expire after 5 minutes — safe for long-running servers.
@@ -665,13 +687,13 @@ filter(users, { city: 'Berlin', age: { $gte: 18 } }, { debug: true });
## Performance
-| Technique | Benefit |
-|-----------|---------|
-| Early-exit operators | Skip remaining items on first mismatch |
-| LRU result cache | 530x–1520x speedup on repeated queries |
-| LRU predicate cache | Compiled predicates reused across calls |
-| LRU regex cache | Compiled patterns reused, bounded to 500 entries |
-| Lazy generators | 500x faster when you don't need all results |
+| Technique | Benefit |
+| --------------------- | --------------------------------------------------- |
+| Early-exit operators | Skip remaining items on first mismatch |
+| LRU result cache | 530x–1520x speedup on repeated queries |
+| LRU predicate cache | Compiled predicates reused across calls |
+| LRU regex cache | Compiled patterns reused, bounded to 500 entries |
+| Lazy generators | 500x faster when you don't need all results |
| Absolute TTL eviction | Stale entries removed after 5 min — no memory leaks |
```typescript
@@ -686,12 +708,12 @@ const first100 = filterFirst(millionRecords, { active: true }, 100);
## Bundle Size
-| Import | Size (gzipped) | Tree-Shakeable |
-|--------|----------------|----------------|
-| Full | 12 KB | ✅ |
-| Core only | 8.4 KB | ✅ |
-| React hooks | 9.2 KB | ✅ |
-| Lazy evaluation | 5.4 KB | ✅ |
+| Import | Size (gzipped) | Tree-Shakeable |
+| --------------- | -------------- | -------------- |
+| Full | 12 KB | ✅ |
+| Core only | 8.4 KB | ✅ |
+| React hooks | 9.2 KB | ✅ |
+| Lazy evaluation | 5.4 KB | ✅ |
---
@@ -728,7 +750,19 @@ filter(data, expression, { enableCache: true, limit: 50 });
## Changelog
-### v5.8.2 (Current)
+### v5.9.2 (Current)
+
+- 🧹 **Refactor**: Removed Svelte integration exports, dependencies, and related docs from the package.
+- 🔧 **CI/CD**: Hardened npm publish workflow with safer version resolution and improved release handling.
+- 📦 **Release Reliability**: Synced lockfile with dependency changes to avoid CI failures with `--frozen-lockfile`.
+- ✅ **Publishing**: Improved release pipeline behavior so versioning and GitHub Releases run more consistently.
+
+### v5.9.1
+
+- 🚀 **Release**: Published patch release with workflow and release-process fixes.
+- 🏷️ **Versioning**: Stabilized tag/version flow to avoid collisions with existing release tags.
+
+### v5.8.2
- 🐛 **Bug Fix**: Wildcard regex now correctly escapes all special characters (`.`, `+`, `*`, `?`, `(`, `[`, `^`, etc.) — patterns like `%.txt` or `a.b%` no longer silently break
- 🐛 **Bug Fix**: `$timeOfDay` with `start > end` (e.g. `{ start: 22, end: 5 }`) now correctly fails validation instead of silently never matching
@@ -773,6 +807,7 @@ filter(data, expression, { enableCache: true, limit: 50 });
We welcome contributions! Please read our [Contributing Guide](./CONTRIBUTING.md) for details.
**Ways to Contribute:**
+
- Report bugs or request features via [GitHub Issues](https://github.com/mcabreradev/filter/issues)
- Submit pull requests with bug fixes or new features
- Improve documentation
diff --git a/docs/project/changelog.md b/docs/project/changelog.md
index fcd3779..74267cb 100644
--- a/docs/project/changelog.md
+++ b/docs/project/changelog.md
@@ -5,9 +5,29 @@ All notable changes to @mcabreradev/filter are documented here.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [5.9.2] - 2026-03-21
+
+### Changed
+
+- Removed Svelte integration support from package exports and dependency declarations.
+- Updated project scripts and docs references to reflect framework support changes.
+
+### Fixed
+
+- Synced `pnpm-lock.yaml` with `package.json` after Svelte removal to fix CI install failures with `--frozen-lockfile`.
+- Improved release workflow reliability for npm publish and GitHub release generation.
+
+## [5.9.1] - 2026-03-21
+
+### Fixed
+
+- Stabilized release automation to avoid tag/version collisions during patch publishing.
+- Hardened npm publishing workflow and release orchestration.
+
## [5.8.2] - 2025-11-17
### Documentation
+
- **Comprehensive Documentation Update**: Complete overhaul of documentation structure
- Consolidated all operator documentation into single comprehensive guide
- Expanded API Reference with 40+ exported functions documented
@@ -23,6 +43,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Lazy evaluation patterns
### Changed
+
- Updated documentation structure for better navigation and discoverability
- Improved TypeScript examples with comprehensive type coverage
- Enhanced operator examples with real-world use cases
@@ -30,20 +51,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [5.8.1] - 2025-11-15
### Fixed
+
- Minor documentation fixes and typo corrections
- Improved error messages for invalid geospatial coordinates
- Fixed type inference for nested object expressions
### Changed
+
- Updated dependencies to latest stable versions
- Improved bundle size optimization
## [5.8.3] - 2025-11-26
### Bug Fixes
+
- **Cache**: Fixed critical issue where `limit` option was ignored in cache key. Requests with different limits now correctly generate distinct cache keys.
### Performance Improvements
+
- **Memory**: Replaced unbounded `Map` caches with `LRUCache` strategy.
- `FilterCache`: Limited to 100 entries per source array.
- `RegexCache`: Limited to 500 compiled patterns.
@@ -52,6 +77,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [5.8.0] - 2025-11-10
### Added
+
- **OrderBy and Limit Options**: Enhanced configuration system
- Full support for single and multi-field sorting
- Nested path sorting with dot notation (e.g., 'profile.age')
@@ -63,11 +89,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Full generic support for custom types
### Changed
+
- Optimized internal sorting algorithms for better performance
- Improved cache key generation for orderBy and limit combinations
- Updated all framework integrations to support orderBy and limit
### Performance
+
- OrderBy uses stable sort algorithm (10-15% faster than v5.7.0)
- Limit applies after filtering/sorting (minimal overhead)
- Cache efficiency improved for complex queries with orderBy
@@ -75,6 +103,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [5.7.1] - 2025-11-08
### Fixed
+
- **$contains Operator**: Fixed type detection edge cases
- Improved string vs array context detection
- Better handling of undefined values
@@ -85,12 +114,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed Preact hook re-render optimization
### Changed
+
- Improved error messages for invalid expressions
- Better TypeScript type inference for logical operators
## [5.7.0] - 2025-11-06
### Added
+
- **Framework Integrations**: Angular, SolidJS, and Preact support
- **Angular**: Services and Pipes with Signals support
- `FilterService`: Core filtering service with Signal-based state
@@ -127,6 +158,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Updated Quick Start guide with new features
### Fixed
+
- **$contains Operator**: Fixed type detection to distinguish between string and array contexts
- Enhanced `hasArrayOps` to check actual value types (not just operator presence)
- Enhanced `hasStringOps` to check actual value types
@@ -134,17 +166,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed edge case where undefined properties would incorrectly pass $contains checks
### Changed
+
- Updated framework integrations documentation to v5.7.0
- Updated README with all new features (Angular, SolidJS, Preact, orderBy, limit)
- Updated configuration guide with orderBy and limit sections
- Improved Quick Start guide with sorting and limiting examples
### Performance
+
- OrderBy uses efficient comparison functions
- Limit applies slice operation after filtering (minimal overhead)
- Framework integrations use proper memoization strategies
### Testing
+
- Added 33 comprehensive tests for limit functionality
- Added tests for orderBy with limit combinations
- Fixed integration tests for $contains operator with proper type checking
@@ -154,6 +189,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [5.6.0] - 2025-11-01
### Added
+
- **Geospatial Operators**: Location-based filtering with three powerful spatial operators
- `$near`: Find points within radius with optional min/max distance
- `$geoBox`: Bounding box queries for rectangular areas
@@ -181,24 +217,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- IoT device monitoring patterns
### Changed
+
- Updated operator count from 18+ to 30+ operators
- Enhanced type system to recognize GeoPoint and Date types
- Improved autocomplete for geospatial and datetime operators
- Extended constants to include all operator keys
### Performance
+
- Fast distance calculation using spherical law of cosines
- Efficient ray casting algorithm for polygon containment
- Optimized bounding box checks
- Compatible with lazy evaluation for large datasets
### Testing
+
- Added 26 new comprehensive tests
- Total test count: 523 tests (previously 497)
- 100% code coverage for geospatial features
- Edge case testing for invalid coordinates and missing data
### Datetime Operators
+
- **Relative Time Filtering**: Filter by last/next N days/hours/minutes
- `$recent`: Find events in the last N days/hours/minutes
- `$upcoming`: Find events in the next N days/hours/minutes
@@ -228,6 +268,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Weekend/weekday filtering patterns
### Testing (Enhanced)
+
- Added 90 new comprehensive tests for datetime operators
- Total test count: 613+ tests (previously 523)
- 100% code coverage for all datetime features
@@ -236,11 +277,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [5.5.1] - 2025-10-30
### Fixed
+
- Bug fixes and stability improvements
- Build optimization issues
- Type definition exports
### Changed
+
- Updated documentation with latest features
- Improved error messages
- Enhanced performance for array operations
@@ -248,6 +291,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [5.5.0] - 2025-10-28
### Added
+
- **Array OR Syntax**: Intuitive array-based OR filtering without explicit `$in` operator
- `filter(products, { category: ['Electronics', 'Books'] })`
- Supports wildcards within array values
@@ -270,12 +314,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Expression tree visualization
### Changed
+
- Enhanced array operator performance
- Improved type inference for array expressions
- Optimized debug tree building
- Better error messages for invalid expressions
### Fixed
+
- Edge cases with empty arrays in expressions
- Type inference issues with array OR syntax
- Debug output formatting inconsistencies
@@ -283,6 +329,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [5.4.0] - 2024-10-26
### Added
+
- Comprehensive documentation overhaul
- Migration guide for v5.4
- Framework-specific SSR guides
@@ -292,11 +339,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Best practices guide
### Changed
+
- Updated React integration documentation
- Updated Vue integration documentation
- Improved API reference clarity
### Fixed
+
- Documentation API inconsistencies
- Outdated code examples
- Missing TypeScript type references
@@ -304,6 +353,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [5.3.0] - 2024-09-15
### Added
+
- Pagination support for all framework integrations
- `usePaginatedFilter` hook for React
- `usePaginatedFilter` composable for Vue
@@ -311,16 +361,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Pagination actions (`nextPage`, `previousPage`, `goToPage`, `setPageSize`)
### Changed
+
- Improved performance for large datasets
- Enhanced memoization strategy
### Fixed
+
- Memory leak in memoization cache
- Type inference issues with generic components
## [5.2.0] - 2024-08-10
### Added
+
- Debounced filtering support
- `useDebouncedFilter` hook for React
- `useDebouncedFilter` composable for Vue
@@ -328,27 +381,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Configurable delay option
### Changed
+
- Optimized re-render behavior in React
- Improved reactivity in Vue
+
## [5.1.0] - 2024-07-05
### Added
+
- `useFilteredState` hook for React
- `useFilteredState` composable for Vue
- State management for data and expressions
- Setter functions for dynamic updates
### Changed
+
- Improved TypeScript type inference
- Enhanced documentation with more examples
### Fixed
+
- Edge case with empty arrays
- Null/undefined handling in expressions
## [5.0.0] - 2024-06-01
### Breaking Changes
+
- Renamed `data` to `filtered` in return values
- Removed `isError` and `error` from return values
- Changed `isLoading` to `isFiltering`
@@ -357,6 +416,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Updated minimum Vue version to 3.0+
### Added
+
- Full TypeScript rewrite
- Improved type safety and inference
- Better error messages
@@ -364,86 +424,101 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Tree-shaking support
### Changed
+
- Simplified API surface
- Improved documentation
- Enhanced test coverage to 100%
### Migration Guide
+
See [Migration Guide v5.4](/guide/migration-v2) for detailed migration instructions.
## [4.5.0] - 2024-04-15
### Added
+
- Lazy evaluation support
- `createLazyFilter` function
- Chainable lazy operations
- Memory optimization for large datasets
### Changed
+
- Improved operator processing performance
- Enhanced memoization algorithm
## [4.4.0] - 2024-03-10
### Added
+
- Nested object filtering support
- Dot notation for property access
- Deep comparison utilities
- Array filtering within objects
### Fixed
+
- Nested property access edge cases
- Deep equality comparison issues
## [4.3.0] - 2024-02-05
### Added
+
- Custom operator registration
- `registerOperator` function
- Operator extension API
- Plugin system foundation
### Changed
+
- Refactored operator processing
- Improved operator type definitions
## [4.2.0] - 2024-01-15
### Added
+
- String operators: `$startsWith`, `$endsWith`, `$contains`
- Case-insensitive string matching option
- Regular expression operator `$regex`
### Fixed
+
- String comparison edge cases
- Unicode string handling
## [4.1.0] - 2023-12-10
### Added
+
- Array operators: `$in`, `$nin`
- Logical operators: `$and`, `$or`, `$not`
- Complex expression support
- Nested logical operations
### Changed
+
- Improved expression parsing
- Enhanced type safety for operators
## [4.0.0] - 2023-11-01
### Breaking Changes
+
- Removed jQuery-style API
- Changed expression format to object-based
- Updated operator syntax
### Added
+
- Modern operator-based API
- TypeScript support
- Framework integrations (React, Vue)
- Comprehensive test suite
### Changed
+
- Complete API redesign
- Improved performance
- Better documentation
@@ -472,4 +547,3 @@ See [Contributing Guide](/project/contributing) for information on how to contri
## License
MIT License - see [LICENSE](/project/license) for details.
-