diff --git a/src/index.d.ts b/src/index.d.ts index 85fb9f774c..5c30ce08c9 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -20,27 +20,27 @@ declare namespace RamdaAdjunct { export interface Static { /** - * Checks if input value is `Array` + * Checks if input value is `Array`. */ isArray(val: any): val is Array; /** - * Checks if input value is `Boolean + * Checks if input value is `Boolean. */ isBoolean(val: any): val is Boolean; /** - * Returns `true` if the given value is its type's empty value, `null` or `undefined` + * Returns `true` if the given value is its type's empty value, `null` or `undefined`. */ isNilOrEmpty(val: any): boolean; /** - * Checks if input value is complement of `Array` + * Checks if input value is complement of `Array`. */ isNotArray(val: any): boolean; /** - * Checks if input value is complement of `Boolean` + * Checks if input value is complement of `Boolean`. */ isNotBoolean(val: any): boolean; @@ -50,83 +50,89 @@ declare namespace RamdaAdjunct { isNotEmpty(val: any): boolean; /** - * Checks if input value is complement of `null` or `undefined` + * Checks if input value is complement of `null` or `undefined`. */ isNotNil(val: any): boolean; /** - * Checks if input value is complement of `null` + * Checks if input value is complement of `null`. */ isNotNull(val: any): boolean; /** - * Checks if input value is complement of `String` + * Checks if input value is complement of `String`. */ isNotString(val: any): boolean; /** - * Checks if input value is complement `undefined` + * Checks if input value is complement `undefined`. */ isNotUndefined(val: any): boolean; /** - * Checks if input value is `null` + * Checks if input value is `null`. */ isNull(val: any): val is null; /** - * Checks if input value is `String` + * Checks if input value is `String`. */ isString(val: any): val is String; /** - * Checks if input value is `undefined` + * Checks if input value is `undefined`. */ isUndefined(val: any): val is undefined; + /** + * Tests whether or not an object is similar to an array. + */ + isArrayLike(val: any): boolean + + /** * Tests whether or not an object is similar to an array. */ isNotArrayLike(val: any): boolean; /** - * Checks if input value is `Generator Function` + * Checks if input value is `Generator Function`. */ isGeneratorFunction(val: any): boolean; /** - * Checks if input value is complement of `Generator Function` + * Checks if input value is complement of `Generator Function`. */ isNotGeneratorFunction(val: any): boolean; /** - * Checks if input value is `Async Function` + * Checks if input value is `Async Function`. */ isAsyncFunction(val: any): boolean; /** - * Checks if input value is complement of `Async Function` + * Checks if input value is complement of `Async Function`. */ isNotAsyncFunction(val: any): boolean; /** - * Checks if input value is `Function` + * Checks if input value is `Function`. */ isFunction(val: any): boolean; /** - * Checks if input value is complement of `Function` + * Checks if input value is complement of `Function`. */ isNotFunction(val: any): boolean; /** - * Checks if input value is language type of `Object` + * Checks if input value is language type of `Object`. */ isObj(val: any): val is Object; isObject(val: any): val is Object; /** - * Checks if input value is complement of language type of `Object` + * Checks if input value is complement of language type of `Object`. */ isNotObj(val: any): boolean; isNotObject(val: any): boolean; // alias @@ -144,13 +150,13 @@ declare namespace RamdaAdjunct { isNotObjectLike(val: any): boolean; // alias /** - * Check to see if an object is a plain object (created using `{}`, `new Object()` or `Object.create(null)`) + * Check to see if an object is a plain object (created using `{}`, `new Object()` or `Object.create(null)`). */ isPlainObj(val: any): boolean; isPlainObject(val: any): boolean; // alias /** - * Check to see if an object is not a plain object (created using `{}`, `new Object()` or `Object.create(null)`) + * Check to see if an object is not a plain object (created using `{}`, `new Object()` or `Object.create(null)`). */ isNotPlainObj(val: any): boolean; isNotPlainObject(val: any): boolean; // alias @@ -161,7 +167,7 @@ declare namespace RamdaAdjunct { isDate(val: any): val is Date; /** - * Checks if value is complement of `Date` object + * Checks if value is complement of `Date` object. */ isNotDate(val: any): boolean; @@ -192,12 +198,12 @@ declare namespace RamdaAdjunct { isNotNaN(val: any): boolean; /** - * Checks if value is a `Number` primitive or object + * Checks if value is a `Number` primitive or object. */ isNumber(val: any): val is Number; /** - * Checks if value is a complement of `Number` primitive or object + * Checks if value is a complement of `Number` primitive or object. */ isNotNumber(val: any): boolean; diff --git a/src/index.js b/src/index.js index 6c5016454f..87369eb358 100644 --- a/src/index.js +++ b/src/index.js @@ -12,6 +12,7 @@ import isNotEmpty from './isNotEmpty'; import isNilOrEmpty from './isNilOrEmpty'; import isString from './isString'; import isNotString from './isNotString'; +import isArrayLike from './isArrayLike'; import isNotArrayLike from './isNotArrayLike'; import isGeneratorFunction from './isGeneratorFunction'; import isNotGeneratorFunction from './isNotGeneratorFunction'; @@ -71,6 +72,7 @@ export { default as isNotEmpty } from './isNotEmpty'; export { default as isNilOrEmpty } from './isNilOrEmpty'; export { default as isString } from './isString'; export { default as isNotString } from './isNotString'; +export { default as isArrayLike } from './isArrayLike'; export { default as isNotArrayLike } from './isNotArrayLike'; export { default as isGeneratorFunction } from './isGeneratorFunction'; export { default as isNotGeneratorFunction } from './isNotGeneratorFunction'; @@ -142,6 +144,7 @@ const RA = { isNilOrEmpty, isString, isNotString, + isArrayLike, isNotArrayLike, isGeneratorFunction, isNotGeneratorFunction, diff --git a/src/isArrayLike.js b/src/isArrayLike.js new file mode 100644 index 0000000000..3a77528e50 --- /dev/null +++ b/src/isArrayLike.js @@ -0,0 +1,67 @@ +import { has } from 'ramda'; + +import isArray from './isArray'; +import isString from './isString'; + + +/* eslint-disable max-len */ +/** + * Tests whether or not an object is similar to an array. + * + * @func isArrayLike + * @memberOf RA + * @since {@link https://char0n.github.io/ramda-adjunct/1.9.0|v1.9.0} + * @licence https://github.com/ramda/ramda/blob/master/LICENSE.txt + * @category List + * @category Type + * @sig * -> Boolean + * @param {*} val The value to test + * @returns {Boolean} `true` if `val` has a numeric length property and extreme indices defined; `false` otherwise. + + * @example + * + * RA.isArrayLike([]); //=> true + * RA.isArrayLike(true); //=> false + * RA.isArrayLike({}); //=> false + * RA.isArrayLike({length: 10}); //=> false + * RA.isArrayLike({0: 'zero', 9: 'nine', length: 10}); //=> true + */ +/* eslint-enable max-lent */ +const isArrayLike = (val) => { + if (isArray(val)) { return true } + if (!val) { return false } + if (typeof val !== 'object') { return false } + if (isString(val)) { return false } + if (val.nodeType === 1) { return !!val.length } + if (val.length === 0) { return true } + if (val.length > 0) { + return has(0, val) && has(val.length - 1, val); + } + return false; +}; + +export default isArrayLike; + +/** + The MIT License (MIT) + + Copyright (c) 2013-2016 Scott Sauyet and Michael Hurley + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ diff --git a/src/isNotArrayLike.js b/src/isNotArrayLike.js index 69f995172a..7f1f7058f3 100644 --- a/src/isNotArrayLike.js +++ b/src/isNotArrayLike.js @@ -1,4 +1,7 @@ -import { complement, isArrayLike } from 'ramda'; +import { complement } from 'ramda'; + +import isArrayLike from './isArrayLike'; + /** * Tests whether or not an object is similar to an array. diff --git a/test/isArrayLike.js b/test/isArrayLike.js new file mode 100644 index 0000000000..9f7fcc3646 --- /dev/null +++ b/test/isArrayLike.js @@ -0,0 +1,72 @@ +import RA from '../src/index'; +import eq from './shared/eq'; + + +describe('isArrayLike', function() { + it('is true for Arrays', function() { + eq(RA.isArrayLike([]), true); + eq(RA.isArrayLike([1, 2, 3, 4]), true); + eq(RA.isArrayLike([null]), true); + }); + + it('is true for arguments', function() { + function test() { + return RA.isArrayLike(arguments); + } + eq(test(), true); + eq(test(1, 2, 3), true); + eq(test(null), true); + }); + + it('is false for Strings', function() { + eq(RA.isArrayLike(''), false); + eq(RA.isArrayLike('abcdefg'), false); + }); + + it('is true for arbitrary objects with numeric length, if extreme indices are defined', function() { + const obj1 = { length: 0 }; + const obj2 = { 0: 'something', length: 0 }; + const obj3 = { 0: void 0, length: 0 }; + const obj4 = { 0: 'zero', 1: 'one', length: 2 }; + const obj5 = { 0: 'zero', length: 2 }; + const obj6 = { 1: 'one', length: 2 }; + eq(RA.isArrayLike(obj1), true); + eq(RA.isArrayLike(obj2), true); + eq(RA.isArrayLike(obj3), true); + eq(RA.isArrayLike(obj4), true); + eq(RA.isArrayLike(obj5), false); + eq(RA.isArrayLike(obj6), false); + }); + + it('is false for everything else', function() { + eq(RA.isArrayLike(undefined), false); + eq(RA.isArrayLike(1), false); + eq(RA.isArrayLike({}), false); + eq(RA.isArrayLike(false), false); + eq(RA.isArrayLike(function() {}), false); + }); +}); + +/** + The MIT License (MIT) + + Copyright (c) 2013-2016 Scott Sauyet and Michael Hurley + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */