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
dependenciestopeerDependencies(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:
# Install zod as a peer dependency
npm install zod
# or
pnpm add zod
# or
yarn add zodIf 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:
import { validateExpression, validateOptions } from '@mcabreradev/filter';
// These require zod to be installed
validateExpression(expression);
validateOptions(options);Core filtering works without zod:
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):
const result = filter(data, expression);After (v5.0.0):
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:
npm install zodCore filtering works without Zod!
Before (v3.x):
filter(data, undefined);After (v5.0.0) with validation:
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:
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 matchingmaxDepth(number, default:3): Maximum depth for nested object comparison (1-10)enableCache(boolean, default:false): Enable result cachingcustomComparator(function, optional): Custom comparison function
2. Enhanced Type Safety
v5.0.0 provides better TypeScript support with explicit types:
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:
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
enableCacheoption - 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
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
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
filter(users, { name: { $startsWith: 'Al' } });
filter(users, { email: { $endsWith: '@company.com' } });
filter(products, { description: { $contains: 'wireless' } });Available: $startsWith, $endsWith, $contains
Combining Operators
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:
node --versionStep 2: Update the Package
Using npm:
npm install @mcabreradev/filter@5.0.0Using yarn:
yarn add @mcabreradev/filter@5.0.0Using pnpm:
pnpm add @mcabreradev/filter@5.0.0Step 3: Update Imports
The default export remains the same, but named exports are recommended:
Before (v3.x):
import filter from '@mcabreradev/filter';After (v5.0.0) - Both work:
import filter from '@mcabreradev/filter';
import { filter } from '@mcabreradev/filter';Step 4: Add Type Parameters (Recommended)
For better type safety, add explicit type parameters:
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:
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:
const result = filter(data, '%berlin%', {
caseSensitive: true,
maxDepth: 2
});Common Migration Scenarios
Scenario 1: Basic String Filtering
No changes required - Works exactly the same:
const result = filter(customers, 'Berlin');Scenario 2: Wildcard Matching
No changes required - Works exactly the same:
const result = filter(customers, '%erlin');
const result2 = filter(customers, '_erlin');Scenario 3: Object-Based Filtering
No changes required - Works exactly the same:
const result = filter(customers, { city: 'Berlin' });Scenario 4: Predicate Functions
No changes required - Works exactly the same:
const result = filter(customers, (item) => item.age > 18);Scenario 5: Case-Sensitive Filtering (NEW)
v5.0.0 feature:
const result = filter(
[{ name: 'BERLIN' }, { name: 'berlin' }],
'berlin',
{ caseSensitive: true }
);Scenario 6: Migrating from Custom Predicates to Operators
Before (v3.x) - Using predicates:
const result = filter(products, (p) => p.price >= 100 && p.price <= 500);After (v5.0.0) - Using operators (recommended):
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):
const result = filter(products, (p) =>
p.price < 500 &&
['Electronics', 'Furniture'].includes(p.category) &&
p.name.startsWith('Pro')
);After (v5.0.0):
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:
npm testCheck for:
- TypeScript compilation errors
- Runtime validation errors
- 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:
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:
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:
const expression: Expression<MyType> = { ... };
const result = filter<MyType>(data, expression);Getting Help
If you encounter issues during migration:
- Check the README for updated examples
- Review the TypeScript types for API reference
- Open an issue on GitHub
Rollback Plan
If you need to rollback to v3.x:
npm install @mcabreradev/filter@3.1.3Note: v3.x will continue to receive critical bug fixes for 6 months after v5.0.0 release.