From 3cbef48b6c95698696c5d6a2d4ba800523774c98 Mon Sep 17 00:00:00 2001 From: gui Date: Mon, 25 Sep 2017 20:20:06 +0100 Subject: [PATCH 1/5] Add `is.inRange()` (#3) --- index.js | 8 ++++++++ readme.md | 7 +++++++ test.js | 13 +++++++++++++ 3 files changed, 28 insertions(+) diff --git a/index.js b/index.js index 78b4368..99caa9a 100644 --- a/index.js +++ b/index.js @@ -150,4 +150,12 @@ const typedArrayTypes = new Set([ ]); is.typedArray = x => typedArrayTypes.has(getObjectType(x)); +is.inRange = (x, range) => { + if (is.number(range)) { + return (x >= Math.min(0, range)) && (x <= Math.max(range, 0)); + } + + return (is.array(range)) && (x >= Math.min.apply(Math, range)) && (x <= Math.max.apply(Math, range)); +}; + module.exports = is; diff --git a/readme.md b/readme.md index 45ade28..40e5d1b 100644 --- a/readme.md +++ b/readme.md @@ -121,6 +121,13 @@ Returns `true` for instances created by a ES2015 class. ##### .typedArray(value) +##### .inRange(value, range) + +Check to see if the value is within a given range, for example `is.inRange(3, [0, 5])`. +The range supplied can be an array of any size, though this will only check for +the minimum and maximum values in it. + +If `range` is a number (e.g., `is.inRange(3, 10)`), it will be treated as a range of 0 to `range`. ## FAQ diff --git a/test.js b/test.js index 357aa55..6f5d6a6 100644 --- a/test.js +++ b/test.js @@ -305,3 +305,16 @@ test('is.typedArray', t => { t.false(m.typedArray([])); t.false(m.typedArray({})); }); + +test('is.inRange', t => { + const x = 3; + + t.true(m.inRange(x, [0, 5])); + t.true(m.inRange(x, [5, 0])); + t.true(m.inRange(x, [-5, 5])); + t.true(m.inRange(x, [5, -5])); + t.false(m.inRange(x, [4, 8])); + + t.true(m.inRange(x, 10)); + t.false(m.inRange(x, 2)); +}); From 26ca1953028c6eb0b73286a5beef69fe87cf7a64 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 26 Sep 2017 02:32:58 +0700 Subject: [PATCH 2/5] Minor tweaks to `is.inRange()` --- index.js | 9 +++++++-- readme.md | 19 +++++++++++++++---- test.js | 12 ++++++++++++ 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/index.js b/index.js index 99caa9a..2ba0ab3 100644 --- a/index.js +++ b/index.js @@ -152,10 +152,15 @@ is.typedArray = x => typedArrayTypes.has(getObjectType(x)); is.inRange = (x, range) => { if (is.number(range)) { - return (x >= Math.min(0, range)) && (x <= Math.max(range, 0)); + return x >= Math.min(0, range) && x <= Math.max(range, 0); } - return (is.array(range)) && (x >= Math.min.apply(Math, range)) && (x <= Math.max.apply(Math, range)); + if (is.array(range) && range.length === 2) { + // TODO: Use spread operator here when targeting Node.js 6 or higher + return x >= Math.min.apply(null, range) && x <= Math.max.apply(null, range); + } + + throw new TypeError('Invalid range'); }; module.exports = is; diff --git a/readme.md b/readme.md index 40e5d1b..6038e65 100644 --- a/readme.md +++ b/readme.md @@ -123,11 +123,22 @@ Returns `true` for instances created by a ES2015 class. ##### .inRange(value, range) -Check to see if the value is within a given range, for example `is.inRange(3, [0, 5])`. -The range supplied can be an array of any size, though this will only check for -the minimum and maximum values in it. +Check if `value` (number) is in the given `range`. The range is an array of two values, lower bound and upper bound, in no specific order. + +```js +is.inRange(3, [0, 5]); +is.inRange(3, [5, 0]); +is.inRange(0, [-2, 2]); +``` + +##### .inRange(value, upperBound) + +Check if `value` (number) is in the range of `0` to `upperBound`. + +```js +is.inRange(3, 10); +``` -If `range` is a number (e.g., `is.inRange(3, 10)`), it will be treated as a range of 0 to `range`. ## FAQ diff --git a/test.js b/test.js index 6f5d6a6..18f6158 100644 --- a/test.js +++ b/test.js @@ -314,7 +314,19 @@ test('is.inRange', t => { t.true(m.inRange(x, [-5, 5])); t.true(m.inRange(x, [5, -5])); t.false(m.inRange(x, [4, 8])); + t.true(m.inRange(-7, [-5, -10])); + t.true(m.inRange(-5, [-5, -10])); + t.true(m.inRange(-10, [-5, -10])); t.true(m.inRange(x, 10)); + t.true(m.inRange(0, 0)); t.false(m.inRange(x, 2)); + + t.throws(() => { + t.true(m.inRange(0)); + }); + + t.throws(() => { + t.true(m.inRange(0, [5])); + }); }); From f918d8a7d4388b59dc7509861c09a38e83950c5c Mon Sep 17 00:00:00 2001 From: Giora Guttsait Date: Thu, 28 Sep 2017 06:41:16 +0300 Subject: [PATCH 3/5] Refactor to reduce code repetition (#6) --- index.js | 109 ++++++++++++++++++++++++++----------------------------- test.js | 20 ++++++++-- 2 files changed, 68 insertions(+), 61 deletions(-) diff --git a/index.js b/index.js index 2ba0ab3..5734148 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,10 @@ 'use strict'; +const util = require('util'); + const toString = Object.prototype.toString; const getObjectType = x => toString.call(x).slice(8, -1); +const isOfType = type => x => typeof x === type; // eslint-disable-line valid-typeof +const isObjectOfType = type => x => getObjectType(x) === type; const is = value => { if (value == null) { // eslint-disable-line no-eq-null, eqeqeq @@ -29,7 +33,7 @@ const is = value => { return 'symbol'; } - if (type === 'function') { + if (is.function(value)) { return 'Function'; } @@ -53,74 +57,63 @@ const is = value => { return 'Object'; }; -is.undefined = x => typeof x === 'undefined'; +is.undefined = isOfType('undefined'); is.null = x => x === null; -is.string = x => typeof x === 'string'; -is.number = x => typeof x === 'number'; -is.boolean = x => typeof x === 'boolean'; -is.symbol = x => typeof x === 'symbol'; +is.string = isOfType('string'); +is.number = isOfType('number'); +is.boolean = isOfType('boolean'); +is.symbol = isOfType('symbol'); is.array = Array.isArray; -is.function = x => typeof x === 'function'; +is.function = isOfType('function'); is.buffer = Buffer.isBuffer; -is.object = x => { - const type = typeof x; - return x !== null && (type === 'object' || type === 'function'); -}; +const isObject = x => typeof x === 'object'; -is.nativePromise = x => getObjectType(x) === 'Promise'; +is.object = x => !is.nullOrUndefined(x) && (is.function(x) || isObject(x)); -is.promise = x => { - return is.nativePromise(x) || - ( - x !== null && - typeof x === 'object' && - typeof x.then === 'function' && - typeof x.catch === 'function' - ); -}; +is.nativePromise = isObjectOfType('Promise'); -is.regExp = x => getObjectType(x) === 'RegExp'; -is.date = x => getObjectType(x) === 'Date'; -is.error = x => getObjectType(x) === 'Error'; -is.map = x => getObjectType(x) === 'Map'; -is.set = x => getObjectType(x) === 'Set'; -is.weakMap = x => getObjectType(x) === 'WeakMap'; -is.weakSet = x => getObjectType(x) === 'WeakSet'; +const hasPromiseAPI = x => + !is.null(x) && + isObject(x) && + is.function(x.then) && + is.function(x.catch); -is.int8Array = x => getObjectType(x) === 'Int8Array'; -is.uint8Array = x => getObjectType(x) === 'Uint8Array'; -is.uint8ClampedArray = x => getObjectType(x) === 'Uint8ClampedArray'; -is.int16Array = x => getObjectType(x) === 'Int16Array'; -is.uint16Array = x => getObjectType(x) === 'Uint16Array'; -is.int32Array = x => getObjectType(x) === 'Int32Array'; -is.uint32Array = x => getObjectType(x) === 'Uint32Array'; -is.float32Array = x => getObjectType(x) === 'Float32Array'; -is.float64Array = x => getObjectType(x) === 'Float64Array'; +is.promise = x => is.nativePromise(x) || hasPromiseAPI(x); -is.arrayBuffer = x => getObjectType(x) === 'ArrayBuffer'; +is.regExp = isObjectOfType('RegExp'); +is.date = isObjectOfType('Date'); +is.error = isObjectOfType('Error'); +is.map = isObjectOfType('Map'); +is.set = isObjectOfType('Set'); +is.weakMap = isObjectOfType('WeakMap'); +is.weakSet = isObjectOfType('WeakSet'); -is.sharedArrayBuffer = x => { - try { - return getObjectType(x) === 'SharedArrayBuffer'; - } catch (err) { - return false; - } -}; +is.int8Array = isObjectOfType('Int8Array'); +is.uint8Array = isObjectOfType('Uint8Array'); +is.uint8ClampedArray = isObjectOfType('Uint8ClampedArray'); +is.int16Array = isObjectOfType('Int16Array'); +is.uint16Array = isObjectOfType('Uint16Array'); +is.int32Array = isObjectOfType('Int32Array'); +is.uint32Array = isObjectOfType('Uint32Array'); +is.float32Array = isObjectOfType('Float32Array'); +is.float64Array = isObjectOfType('Float64Array'); + +is.arrayBuffer = isObjectOfType('ArrayBuffer'); +is.sharedArrayBuffer = isObjectOfType('SharedArrayBuffer'); is.nan = Number.isNaN; -is.nullOrUndefined = x => x === null || typeof x === 'undefined'; +is.nullOrUndefined = x => is.null(x) || is.undefined(x); -is.primitive = x => { - const type = typeof x; - return x === null || - type === 'undefined' || - type === 'string' || - type === 'number' || - type === 'boolean' || - type === 'symbol'; -}; +const primitiveTypes = new Set([ + 'undefined', + 'string', + 'number', + 'boolean', + 'symbol' +]); +is.primitive = x => is.null(x) || primitiveTypes.has(typeof x); is.integer = Number.isInteger; @@ -133,9 +126,9 @@ is.plainObject = x => { prototype === Object.getPrototypeOf({})); }; -is.iterable = x => !is.null(x) && !is.undefined(x) && typeof x[Symbol.iterator] === 'function'; +is.iterable = x => !is.nullOrUndefined(x) && is.function(x[Symbol.iterator]); -is.class = x => typeof x === 'function' && x.toString().startsWith('class '); +is.class = x => is.function(x) && x.toString().startsWith('class '); const typedArrayTypes = new Set([ 'Int8Array', @@ -160,7 +153,7 @@ is.inRange = (x, range) => { return x >= Math.min.apply(null, range) && x <= Math.max.apply(null, range); } - throw new TypeError('Invalid range'); + throw new TypeError(`Invalid range: ${util.inspect}`); }; module.exports = is; diff --git a/test.js b/test.js index 18f6158..316bb41 100644 --- a/test.js +++ b/test.js @@ -10,7 +10,11 @@ const ErrorSubclassFixture = class extends Error {}; const types = new Map([ ['undefined', undefined], ['null', null], - ['string', '🦄'], + ['string', [ + '🦄', + 'hello world', + '' + ]], ['number', [ 6, 1.4, @@ -320,13 +324,23 @@ test('is.inRange', t => { t.true(m.inRange(x, 10)); t.true(m.inRange(0, 0)); + t.true(m.inRange(-2, -3)); t.false(m.inRange(x, 2)); + t.false(m.inRange(-3, -2)); t.throws(() => { - t.true(m.inRange(0)); + m.inRange(0); }); t.throws(() => { - t.true(m.inRange(0, [5])); + m.inRange(0, []); + }); + + t.throws(() => { + m.inRange(0, [5]); + }); + + t.throws(() => { + m.inRange(0, [1, 2, 3]); }); }); From e97e68cd0193f718e9c58b504d675087b75292b2 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Thu, 28 Sep 2017 13:26:23 +0700 Subject: [PATCH 4/5] Welcome @gioragutt as a maintainer --- readme.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 6038e65..0962385 100644 --- a/readme.md +++ b/readme.md @@ -169,6 +169,12 @@ The most common mistakes I noticed in these modules was using `instanceof` for t - [is-empty-iterable](https://github.com/sindresorhus/is-empty-iterable) - Check if an Iterable is empty +## Created by + +- [Sindre Sorhus](https://github.com/sindresorhus) +- [Giora Guttsait](https://github.com/gioragutt) + + ## License -MIT © [Sindre Sorhus](https://sindresorhus.com) +MIT From 000f66bbdcbab8d1c9e62ed774851392984bfed6 Mon Sep 17 00:00:00 2001 From: Sam Gluck Date: Thu, 28 Sep 2017 14:57:32 +0100 Subject: [PATCH 5/5] Fix call to util.inspect --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 5734148..befda91 100644 --- a/index.js +++ b/index.js @@ -153,7 +153,7 @@ is.inRange = (x, range) => { return x >= Math.min.apply(null, range) && x <= Math.max.apply(null, range); } - throw new TypeError(`Invalid range: ${util.inspect}`); + throw new TypeError(`Invalid range: ${util.inspect(range)}`); }; module.exports = is;