add matches

This commit is contained in:
Yanick Champoux 2023-07-25 10:07:39 -04:00
parent 986843a28c
commit c065f074f7
3 changed files with 83 additions and 0 deletions

3
src/index.ts Normal file
View File

@ -0,0 +1,3 @@
export * from 'remeda';
export * from './matches';

22
src/matches.test.ts Normal file
View File

@ -0,0 +1,22 @@
import { test, expect } from 'vitest';
import { matches } from './matches';
test('basic', () => {
expect(matches(1, 1)).toBeTruthy();
expect(matches(1, 2)).not.toBeTruthy();
expect(matches({ a: 1, b: 2 }, { a: 1 })).toBeTruthy();
expect(matches({ a: 2, b: 2 }, { a: 1 })).not.toBeTruthy();
expect(
matches([1, 1, { a: 3 }], { 2: { a: (x: number) => x > 2 } })
).toBeTruthy();
expect(matches({ a: 4, b: 5, c: 6 }, { a: 4, c: 6 })).toEqual(true);
});
test('data last', () => {
const partial = matches(1);
expect(partial(1)).toBeTruthy();
expect(partial(2)).toBeFalsy();
expect(matches({ a: 4, c: 6 })({ a: 4, b: 5, c: 6 })).toEqual(true);
});

58
src/matches.ts Normal file
View File

@ -0,0 +1,58 @@
import { purry } from 'remeda';
function _matches(target: any, condition: any) {
if (typeof condition === 'function') return condition(target);
if (typeof condition === 'object') {
return Object.entries(condition).every(([key, value]) =>
matches(target[key], value)
);
}
return target === condition;
}
type Matcher<I = any> = ((dataInput: I) => boolean) | any;
/**
* Compares the input with the matcher and returns `true` if they match.
* The matcher can be a function (which will be fed the input and is expected
* to return a boolean), or a value. If the value is an object, the matching
* will be recursive.
* @param input the input data
* @param matcher matching function or value
* @signature
* R.matches(inputData, matcher)
* @example
* R.matches( 'potato', 'potato'); // => true
* R.matches( 'potato', 'turnip'); // => false
* R.matches( 'potato', vegetable => vegetable === 'potato'); // => true
* R.matches({ a: 1, b :2 }, { a: 1 } ); // => true
* R.matches({ 'a': 4, 'b': 5, 'c': 6 }, { 'a': 4, 'c': 6 }) // => true
* @data_first
* @category Object
*/
export function matches<I>(data: I, matcher: Matcher<I>): boolean;
/**
* Compares the input with the matcher and returns `true` if they match.
* The matcher can be a function (which will be fed the input and is expected
* to return a boolean), or a value. If the value is an object, the matching
* will be recursive.
* @param input the input data
* @param matcher matching function or value
* @signature
* R.matches(matcher)(inputData)
* @example
* R.pipe({a:1,b:2}, R.matches({ a: 1 }) ) // => true
* R.pipe({a:1,b:2}, R.matches({ b: (val) => val < 5 }) ) // => true
* R.pipe({a:1,b:2}, R.matches({ c: 3 }) ) // => false
* R.pipe( { 'a': 4, 'b': 5, 'c': 6 }, R.matches({ 'a': 4, 'c': 6 })) // => true
* @data_last
* @category Object
*/
export function matches(matcher: Matcher): (dataIn: any) => boolean;
export function matches() {
return purry(_matches, arguments);
}