diff --git a/package.json b/package.json index 247fc2c2e..ab4355726 100644 --- a/package.json +++ b/package.json @@ -101,9 +101,6 @@ "dependencies": { "@babel/runtime": "^7.2.0", "classnames": "^2.2.3", - "lodash.isfunction": "^3.0.9", - "lodash.isobject": "^3.0.2", - "lodash.tonumber": "^4.0.3", "prop-types": "^15.5.8", "react-lifecycles-compat": "^3.0.4", "react-popper": "^1.3.3", diff --git a/src/Col.js b/src/Col.js index 1dd0b10a8..601ce165b 100644 --- a/src/Col.js +++ b/src/Col.js @@ -1,8 +1,7 @@ -import isobject from 'lodash.isobject'; import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import { mapToCssModules, tagPropType } from './utils'; +import { mapToCssModules, tagPropType, isObject } from './utils'; const colWidths = ['xs', 'sm', 'md', 'lg', 'xl']; const stringOrNumberProp = PropTypes.oneOfType([PropTypes.number, PropTypes.string]); @@ -66,7 +65,7 @@ const Col = (props) => { const isXs = !i; - if (isobject(columnProp)) { + if (isObject(columnProp)) { const colSizeInterfix = isXs ? '-' : `-${colWidth}-`; const colClass = getColumnSizeClass(isXs, colWidth, columnProp.size); diff --git a/src/Label.js b/src/Label.js index 476c16c7a..9af0fb297 100644 --- a/src/Label.js +++ b/src/Label.js @@ -1,8 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import isobject from 'lodash.isobject'; -import { mapToCssModules, tagPropType } from './utils'; +import { mapToCssModules, tagPropType, isObject } from './utils'; const colWidths = ['xs', 'sm', 'md', 'lg', 'xl']; @@ -77,7 +76,7 @@ const Label = (props) => { const isXs = !i; let colClass; - if (isobject(columnProp)) { + if (isObject(columnProp)) { const colSizeInterfix = isXs ? '-' : `-${colWidth}-`; colClass = getColumnSizeClass(isXs, colWidth, columnProp.size); diff --git a/src/Progress.js b/src/Progress.js index 5f1b346a0..1cf31b2d9 100644 --- a/src/Progress.js +++ b/src/Progress.js @@ -1,8 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import toNumber from 'lodash.tonumber'; -import { mapToCssModules, tagPropType } from './utils'; +import { mapToCssModules, tagPropType, toNumber } from './utils'; const propTypes = { children: PropTypes.node, diff --git a/src/__tests__/utils.spec.js b/src/__tests__/utils.spec.js index 187216c43..58197a473 100644 --- a/src/__tests__/utils.spec.js +++ b/src/__tests__/utils.spec.js @@ -181,6 +181,86 @@ describe('Utils', () => { }); }); + describe('isFunction', function() { + it('should return `true` for functions', function() { + function test(){} + expect(Utils.isFunction(test)).toBe(true); + expect(Utils.isFunction(Array.prototype.slice)).toBe(true); + }); + + it('should return `true` for async functions', function() { + async function asyncFunc() {} + expect(Utils.isFunction(asyncFunc)).toEqual(typeof asyncFunc === 'function'); + }); + + it('should return `true` for generator functions', function() { + function* genFunc() {} + expect(Utils.isFunction(genFunc)).toEqual(typeof genFunc === 'function'); + }); + + + it('should return `false` for non-functions', function() { + function toArgs(array) { + return (function() { return arguments; }.apply(undefined, array)); + } + expect(Utils.isFunction(toArgs([1, 2, 3]))).toBe(false); + expect(Utils.isFunction([1, 2, 3])).toBe(false); + expect(Utils.isFunction(true)).toBe(false); + expect(Utils.isFunction(new Date)).toBe(false); + expect(Utils.isFunction(new Error)).toBe(false); + expect(Utils.isFunction({ 'a': 1 })).toBe(false); + expect(Utils.isFunction(1)).toBe(false); + expect(Utils.isFunction(/x/)).toBe(false); + expect(Utils.isFunction('a')).toBe(false); + expect(Utils.isFunction(Symbol("a"))).toBe(false); + // + if (document) { + expect(Utils.isFunction(document.getElementsByTagName('body'))).toBe(false); + } + }); + + }); + + describe('isObject', function() { + it('should return `true` for objects', function() { + function toArgs(array) { + return (function() { return arguments; }.apply(undefined, array)); + } + expect(Utils.isObject([1, 2, 3])).toBe(true); + expect(Utils.isObject(Object(false))).toBe(true); + expect(Utils.isObject(new Date)).toBe(true); + expect(Utils.isObject(new Error)).toBe(true); + expect(Utils.isObject({ 'a': 1 })).toBe(true); + expect(Utils.isObject({ 'a': 1 })).toBe(true); + expect(Utils.isObject(Object(0))).toBe(true); + expect(Utils.isObject(/x/)).toBe(true); + expect(Utils.isObject(Object("a"))).toBe(true); + if (document) { + expect(Utils.isObject(document.body)).toBe(true); + } + }); + + it('should return `false` for non-objects', function() { + + expect(Utils.isObject(0)).toBe(false); + expect(Utils.isObject(false)).toBe(false); + expect(Utils.isObject(1)).toBe(false); + }); + + }); + + describe('toNumber', function() { + it('should return number', function() { + expect(Utils.toNumber("5")).toEqual(5); + expect(Utils.toNumber("5.0")).toEqual(5); + expect(Utils.toNumber("1.1")).toEqual(1.1); + expect(Utils.toNumber("-1.1")).toEqual(-1.1); + expect(Utils.toNumber(0/0)).toEqual(NaN); + expect(Utils.toNumber(0)).toEqual(0); + + }); + }); + // TODO // describe('getScrollbarWidth', () => { // // jsdom workaround https://github.com/tmpvar/jsdom/issues/135#issuecomment-68191941 diff --git a/src/utils.js b/src/utils.js index c1c8effb1..5853fade0 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,4 +1,3 @@ -import isFunction from 'lodash.isfunction'; import PropTypes from 'prop-types'; // https://github.com/twbs/bootstrap/blob/v4.0.0-alpha.4/js/src/modal.js#L436-L443 @@ -226,6 +225,51 @@ export function isReactRefObj(target) { return false; } +function getTag(value) { + if (value == null) { + return value === undefined ? '[object Undefined]' : '[object Null]' + } + return Object.prototype.toString.call(value) +} + +export function toNumber(value) { + const type = typeof value; + const NAN = 0 / 0; + if (type === 'number') { + return value + } + if (type === 'symbol' || (type === 'object' && getTag(value) === '[object Symbol]')) { + return NAN + } + if (isObject(value)) { + const other = typeof value.valueOf === 'function' ? value.valueOf() : value; + value = isObject(other) ? `${other}` : other + } + if (type !== 'string') { + return value === 0 ? value : +value + } + value = value.replace(/^\s+|\s+$/g, ''); + const isBinary = /^0b[01]+$/i.test(value); + return (isBinary || /^0o[0-7]+$/i.test(value)) + ? parseInt(value.slice(2), isBinary ? 2 : 8) + : (/^[-+]0x[0-9a-f]+$/i.test(value) ? NAN : +value) +} + +export function isObject(value) { + const type = typeof value; + return value != null && (type === 'object' || type === 'function') +} + +export function isFunction(value) { + if (!isObject(value)) { + return false + } + + const tag = getTag(value); + return tag === '[object Function]' || tag === '[object AsyncFunction]' || + tag === '[object GeneratorFunction]' || tag === '[object Proxy]' +} + export function findDOMElements(target) { if (isReactRefObj(target)) { return target.current; diff --git a/yarn.lock b/yarn.lock index bbb429941..251157adf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7821,21 +7821,11 @@ lodash.isequal@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= -lodash.isfunction@^3.0.9: - version "3.0.9" - resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051" - integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw== - lodash.ismatch@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc= -lodash.isobject@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-3.0.2.tgz#3c8fb8d5b5bf4bf90ae06e14f2a530a4ed935e1d" - integrity sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0= - lodash.isplainobject@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" @@ -7915,11 +7905,6 @@ lodash.templatesettings@^4.0.0: dependencies: lodash._reinterpolate "^3.0.0" -lodash.tonumber@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/lodash.tonumber/-/lodash.tonumber-4.0.3.tgz#0b96b31b35672793eb7f5a63ee791f1b9e9025d9" - integrity sha1-C5azGzVnJ5Prf1pj7nkfG56QJdk= - lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"