Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@
- [Browser Support](#browser-support)
- [Migration from v3.x](#migration-from-v3x)
- [Changelog](#changelog)
- [v5.8.2 (Current)](#v582-current)
- [v5.9.0 (Current)](#v590-current)
- [v5.8.2](#v582)
- [v5.8.0](#v580)
- [v5.7.0](#v570)
- [v5.6.0](#v560)
Expand Down Expand Up @@ -166,6 +167,12 @@ const startsWithAl = filter(users, 'Al%');
// → [{ name: 'Alice', ... }]
```

> **`find` is an alias for `filter`** — use whichever name feels more natural:
> ```typescript
> import { find } from '@mcabreradev/filter';
> const result = find(users, { active: true }); // identical to filter()
> ```

**🎮 [Try it in the Playground →](https://mcabreradev-filter.vercel.app/playground/)**

---
Expand Down Expand Up @@ -728,7 +735,19 @@ filter(data, expression, { enableCache: true, limit: 50 });

## Changelog

### v5.8.2 (Current)
### v5.9.0 (Current)

- ✨ **New**: `find` — an alias for `filter` with identical signature and behavior. `import { find } from '@mcabreradev/filter'` returns `T[]` just like `filter`.
- ✨ **New**: `lazyFind` — the lazy-iterator helper (previously exported as `find`) is now exported as `lazyFind`. Returns `T | undefined`, exits on first match.
- ⚠️ **Breaking**: `find` exported from `@mcabreradev/filter` root **changed meaning**. Previously it was the lazy-iterator helper (`T | undefined`); it is now an alias for `filter` (`T[]`). Rename usages to `lazyFind`.

```typescript
// Migrate: rename find → lazyFind for the iterable helper
import { lazyFind } from '@mcabreradev/filter';
const item = lazyFind(iterable, (x) => x.active); // T | undefined
```

### 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
Expand Down
24 changes: 23 additions & 1 deletion __test__/filter.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import filter from '../src/index';
import filter, { find } from '../src/index';

import data from './data.json';

Expand Down Expand Up @@ -300,3 +300,25 @@ describe('Array values with OR logic (syntactic sugar for $in)', () => {
expect(result.map((u) => u.city).sort()).toEqual(['Berlin', 'Berlin', 'London']);
});
});

describe('find alias', () => {
it('returns same results as filter', () => {
expect(find(data, 'Berlin')).toEqual(filter(data, 'Berlin'));
});

it('works with object expression', () => {
const city = 'Berlin';
expect(find(data, { city })).toEqual(filter(data, { city }));
});

it('works with predicate function', () => {
const pred = (item: (typeof data)[0]) => item.city === 'Berlin';
expect(find(data, pred)).toEqual(filter(data, pred));
});

it('works with options', () => {
expect(find(data, 'berlin', { caseSensitive: false })).toEqual(
filter(data, 'berlin', { caseSensitive: false }),
);
});
});
8 changes: 7 additions & 1 deletion __test__/test-d/filter.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expectType, expectError } from 'tsd';
import { filter } from '../../src/core/filter';
import { filter, find } from '../../src/core/filter';
import type { FilterOptions } from '../../src/types';
Comment on lines 1 to 3

interface User {
Expand Down Expand Up @@ -114,3 +114,9 @@ const mixedArray: (string | number)[] = ['a', 1, 'b', 2];
expectType<(string | number)[]>(filter(mixedArray, 'a'));

expectType<(string | number)[]>(filter(mixedArray, (item) => typeof item === 'string'));

expectType<User[]>(find(users, 'John'));
expectType<User[]>(find(users, { name: 'John' }));
expectType<User[]>(find(users, (user) => user.age > 18));
expectType<User[]>(find(users, { name: 'John' }, options));
expectError(find('not-an-array', 'test'));
70 changes: 70 additions & 0 deletions docs/api/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,76 @@ const users = [{ name: 'Alice', age: 30 }, { name: 'Bob', age: 25 }];
const result = filter(users, { age: { $gte: 25 } });
```

### find

Alias for `filter` — identical signature and behavior. Use whichever name fits your style.

```typescript
function find<T>(
array: T[],
expression: Expression<T>,
options?: FilterOptions
): T[]
```

**Example:**
```typescript
import { find } from '@mcabreradev/filter';

const users = [{ name: 'Alice', age: 30 }, { name: 'Bob', age: 25 }];

// Exactly the same as calling filter()
const result = find(users, { age: { $gte: 25 } });
```

::: tip
`find` and `filter` are the same array-returning function. Pick the one that reads most naturally in your codebase. If you're looking for the lazy-iterator helper that was previously named `find` (with signature `Iterable<T> → T | undefined`), it is now exported as `lazyFind`:

```ts
import { lazyFind } from '@mcabreradev/filter';
```
:::

### lazyFind

Finds the first item in an **iterable** that satisfies a predicate. Returns `T | undefined` and exits immediately on the first match — no array is allocated.

> **Migration note (v5.9.0):** This function was previously exported as `find` from the root package. It has been renamed to `lazyFind` to make room for the new `find` alias for `filter`. Update your imports accordingly.

```typescript
function lazyFind<T>(
iterable: Iterable<T>,
predicate: (item: T, index: number) => boolean
): T | undefined
```

**Parameters:**
- `iterable` - Any iterable (array, generator, Set, Map values, …)
- `predicate` - Function that returns `true` for the desired item

**Returns:** The first matching item, or `undefined` if none found

**Example:**
```typescript
import { lazyFind } from '@mcabreradev/filter';

const users = [{ name: 'Alice', active: false }, { name: 'Bob', active: true }];

const first = lazyFind(users, (u) => u.active);
// → { name: 'Bob', active: true } (stops after finding Bob)

// Works with generators too
function* infiniteStream() { let i = 0; while (true) yield i++; }
const found = lazyFind(infiniteStream(), (n) => n > 100);
// → 101 (exits immediately without consuming the rest)
```

::: warning Difference from `find`
`lazyFind(iterable, predicate)` accepts **any iterable** and a plain **predicate function**, returning the **first match** as `T | undefined`.

`find(array, expression, options?)` accepts an **array** and any **filter expression**, returning **all matches** as `T[]`.
:::

### filterLazy

Returns a lazy iterator for on-demand filtering.
Expand Down
11 changes: 9 additions & 2 deletions docs/guide/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,20 @@ Choose between two import styles:

```typescript
// Classic import (all features)
import { filter, useFilter } from '@mcabreradev/filter';
import { filter, find, useFilter } from '@mcabreradev/filter';

// Modular import (smaller bundle, recommended for production)
import { filter } from '@mcabreradev/filter/core';
import { filter, find } from '@mcabreradev/filter/core';
import { useFilter } from '@mcabreradev/filter/react';
```

::: tip `find` is an alias for `filter`
Both functions are identical — same signature, same results. Use whichever reads more naturally in your codebase.
```typescript
find(users, { active: true }); // same as filter(users, { active: true })
```
:::

::: tip Bundle Size
Modular imports reduce bundle size by **50-70%**! See [Modular Imports](/guide/modular-imports) for details.
:::
Expand Down
48 changes: 48 additions & 0 deletions docs/project/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,54 @@ 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.0] - 2026-03-18

### Added
- **`find` alias**: `find` is now exported as an alias for `filter` with the identical signature and behavior. Import from `@mcabreradev/filter` or `@mcabreradev/filter/core`. Use whichever name reads more naturally in your codebase.
```typescript
import { find } from '@mcabreradev/filter';
const result = find(users, { active: true }); // identical to filter() — returns T[]
```
- **`lazyFind`**: The lazy-iterator helper (previously exported as `find` from the root package) is now exported as `lazyFind`. It finds the first matching item in an iterable and returns `T | undefined`.
```typescript
import { lazyFind } from '@mcabreradev/filter';
const first = lazyFind(iterable, (item, i) => item.active); // returns T | undefined
```

### Breaking Changes
- **`find` renamed to `lazyFind` in the main package export** (`@mcabreradev/filter`).

Previously `import { find } from '@mcabreradev/filter'` gave you the lazy-iterator helper with signature `find<T>(iterable: Iterable<T>, predicate: (item: T, index: number) => boolean): T | undefined`.

It is now exported as **`lazyFind`** with the same signature. The name `find` now refers to the array-filter alias (signature `find<T>(array: T[], expression: Expression<T>, options?: FilterOptions): T[]`).

**Migration:**
```typescript
// Before (v5.8.x)
import { find } from '@mcabreradev/filter';
const item = find(iterable, (x) => x.active); // T | undefined

// After (v5.9.0+)
import { lazyFind } from '@mcabreradev/filter';
const item = lazyFind(iterable, (x) => x.active); // T | undefined
```

> **Note:** This change only affects consumers who imported the `find` lazy-iterator helper from the root `@mcabreradev/filter` package. Imports from sub-packages (`@mcabreradev/filter/core`, etc.) are not affected.

### Changed / Breaking
- **`find` lazy helper renamed to `lazyFind`**: Previously, the `find` export from the main entry point was a lazy-iterator helper with a different signature and behavior. That helper has been renamed to `lazyFind`, and `find` now aliases `filter` instead.
- If you relied on the old lazy `find`, update your imports and calls:
```typescript
// Before 5.9.0 (lazy iterator helper)
import { find } from '@mcabreradev/filter';
const iterator = find(users, { active: true }); // lazy iterator

// From 5.9.0 onwards
import { lazyFind } from '@mcabreradev/filter';
const iterator = lazyFind(users, { active: true }); // same lazy behavior as old find
```
- The new `find` export matches `filter`’s eager, array-returning behavior and signature. Use `lazyFind` when you need lazy iteration, and `find`/`filter` for eager filtering.

Comment thread
mcabreradev marked this conversation as resolved.
Outdated
## [5.8.2] - 2025-11-17

### Documentation
Expand Down
2 changes: 2 additions & 0 deletions src/core/filter/filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ export function filter<T>(array: T[], expression: Expression<T>, options?: Filte
}
}

export const find = filter;

Comment on lines +105 to +106
export function clearFilterCache(): void {
globalFilterCache.clear();
memoization.clearAll();
Expand Down
2 changes: 1 addition & 1 deletion src/core/filter/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { filter, clearFilterCache, getFilterCacheStats } from './filter.js';
export { filter, find, clearFilterCache, getFilterCacheStats } from './filter.js';
2 changes: 1 addition & 1 deletion src/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { filter, clearFilterCache, getFilterCacheStats } from './filter/filter.js';
export { filter, find, clearFilterCache, getFilterCacheStats } from './filter/filter.js';
export {
filterLazy,
filterLazyAsync,
Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { filter } from './core/index.js';

export { filter };
export { find } from './core/index.js';

export { clearFilterCache, getFilterCacheStats } from './core/index.js';

Expand All @@ -26,7 +27,7 @@ export {
forEach,
every,
some,
find,
find as lazyFind,
chunk,
Comment on lines 21 to 31
flatten,
asyncMap,
Expand Down
Loading