Browse Source

Support dot properties in object hasKeys and hasAnyKeys - fixes #50 (#52)

iss58
Sam Verschueren 7 years ago
committed by Sindre Sorhus
parent
commit
e22f0f8e24
  1. 2
      package.json
  2. 11
      source/lib/predicates/object.ts
  3. 6
      source/lib/utils/has-items.ts
  4. 8
      source/test/object.ts

2
package.json

@ -48,6 +48,7 @@
],
"devDependencies": {
"@sindresorhus/is": "^0.7.0",
"@types/dot-prop": "^4.2.0",
"@types/highlight.js": "^9.12.2",
"@types/lodash.isequal": "^4.5.2",
"@types/node": "^8.0.31",
@ -57,6 +58,7 @@
"awesome-typescript-loader": "^3.2.3",
"codecov": "^3.0.0",
"del-cli": "^1.1.0",
"dot-prop": "^4.2.0",
"license-webpack-plugin": "^1.1.1",
"lodash.isequal": "^4.5.0",
"nyc": "^11.2.1",

11
source/lib/predicates/object.ts

@ -1,4 +1,5 @@
import is from '@sindresorhus/is';
import * as dotProp from 'dot-prop';
import isEqual = require('lodash.isequal'); // tslint:disable-line:no-require-imports
import {Predicate, Context} from './predicate';
import hasItems from '../utils/has-items';
@ -88,26 +89,28 @@ export class ObjectPredicate extends Predicate<object> {
}
/**
* Test an object to include all the provided keys.
* Test an object to include all the provided keys. You can use [dot-notation](https://github.com/sindresorhus/dot-prop) in a key to access nested properties.
*
* @param keys The keys that should be present in the object.
*/
hasKeys(...keys: string[]) {
return this.addValidator({
message: (_, missingKeys) => `Expected object to have keys \`${JSON.stringify(missingKeys)}\``,
validator: object => hasItems(new Set(Object.keys(object)), keys)
validator: object => hasItems({
has: item => dotProp.has(object, item)
}, keys)
});
}
/**
* Test an object to include any of the provided keys.
* Test an object to include any of the provided keys. You can use [dot-notation](https://github.com/sindresorhus/dot-prop) in a key to access nested properties.
*
* @param keys The keys that could be a key in the object.
*/
hasAnyKeys(...keys: string[]) {
return this.addValidator({
message: () => `Expected object to have any key of \`${JSON.stringify(keys)}\``,
validator: (object: any) => keys.some(key => object[key] !== undefined)
validator: (object: any) => keys.some(key => dotProp.has(object, key))
});
}
}

6
source/lib/utils/has-items.ts

@ -1,4 +1,6 @@
type Collection = Set<any> | Map<any, any> | WeakSet<any> | WeakMap<any, any>;
export interface CollectionLike<T> {
has(item: T): boolean;
}
/**
* Retrieve the missing values in a collection based on an array of items.
@ -8,7 +10,7 @@ type Collection = Set<any> | Map<any, any> | WeakSet<any> | WeakMap<any, any>;
* @param items Items to search for.
* @param maxValues Maximum number of values after the search process is stopped. (Default: 5)
*/
export default (source: Collection, items: any[], maxValues = 5) => {
export default (source: CollectionLike<any>, items: any[], maxValues = 5) => {
const missingValues: any[] = [];
for (const value of items) {

8
source/test/object.ts

@ -49,12 +49,18 @@ test('object.instanceOf', t => {
test('object.hasKeys', t => {
t.notThrows(() => m({unicorn: '🦄'}, m.object.hasKeys('unicorn')));
t.notThrows(() => m({unicorn: {value: '🦄'}}, m.object.hasKeys('unicorn')));
t.notThrows(() => m({unicorn: {value: '🦄'}}, m.object.hasKeys('unicorn.value')));
t.notThrows(() => m({unicorn: '🦄', rainbow: '🌈'}, m.object.hasKeys('unicorn', 'rainbow')));
t.throws(() => m({unicorn: '🦄'}, m.object.hasKeys('unicorn', 'rainbow')), 'Expected object to have keys `["rainbow"]`');
t.throws(() => m({unicorn: {value: '🦄'}}, m.object.hasKeys('unicorn.foo')), 'Expected object to have keys `["unicorn.foo"]`');
});
test('object.hasAnyKeys', t => {
t.notThrows(() => m({unicorn: '🦄'}, m.object.hasAnyKeys('unicorn', 'rainbow')));
t.notThrows(() => m({unicorn: '🦄'}, m.object.hasAnyKeys('unicorn', 'rainbow', 'foo.bar')));
t.notThrows(() => m({unicorn: {value: '🦄'}}, m.object.hasAnyKeys('unicorn', 'rainbow')));
t.notThrows(() => m({unicorn: {value: '🦄'}}, m.object.hasAnyKeys('unicorn.value', 'rainbow')));
t.notThrows(() => m({unicorn: '🦄', rainbow: '🌈'}, m.object.hasAnyKeys('unicorn')));
t.throws(() => m({unicorn: '🦄'}, m.object.hasAnyKeys('foo')), 'Expected object to have any key of `["foo"]`');
t.throws(() => m({unicorn: '🦄'}, m.object.hasAnyKeys('unicorn.value')), 'Expected object to have any key of `["unicorn.value"]`');
});

Loading…
Cancel
Save