From 6e07df5896f017aae28e6ad9c18f7b32598759c7 Mon Sep 17 00:00:00 2001 From: Arfat Salman Date: Fri, 28 Sep 2018 11:54:35 +0530 Subject: [PATCH] Add emptiness methods (#61) Fix #53 --- readme.md | 70 ++++++++++++++++++++--- source/index.ts | 20 +++++-- source/tests/test.ts | 130 ++++++++++++++++++++++++++++++------------- 3 files changed, 169 insertions(+), 51 deletions(-) diff --git a/readme.md b/readme.md index 51a8b0d..46fa906 100644 --- a/readme.md +++ b/readme.md @@ -160,6 +160,68 @@ is.boundFunction(function () {}); ##### .sharedArrayBuffer(value) ##### .dataView(value) +#### Emptiness + +##### .emptyString(value) + +Returns `true` if the value is a `string` and the `.length` is 0. + +##### .nonEmptyString(value) + +Returns `true` if the value is a `string` and the `.length` is more than 0. + +##### .emptyStringOrWhitespace(value) + +Returns `true` if `is.emptyString(value)` or if it's a `string` that is all whitespace. + +##### .emptyArray(value) + +Returns `true` if the value is an `Array` and the `.length` is 0. + +##### .nonEmptyArray(value) + +Returns `true` if the value is an `Array` and the `.length` is more than 0. + +##### .emptyObject(value) + +Returns `true` if the value is an `Object` and `Object.keys(value).length` is 0. + +Please note that `Object.keys` returns only own enumerable properties. Hence something like this can happen: + +```js +const object1 = {}; + +Object.defineProperty(object1, 'property1', { + value: 42, + writable: true, + enumerable: false, + configurable: true +}); + +is.emptyObject(object1); +// => true +``` + +##### .nonEmptyObject(value) + +Returns `true` if the value is an `Object` and `Object.keys(value).length` is more than 0. + +##### .emptySet(value) + +Returns `true` if the value is a `Set` and the `.size` is 0. + +##### .nonEmptySet(Value) + +Returns `true` if the value is a `Set` and the `.size` is more than 0. + +##### .emptyMap(value) + +Returns `true` if the value is a `Map` and the `.size` is 0. + +##### .nonEmptyMap(value) + +Returns `true` if the value is a `Map` and the `.size` is more than 0. + #### Miscellaneous ##### .directInstanceOf(value, class) @@ -295,14 +357,6 @@ Returns `true` if `value` is an even integer. Returns `true` if `value` is an odd integer. -##### .empty(value) - -Returns `true` if `value` is falsy or an empty string, array, object, map, or set. - -##### .emptyOrWhitespace(value) - -Returns `true` if `is.empty(value)` or a string that is all whitespace. - ##### .any(predicate, ...values) Returns `true` if **any** of the input `values` returns true in the `predicate`: diff --git a/source/index.ts b/source/index.ts index 8f93bba..534700b 100644 --- a/source/index.ts +++ b/source/index.ts @@ -270,12 +270,22 @@ namespace is { // tslint:disable-line:no-namespace export const odd = isAbsoluteMod2(1); const isWhiteSpaceString = (value: any) => string(value) && /\S/.test(value) === false; - const isEmptyStringOrArray = (value: any) => (string(value) || array(value)) && value.length === 0; - const isEmptyObject = (value: any) => !map(value) && !set(value) && object(value) && Object.keys(value).length === 0; - const isEmptyMapOrSet = (value: any) => (map(value) || set(value)) && value.size === 0; - export const empty = (value: any) => falsy(value) || isEmptyStringOrArray(value) || isEmptyObject(value) || isEmptyMapOrSet(value); - export const emptyOrWhitespace = (value: any) => empty(value) || isWhiteSpaceString(value); + export const emptyArray = (value: any) => array(value) && value.length === 0; + export const nonEmptyArray = (value: any) => array(value) && value.length > 0; + + export const emptyString = (value: any) => string(value) && value.length === 0; + export const nonEmptyString = (value: any) => string(value) && value.length > 0; + export const emptyStringOrWhitespace = (value: any) => emptyString(value) || isWhiteSpaceString(value); + + export const emptyObject = (value: any) => object(value) && !map(value) && !set(value) && Object.keys(value).length === 0; + export const nonEmptyObject = (value: any) => object(value) && !map(value) && !set(value) && Object.keys(value).length > 0; + + export const emptySet = (value: any) => set(value) && value.size === 0; + export const nonEmptySet = (value: any) => set(value) && value.size > 0; + + export const emptyMap = (value: any) => map(value) && value.size === 0; + export const nonEmptyMap = (value: any) => map(value) && value.size > 0; type ArrayMethod = (fn: (value: any, index: number, array: any[]) => boolean, thisArg?: any) => boolean; const predicateOnArray = (method: ArrayMethod, predicate: any, values: any[]) => { diff --git a/source/tests/test.ts b/source/tests/test.ts index 810b42f..66c3c9e 100644 --- a/source/tests/test.ts +++ b/source/tests/test.ts @@ -46,6 +46,13 @@ const types = new Map([ '' ] }], + ['emptyString', { + is: m.emptyString, + fixtures: [ + '', + String() + ] + }], ['number', { is: m.number, fixtures: [ @@ -76,6 +83,13 @@ const types = new Map([ new Array(2) // tslint:disable-line:prefer-array-literal ] }], + ['emptyArray', { + is: m.emptyArray, + fixtures: [ + [], + new Array() + ] + }], ['function', { is: m.function_, fixtures: [ @@ -167,13 +181,25 @@ const types = new Map([ ['map', { is: m.map, fixtures: [ - new Map() + new Map([['one', '1']]), + ] + }], + ['emptyMap', { + is: m.emptyMap, + fixtures: [ + new Map(), ] }], ['set', { is: m.set, fixtures: [ - new Set() + new Set(['one']) + ] + }], + ['emptySet', { + is: m.emptySet, + fixtures: [ + new Set(), ] }], ['weakSet', { @@ -385,7 +411,7 @@ test('is.null', t => { }); test('is.string', t => { - testType(t, 'string'); + testType(t, 'string', ['emptyString']); }); test('is.number', t => { @@ -401,7 +427,7 @@ test('is.symbol', t => { }); test('is.array', t => { - testType(t, 'array'); + testType(t, 'array', ['emptyArray']); }); test('is.function', t => { @@ -465,11 +491,11 @@ test('is.generatorFunction', t => { }); test('is.map', t => { - testType(t, 'map'); + testType(t, 'map', ['emptyMap']); }); test('is.set', t => { - testType(t, 'set'); + testType(t, 'set', ['emptySet']); }); test('is.weakMap', t => { @@ -739,40 +765,68 @@ test('is.odd', t => { } }); -test('is.empty', t => { - t.true(m.empty(null)); - t.true(m.empty(undefined)); - - t.true(m.empty(false)); - t.false(m.empty(true)); - - t.true(m.empty('')); - t.false(m.empty('🦄')); - - t.true(m.empty([])); - t.false(m.empty(['🦄'])); - - t.true(m.empty({})); - t.false(m.empty({unicorn: '🦄'})); - - const tempMap = new Map(); - t.true(m.empty(tempMap)); - - tempMap.set('unicorn', '🦄'); - t.false(m.empty(tempMap)); - - const tempSet = new Set(); - t.true(m.empty(tempSet)); - - tempSet.add(1); - t.false(m.empty(tempSet)); +test('is.emptyArray', t => { + testType(t, 'emptyArray'); }); -test('is.emptyOrWhitespace', t => { - t.true(m.emptyOrWhitespace('')); - t.true(m.emptyOrWhitespace(' ')); - t.false(m.emptyOrWhitespace('🦄')); - t.false(m.emptyOrWhitespace('unicorn')); +test('is.nonEmptyArray', t => { + t.true(m.nonEmptyArray([1, 2, 3])); + t.false(m.nonEmptyArray([])); + t.false(m.nonEmptyArray(new Array())); +}); + +test('is.emptyString', t => { + testType(t, 'emptyString', ['string']); + t.false(m.emptyString('🦄')); +}); + +test('is.nonEmptyString', t => { + t.false(m.nonEmptyString('')); + t.false(m.nonEmptyString(String())); + t.true(m.nonEmptyString('🦄')); +}); + +test('is.emptyStringOrWhitespace', t => { + testType(t, 'emptyString', ['string']); + t.true(m.emptyStringOrWhitespace(' ')); + t.false(m.emptyStringOrWhitespace('🦄')); + t.false(m.emptyStringOrWhitespace('unicorn')); +}); + +test('is.emptyObject', t => { + t.true(m.emptyObject({})); + t.true(m.emptyObject(new Object())); + t.false(m.emptyObject({unicorn: '🦄'})); +}); + +test('is.nonEmptyObject', t => { + t.false(m.nonEmptyObject({})); + t.false(m.nonEmptyObject(new Object())); + t.true(m.nonEmptyObject({unicorn: '🦄'})); +}); + +test('is.emptySet', t => { + testType(t, 'emptySet'); +}); + +test('is.nonEmptySet', t => { + const tempSet = new Set(); + t.false(m.nonEmptySet(tempSet)); + + tempSet.add(1); + t.true(m.nonEmptySet(tempSet)); +}); + +test('is.emptyMap', t => { + testType(t, 'emptyMap'); +}); + +test('is.nonEmptyMap', t => { + const tempMap = new Map(); + t.false(m.nonEmptyMap(tempMap)); + + tempMap.set('unicorn', '🦄'); + t.true(m.nonEmptyMap(tempMap)); }); test('is.any', t => {