Browse Source

Add object.deepValuesOfType validator - fixes #51 (#53)

iss58
Sam Verschueren 7 years ago
committed by Sindre Sorhus
parent
commit
5b1b37a143
  1. 13
      source/lib/predicates/object.ts
  2. 28
      source/lib/utils/of-type-deep.ts
  3. 9
      source/test/object.ts

13
source/lib/predicates/object.ts

@ -4,6 +4,7 @@ import isEqual = require('lodash.isequal'); // tslint:disable-line:no-require-im
import {Predicate, Context} from './predicate';
import hasItems from '../utils/has-items';
import ofType from '../utils/of-type';
import ofTypeDeep from '../utils/of-type-deep';
export class ObjectPredicate extends Predicate<object> {
constructor(context?: Context) {
@ -56,6 +57,18 @@ export class ObjectPredicate extends Predicate<object> {
});
}
/**
* Test all the values in the object deeply to match the provided predicate.
*
* @param predicate The predicate that should be applied against every value in the object.
*/
deepValuesOfType<T>(predicate: Predicate<T>) {
return this.addValidator({
message: (_, error) => error,
validator: (object: any) => ofTypeDeep(object, predicate)
});
}
/**
* Test an object to be deeply equal to the provided object.
*

28
source/lib/utils/of-type-deep.ts

@ -0,0 +1,28 @@
import is from '@sindresorhus/is';
import ow from '../..';
import {Predicate} from '../predicates/predicate';
const ofTypeDeep = (input: any, predicate: Predicate): boolean => {
if (!is.plainObject(input)) {
ow(input, predicate);
return true;
}
return Object.keys(input).every(key => ofTypeDeep(input[key], predicate));
};
/**
* Test all the values in the object against a provided predicate.
*
* @hidden
* @param input Input object
* @param predicate Predicate to test every value in the input object against.
*/
export default (input: any, predicate: Predicate): boolean | string => {
try {
return ofTypeDeep(input, predicate);
} catch (err) {
return err.message;
}
};

9
source/test/object.ts

@ -33,6 +33,15 @@ test('object.valuesOfType', t => {
t.throws(() => m({unicorn: 'a', rainbow: 'b'}, m.object.valuesOfType(m.string.minLength(2))), 'Expected string to have a minimum length of `2`, got `a`');
});
test('object.valuesOfTypeDeep', t => {
t.notThrows(() => m({unicorn: '🦄'}, m.object.deepValuesOfType(m.string)));
t.notThrows(() => m({unicorn: '🦄', rainbow: '🌈'}, m.object.deepValuesOfType(m.string)));
t.notThrows(() => m({unicorn: {key: '🦄', value: '🌈'}}, m.object.deepValuesOfType(m.string)));
t.notThrows(() => m({a: {b: {c: {d: 1}, e: 2}, f: 3}}, m.object.deepValuesOfType(m.number)));
t.throws(() => m({unicorn: {key: '🦄', value: 1}}, m.object.deepValuesOfType(m.string)), 'Expected argument to be of type `string` but received type `number`');
t.throws(() => m({a: {b: {c: {d: 1}, e: '2'}, f: 3}}, m.object.deepValuesOfType(m.number)), 'Expected argument to be of type `number` but received type `string`');
});
test('object.deepEqual', t => {
t.notThrows(() => m({unicorn: '🦄'}, m.object.deepEqual({unicorn: '🦄'})));
t.notThrows(() => m({unicorn: '🦄', rain: {bow: '🌈'}}, m.object.deepEqual({unicorn: '🦄', rain: {bow: '🌈'}})));

Loading…
Cancel
Save