Skip to content

Migration Guide ​

v5.6.1 → Latest (Breaking Change) ​

Zero Dependencies Achievement ​

v5.6.1 introduces a breaking change to achieve truly zero production dependencies.

What Changed ​

  • Zod moved from dependencies to peerDependencies (optional)
  • @vercel/analytics, @vue-leaflet, leaflet moved to devDependencies
  • Bundle size reduced by 81%: 65.63 KB → 12.02 KB

Migration Steps ​

If you use validation features:

bash
# Install zod as a peer dependency
npm install zod
# or
pnpm add zod
# or
yarn add zod

If you DON'T use validation features:

No action required! The library works without any dependencies.

Which Features Require Zod? ​

Zod is only needed if you use these functions:

typescript
import { validateExpression, validateOptions } from '@mcabreradev/filter';

// These require zod to be installed
validateExpression(expression);
validateOptions(options);

Core filtering works without zod:

typescript
import { filter } from '@mcabreradev/filter';

// This works without any dependencies ✅
filter(users, { age: { $gte: 18 } });

Benefits ​

  • ✅ 81% smaller bundle (12.02 KB vs 65.63 KB)
  • ✅ Truly zero dependencies for core functionality
  • ✅ Optional validation - install only if needed
  • ✅ Better tree-shaking in production builds

v3.x → v5.0.0 ​

Overview ​

Version 5.0.0 represents a major refactoring of @mcabreradev/filter with improved type safety, modularity, and new features. This guide will help you migrate from v3.x to v5.0.0.

Breaking Changes ​

1. Minimum Node.js Version ​

  • v3.x: Node.js >= 18
  • v5.0.0: Node.js >= 20

Action Required: Ensure your environment is running Node.js 20 or higher.

2. TypeScript Strict Mode ​

v5.0.0 is built with strict TypeScript mode enabled, which may reveal type issues in your consuming code.

Before (v3.x):

typescript
const result = filter(data, expression);

After (v5.0.0):

typescript
import { filter } from '@mcabreradev/filter';
const result = filter<MyType>(data, expression);

3. Runtime Validation (Optional) ​

v5.0.0+ includes optional runtime validation using Zod. Invalid expressions throw descriptive errors when validation is used.

Optional Feature

Runtime validation requires Zod to be installed as a peer dependency:

bash
npm install zod

Core filtering works without Zod!

Before (v3.x):

typescript
filter(data, undefined);

After (v5.0.0) with validation:

typescript
import { validateExpression } from '@mcabreradev/filter';

validateExpression(undefined);

This will throw: Error: Invalid filter expression: Expected string | number | boolean | null | function | object, received undefined

4. Package Manager ​

The project now standardizes on pnpm. While you can still use npm or yarn to install the package, if you're contributing to the project, you'll need pnpm.

New Features ​

1. Configuration Options ​

v5.0.0 introduces an optional third parameter for configuration:

typescript
import { filter } from '@mcabreradev/filter';

const result = filter(data, expression, {
  caseSensitive: true,
  maxDepth: 5,
  enableCache: true,
  customComparator: (a, b) => a === b
});

Available Options:

  • caseSensitive (boolean, default: false): Enable case-sensitive matching
  • maxDepth (number, default: 3): Maximum depth for nested object comparison (1-10)
  • enableCache (boolean, default: false): Enable result caching
  • customComparator (function, optional): Custom comparison function

2. Enhanced Type Safety ​

v5.0.0 provides better TypeScript support with explicit types:

typescript
import type { Expression, FilterOptions } from '@mcabreradev/filter';

const expression: Expression<User> = { name: 'John' };
const options: FilterOptions = { caseSensitive: true };

const result = filter<User>(users, expression, options);

3. Runtime Validation ​

Expressions and options are now validated at runtime:

typescript
import { validateExpression, validateOptions } from '@mcabreradev/filter';

try {
  const validated = validateExpression(expression);
  const options = validateOptions({ maxDepth: 15 });
} catch (error) {
  console.error(error.message);
}

4. Performance Optimizations ​

  • Regex compilation is now cached
  • Optional result caching via enableCache option
  • Configurable maximum depth to prevent excessive recursion

5. MongoDB-Style Operators (NEW) ​

v5.0.0 introduces powerful MongoDB-style operators for advanced filtering:

Comparison Operators ​

typescript
filter(products, { price: { $gt: 100 } });

filter(products, { price: { $gte: 100, $lte: 500 } });

filter(orders, {
  date: {
    $gte: new Date('2025-01-01'),
    $lte: new Date('2025-12-31')
  }
});

filter(products, { price: { $ne: 0 } });

Available: $gt, $gte, $lt, $lte, $eq, $ne

Array Operators ​

typescript
filter(products, { category: { $in: ['Electronics', 'Books'] } });

filter(products, { category: { $nin: ['Furniture'] } });

filter(products, { tags: { $contains: 'sale' } });

filter(products, { tags: { $size: 3 } });

Available: $in, $nin, $contains, $size

String Operators ​

typescript
filter(users, { name: { $startsWith: 'Al' } });

filter(users, { email: { $endsWith: '@company.com' } });

filter(products, { description: { $contains: 'wireless' } });

Available: $startsWith, $endsWith, $contains

Combining Operators ​

typescript
filter(products, {
  price: { $gte: 100, $lte: 500 },
  category: { $in: ['Electronics', 'Accessories'] },
  name: { $startsWith: 'Pro' }
});

See: Operators Guide for comprehensive operator documentation.

Migration Steps ​

Step 1: Update Node.js ​

Ensure you're running Node.js 20 or higher:

bash
node --version

Step 2: Update the Package ​

Using npm:

bash
npm install @mcabreradev/filter@5.0.0

Using yarn:

bash
yarn add @mcabreradev/filter@5.0.0

Using pnpm:

bash
pnpm add @mcabreradev/filter@5.0.0

Step 3: Update Imports ​

The default export remains the same, but named exports are recommended:

Before (v3.x):

typescript
import filter from '@mcabreradev/filter';

After (v5.0.0) - Both work:

typescript
import filter from '@mcabreradev/filter';

import { filter } from '@mcabreradev/filter';

For better type safety, add explicit type parameters:

typescript
interface User {
  name: string;
  age: number;
}

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

const result = filter<User>(users, { age: 30 });

Step 5: Handle Validation Errors ​

Wrap filter calls in try-catch if you're passing dynamic expressions:

typescript
try {
  const result = filter(data, userProvidedExpression);
} catch (error) {
  console.error('Invalid filter expression:', error.message);
}

Step 6: Leverage New Configuration Options ​

Take advantage of new configuration options for better control:

typescript
const result = filter(data, '%berlin%', {
  caseSensitive: true,
  maxDepth: 2
});

Common Migration Scenarios ​

Scenario 1: Basic String Filtering ​

No changes required - Works exactly the same:

typescript
const result = filter(customers, 'Berlin');

Scenario 2: Wildcard Matching ​

No changes required - Works exactly the same:

typescript
const result = filter(customers, '%erlin');
const result2 = filter(customers, '_erlin');

Scenario 3: Object-Based Filtering ​

No changes required - Works exactly the same:

typescript
const result = filter(customers, { city: 'Berlin' });

Scenario 4: Predicate Functions ​

No changes required - Works exactly the same:

typescript
const result = filter(customers, (item) => item.age > 18);

Scenario 5: Case-Sensitive Filtering (NEW) ​

v5.0.0 feature:

typescript
const result = filter(
  [{ name: 'BERLIN' }, { name: 'berlin' }],
  'berlin',
  { caseSensitive: true }
);

Scenario 6: Migrating from Custom Predicates to Operators ​

Before (v3.x) - Using predicates:

typescript
const result = filter(products, (p) => p.price >= 100 && p.price <= 500);

After (v5.0.0) - Using operators (recommended):

typescript
const result = filter(products, {
  price: { $gte: 100, $lte: 500 }
});

Benefits of operators:

  • More declarative and readable
  • Can be serialized to JSON
  • Better TypeScript type safety
  • Runtime validation

Scenario 7: Complex Multi-Condition Filters ​

Before (v3.x):

typescript
const result = filter(products, (p) =>
  p.price < 500 &&
  ['Electronics', 'Furniture'].includes(p.category) &&
  p.name.startsWith('Pro')
);

After (v5.0.0):

typescript
const result = filter(products, {
  price: { $lt: 500 },
  category: { $in: ['Electronics', 'Furniture'] },
  name: { $startsWith: 'Pro' }
});

Testing Your Migration ​

After migrating, run your test suite to ensure everything works as expected:

bash
npm test

Check for:

  1. TypeScript compilation errors
  2. Runtime validation errors
  3. Changed filter behavior (if you relied on edge cases)

Troubleshooting ​

Error: "Invalid filter expression" ​

Cause: You're passing an invalid expression (e.g., undefined).

Solution: Ensure your expression is a string, number, boolean, null, object, or function:

typescript
if (expression !== undefined) {
  const result = filter(data, expression);
}

Error: "Invalid filter options: maxDepth too large" ​

Cause: maxDepth must be between 1 and 10.

Solution: Use a valid maxDepth value:

typescript
const result = filter(data, expression, { maxDepth: 5 });

TypeScript Errors After Upgrade ​

Cause: Strict mode reveals previously hidden type issues.

Solution: Add explicit types to your code:

typescript
const expression: Expression<MyType> = { ... };
const result = filter<MyType>(data, expression);

Getting Help ​

If you encounter issues during migration:

  1. Check the README for updated examples
  2. Review the API reference for exported types
  3. Open an issue on GitHub

Rollback Plan ​

If you need to rollback to v3.x:

bash
npm install @mcabreradev/filter@3.1.3

Note: v3.x will continue to receive critical bug fixes for 6 months after v5.0.0 release.

Released under the MIT License.