From 6673ce05ac3ecf53608a84ad641891ab8a201c6e Mon Sep 17 00:00:00 2001 From: Edward Drapkin Date: Sat, 20 Aug 2016 08:20:55 -0400 Subject: [PATCH 1/7] remove lodash dependency --- package.json | 2 -- src/extendReactClass.js | 10 ++++------ src/index.js | 5 +++-- src/isIterable.js | 8 ++++---- src/linkClass.js | 6 +++--- src/makeConfiguration.js | 10 +++++----- src/parseStyleName.js | 5 +---- src/utils.js | 10 ++++++++++ src/wrapStatelessFunction.js | 8 ++++---- 9 files changed, 34 insertions(+), 30 deletions(-) create mode 100644 src/utils.js diff --git a/package.json b/package.json index 369d02c..ae535cd 100644 --- a/package.json +++ b/package.json @@ -21,13 +21,11 @@ "license": "BSD-3-Clause", "dependencies": { "hoist-non-react-statics": "^1.0.5", - "lodash": "^4.6.1", "object-unfreeze": "^1.0.2" }, "devDependencies": { "babel-cli": "^6.10.1", "babel-plugin-add-module-exports": "^0.2.1", - "babel-plugin-lodash": "^3.2.5", "babel-plugin-transform-proto-to-assign": "^6.9.0", "babel-preset-es2015": "^6.9.0", "babel-preset-react": "^6.11.1", diff --git a/src/extendReactClass.js b/src/extendReactClass.js index b5cfb2d..41c2435 100644 --- a/src/extendReactClass.js +++ b/src/extendReactClass.js @@ -1,9 +1,9 @@ /* eslint-disable react/prop-types */ import React from 'react'; -import _ from 'lodash'; import hoistNonReactStatics from 'hoist-non-react-statics'; import linkClass from './linkClass'; +import {isObject} from './utils'; /** * @param {ReactClass} Component @@ -14,15 +14,13 @@ import linkClass from './linkClass'; export default (Component: Object, defaultStyles: Object, options: Object) => { const WrappedComponent = class extends Component { render () { - let propsChanged, + let propsChanged = false, styles; - propsChanged = false; - if (this.props.styles) { styles = this.props.styles; - } else if (_.isObject(defaultStyles)) { - this.props = _.assign({}, this.props, { + } else if (isObject(defaultStyles)) { + this.props = Object.assign({}, this.props, { styles: defaultStyles }); diff --git a/src/index.js b/src/index.js index 7ee7e4e..8fbf7ec 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +2,7 @@ import _ from 'lodash'; import extendReactClass from './extendReactClass'; import wrapStatelessFunction from './wrapStatelessFunction'; import makeConfiguration from './makeConfiguration'; +import {isFunction} from './utils'; /** * @see https://github.com/gajus/react-css-modules#options @@ -12,7 +13,7 @@ type TypeOptions = {}; * Determines if the given object has the signature of a class that inherits React.Component. */ const isReactComponent = (maybeReactComponent: any): boolean => { - return 'prototype' in maybeReactComponent && _.isFunction(maybeReactComponent.prototype.render); + return 'prototype' in maybeReactComponent && isFunction(maybeReactComponent.prototype.render); }; /** @@ -48,7 +49,7 @@ const decoratorConstructor = (defaultStyles: Object, options: TypeOptions): Func }; export default (...args) => { - if (_.isFunction(args[0])) { + if (isFunction(args[0])) { return functionConstructor(args[0], args[1], args[2]); } else { return decoratorConstructor(args[0], args[1]); diff --git a/src/isIterable.js b/src/isIterable.js index 2c800b1..b507ba2 100644 --- a/src/isIterable.js +++ b/src/isIterable.js @@ -1,6 +1,6 @@ -import _ from 'lodash'; +import {isFunction, isObject} from './utils'; -const ITERATOR_SYMBOL = typeof Symbol !== 'undefined' && _.isFunction(Symbol) && Symbol.iterator; +const ITERATOR_SYMBOL = typeof Symbol !== 'undefined' && isFunction(Symbol) && Symbol.iterator; const OLD_ITERATOR_SYMBOL = '@@iterator'; /** @@ -10,7 +10,7 @@ const OLD_ITERATOR_SYMBOL = '@@iterator'; export default (maybeIterable: any): boolean => { let iterator; - if (!_.isObject(maybeIterable)) { + if (!isObject(maybeIterable)) { return false; } @@ -20,5 +20,5 @@ export default (maybeIterable: any): boolean => { iterator = maybeIterable[OLD_ITERATOR_SYMBOL]; } - return _.isFunction(iterator); + return isFunction(iterator); }; diff --git a/src/linkClass.js b/src/linkClass.js index ea199e9..9896a3a 100644 --- a/src/linkClass.js +++ b/src/linkClass.js @@ -1,4 +1,3 @@ -import _ from 'lodash'; import React, { ReactElement } from 'react'; @@ -6,6 +5,7 @@ import objectUnfreeze from 'object-unfreeze'; import isIterable from './isIterable'; import parseStyleName from './parseStyleName'; import generateAppendClassName from './generateAppendClassName'; +import {isObject} from './utils'; const linkElement = (element: ReactElement, styles: Object, configuration: Object): ReactElement => { let appendClassName, @@ -26,7 +26,7 @@ const linkElement = (element: ReactElement, styles: Object, configuration: Objec if (React.isValidElement(elementShallowCopy.props.children)) { elementShallowCopy.props.children = linkElement(React.Children.only(elementShallowCopy.props.children), styles, configuration); - } else if (_.isArray(elementShallowCopy.props.children) || isIterable(elementShallowCopy.props.children)) { + } else if (Array.isArray(elementShallowCopy.props.children) || isIterable(elementShallowCopy.props.children)) { elementShallowCopy.props.children = React.Children.map(elementShallowCopy.props.children, (node) => { if (React.isValidElement(node)) { return linkElement(node, styles, configuration); @@ -65,7 +65,7 @@ const linkElement = (element: ReactElement, styles: Object, configuration: Objec */ export default (element: ReactElement, styles = {}, configuration = {}): ReactElement => { // @see https://github.com/gajus/react-css-modules/pull/30 - if (!_.isObject(element)) { + if (!isObject(element)) { return element; } diff --git a/src/makeConfiguration.js b/src/makeConfiguration.js index 83b2d41..f6e77da 100644 --- a/src/makeConfiguration.js +++ b/src/makeConfiguration.js @@ -1,5 +1,3 @@ -import _ from 'lodash'; - /** * @typedef CSSModules~Options * @see {@link https://github.com/gajus/react-css-modules#options} @@ -17,12 +15,14 @@ export default (userConfiguration = {}) => { errorWhenNotFound: true }; - _.forEach(userConfiguration, (value, name) => { - if (_.isUndefined(configuration[name])) { + Object.keys(userConfiguration).forEach(name => { + const value = userConfiguration[name]; + + if (!(name in configuration)) { throw new Error('Unknown configuration property "' + name + '".'); } - if (!_.isBoolean(value)) { + if (value !== true && value !== false) { throw new Error('"' + name + '" property value must be a boolean.'); } diff --git a/src/parseStyleName.js b/src/parseStyleName.js index 39c328a..be5ec8a 100644 --- a/src/parseStyleName.js +++ b/src/parseStyleName.js @@ -1,5 +1,3 @@ -import _ from 'lodash'; - const styleNameIndex = {}; export default (styleNamePropertyValue: string, allowMultiple: boolean): Array => { @@ -8,8 +6,7 @@ export default (styleNamePropertyValue: string, allowMultiple: boolean): Array !!e); styleNameIndex[styleNamePropertyValue] = styleNames; } diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..a134350 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,10 @@ +export function isObject(obj) { + return obj === Object(obj); +} + +export function isFunction(func) { + return ( + Object.prototype.toString.call(func) === '[object Function]' + || Object.prototype.toString.call(func) === '[object GeneratorFunction]' + ); +} \ No newline at end of file diff --git a/src/wrapStatelessFunction.js b/src/wrapStatelessFunction.js index 878119a..77e6369 100644 --- a/src/wrapStatelessFunction.js +++ b/src/wrapStatelessFunction.js @@ -1,8 +1,8 @@ /* eslint-disable react/prop-types */ -import _ from 'lodash'; import React from 'react'; import linkClass from './linkClass'; +import {isObject} from './utils'; /** * @see https://facebook.github.io/react/blog/2015/09/10/react-v0.14-rc1.html#stateless-function-components @@ -15,8 +15,8 @@ export default (Component: Function, defaultStyles: Object, options: Object): Fu if (props.styles) { useProps = props; styles = props.styles; - } else if (_.isObject(defaultStyles)) { - useProps = _.assign({}, props, { + } else if (isObject(defaultStyles)) { + useProps = Object.assign({}, props, { styles: defaultStyles }); @@ -35,7 +35,7 @@ export default (Component: Function, defaultStyles: Object, options: Object): Fu return React.createElement('noscript'); }; - _.assign(WrappedComponent, Component); + Object.assign(WrappedComponent, Component); return WrappedComponent; }; From db16369bf3572301ec62f9e895f1f88b5b221edf Mon Sep 17 00:00:00 2001 From: Edward Drapkin Date: Sat, 20 Aug 2016 08:21:05 -0400 Subject: [PATCH 2/7] remove lodash dependency --- .babelrc | 1 - 1 file changed, 1 deletion(-) diff --git a/.babelrc b/.babelrc index 197c614..960613b 100644 --- a/.babelrc +++ b/.babelrc @@ -6,7 +6,6 @@ ], "plugins": [ "add-module-exports", - "lodash", "transform-class-properties", ["transform-es2015-classes", { "loose": true }], "transform-proto-to-assign" From 3e737d20cd1a10ea2b209c4547f5b7909a476415 Mon Sep 17 00:00:00 2001 From: Edward Drapkin Date: Sat, 20 Aug 2016 08:34:32 -0400 Subject: [PATCH 3/7] remove lodash dependency --- .babelrc | 3 ++- package.json | 1 + src/index.js | 1 - src/linkClass.js | 4 ++-- src/utils.js | 4 ++++ 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.babelrc b/.babelrc index 960613b..d51020f 100644 --- a/.babelrc +++ b/.babelrc @@ -8,6 +8,7 @@ "add-module-exports", "transform-class-properties", ["transform-es2015-classes", { "loose": true }], - "transform-proto-to-assign" + "transform-proto-to-assign", + "transform-object-assign" ] } diff --git a/package.json b/package.json index ae535cd..e4b1810 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "devDependencies": { "babel-cli": "^6.10.1", "babel-plugin-add-module-exports": "^0.2.1", + "babel-plugin-object-assign": "^1.2.1", "babel-plugin-transform-proto-to-assign": "^6.9.0", "babel-preset-es2015": "^6.9.0", "babel-preset-react": "^6.11.1", diff --git a/src/index.js b/src/index.js index 8fbf7ec..94c1824 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,3 @@ -import _ from 'lodash'; import extendReactClass from './extendReactClass'; import wrapStatelessFunction from './wrapStatelessFunction'; import makeConfiguration from './makeConfiguration'; diff --git a/src/linkClass.js b/src/linkClass.js index 9896a3a..60811c9 100644 --- a/src/linkClass.js +++ b/src/linkClass.js @@ -5,7 +5,7 @@ import objectUnfreeze from 'object-unfreeze'; import isIterable from './isIterable'; import parseStyleName from './parseStyleName'; import generateAppendClassName from './generateAppendClassName'; -import {isObject} from './utils'; +import {isObject, isArray} from './utils'; const linkElement = (element: ReactElement, styles: Object, configuration: Object): ReactElement => { let appendClassName, @@ -26,7 +26,7 @@ const linkElement = (element: ReactElement, styles: Object, configuration: Objec if (React.isValidElement(elementShallowCopy.props.children)) { elementShallowCopy.props.children = linkElement(React.Children.only(elementShallowCopy.props.children), styles, configuration); - } else if (Array.isArray(elementShallowCopy.props.children) || isIterable(elementShallowCopy.props.children)) { + } else if (isArray(elementShallowCopy.props.children) || isIterable(elementShallowCopy.props.children)) { elementShallowCopy.props.children = React.Children.map(elementShallowCopy.props.children, (node) => { if (React.isValidElement(node)) { return linkElement(node, styles, configuration); diff --git a/src/utils.js b/src/utils.js index a134350..6cc7aa4 100644 --- a/src/utils.js +++ b/src/utils.js @@ -7,4 +7,8 @@ export function isFunction(func) { Object.prototype.toString.call(func) === '[object Function]' || Object.prototype.toString.call(func) === '[object GeneratorFunction]' ); +} + +export function isArray(arr) { + return Array.isArray ? Array.isArray(arr) : Object.prototype.toString.call(arr) === '[object Array]'; } \ No newline at end of file From 44ac31db8e08ed312466e5093a549f18ccd2fead Mon Sep 17 00:00:00 2001 From: Edward Drapkin Date: Sat, 20 Aug 2016 08:49:40 -0400 Subject: [PATCH 4/7] get rid of some IE9+ features --- src/makeConfiguration.js | 4 ++-- src/parseStyleName.js | 3 ++- src/utils.js | 17 ++++++++++++++++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/makeConfiguration.js b/src/makeConfiguration.js index f6e77da..313d253 100644 --- a/src/makeConfiguration.js +++ b/src/makeConfiguration.js @@ -15,7 +15,7 @@ export default (userConfiguration = {}) => { errorWhenNotFound: true }; - Object.keys(userConfiguration).forEach(name => { + for(const name in userConfiguration) { const value = userConfiguration[name]; if (!(name in configuration)) { @@ -27,7 +27,7 @@ export default (userConfiguration = {}) => { } configuration[name] = value; - }); + } return configuration; }; diff --git a/src/parseStyleName.js b/src/parseStyleName.js index be5ec8a..a4df6fb 100644 --- a/src/parseStyleName.js +++ b/src/parseStyleName.js @@ -1,4 +1,5 @@ const styleNameIndex = {}; +import {trim, filterForTruthy} from './utils'; export default (styleNamePropertyValue: string, allowMultiple: boolean): Array => { let styleNames; @@ -6,7 +7,7 @@ export default (styleNamePropertyValue: string, allowMultiple: boolean): Array !!e); + styleNames = filterForTruthy(trim(styleNamePropertyValue).split(' ')); styleNameIndex[styleNamePropertyValue] = styleNames; } diff --git a/src/utils.js b/src/utils.js index 6cc7aa4..7eba916 100644 --- a/src/utils.js +++ b/src/utils.js @@ -11,4 +11,19 @@ export function isFunction(func) { export function isArray(arr) { return Array.isArray ? Array.isArray(arr) : Object.prototype.toString.call(arr) === '[object Array]'; -} \ No newline at end of file +} + +export function trim(str) { + return String.prototype.trim ? str.trim() : str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); +} + +export function filterForTruthy(arr) { + const results = []; + for(const key in arr) { + if(arr[key]) { + results.push(arr[key]); + } + } + + return results; +} From 69f06b391349f55ecc6fcdd2f604ef370a98ad45 Mon Sep 17 00:00:00 2001 From: Edward Drapkin Date: Sat, 20 Aug 2016 08:54:06 -0400 Subject: [PATCH 5/7] fix typo in package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e4b1810..52575e0 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "devDependencies": { "babel-cli": "^6.10.1", "babel-plugin-add-module-exports": "^0.2.1", - "babel-plugin-object-assign": "^1.2.1", + "babel-plugin-transform-object-assign": "^6.8.0", "babel-plugin-transform-proto-to-assign": "^6.9.0", "babel-preset-es2015": "^6.9.0", "babel-preset-react": "^6.11.1", From 82d488f2b20c46b27fb667736d64bb1d95a0489b Mon Sep 17 00:00:00 2001 From: Edward Drapkin Date: Sat, 20 Aug 2016 09:03:51 -0400 Subject: [PATCH 6/7] fix eslint errors --- src/extendReactClass.js | 4 +++- src/makeConfiguration.js | 20 +++++++++++--------- src/parseStyleName.js | 3 ++- src/utils.js | 31 ++++++++++++++++--------------- 4 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/extendReactClass.js b/src/extendReactClass.js index 41c2435..f3f4d4b 100644 --- a/src/extendReactClass.js +++ b/src/extendReactClass.js @@ -14,9 +14,11 @@ import {isObject} from './utils'; export default (Component: Object, defaultStyles: Object, options: Object) => { const WrappedComponent = class extends Component { render () { - let propsChanged = false, + let propsChanged, styles; + propsChanged = false; + if (this.props.styles) { styles = this.props.styles; } else if (isObject(defaultStyles)) { diff --git a/src/makeConfiguration.js b/src/makeConfiguration.js index 313d253..757cc56 100644 --- a/src/makeConfiguration.js +++ b/src/makeConfiguration.js @@ -15,18 +15,20 @@ export default (userConfiguration = {}) => { errorWhenNotFound: true }; - for(const name in userConfiguration) { - const value = userConfiguration[name]; + for (const name in userConfiguration) { + if (userConfiguration.hasOwnProperty(name)) { + const value = userConfiguration[name]; - if (!(name in configuration)) { - throw new Error('Unknown configuration property "' + name + '".'); - } + if (!(name in configuration)) { + throw new Error('Unknown configuration property "' + name + '".'); + } - if (value !== true && value !== false) { - throw new Error('"' + name + '" property value must be a boolean.'); - } + if (value !== true && value !== false) { + throw new Error('"' + name + '" property value must be a boolean.'); + } - configuration[name] = value; + configuration[name] = value; + } } return configuration; diff --git a/src/parseStyleName.js b/src/parseStyleName.js index a4df6fb..e0aeb09 100644 --- a/src/parseStyleName.js +++ b/src/parseStyleName.js @@ -1,6 +1,7 @@ -const styleNameIndex = {}; import {trim, filterForTruthy} from './utils'; +const styleNameIndex = {}; + export default (styleNamePropertyValue: string, allowMultiple: boolean): Array => { let styleNames; diff --git a/src/utils.js b/src/utils.js index 7eba916..54d5f7e 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,29 +1,30 @@ -export function isObject(obj) { +export const isObject = function (obj) { return obj === Object(obj); -} +}; -export function isFunction(func) { +export const isFunction = function (func) { return ( - Object.prototype.toString.call(func) === '[object Function]' - || Object.prototype.toString.call(func) === '[object GeneratorFunction]' - ); -} + Object.prototype.toString.call(func) === '[object Function]' || + Object.prototype.toString.call(func) === '[object GeneratorFunction]' + ); +}; -export function isArray(arr) { +export const isArray = function (arr) { return Array.isArray ? Array.isArray(arr) : Object.prototype.toString.call(arr) === '[object Array]'; -} +}; -export function trim(str) { +export const trim = function (str) { return String.prototype.trim ? str.trim() : str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); -} +}; -export function filterForTruthy(arr) { +export const filterForTruthy = function (arr) { const results = []; - for(const key in arr) { - if(arr[key]) { + + for (const key in arr) { + if (arr[key]) { results.push(arr[key]); } } return results; -} +}; From 63cc4f00f047412d47624f1666e0c824041e6bbe Mon Sep 17 00:00:00 2001 From: Edward Drapkin Date: Sat, 20 Aug 2016 09:09:26 -0400 Subject: [PATCH 7/7] fix test linting! --- tests/linkClass.js | 40 ++++++++++++++++++++-------------------- tests/reactCssModules.js | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/tests/linkClass.js b/tests/linkClass.js index d24076b..a6d5219 100644 --- a/tests/linkClass.js +++ b/tests/linkClass.js @@ -11,11 +11,11 @@ import linkClass from './../src/linkClass'; describe('linkClass', () => { context('ReactElement does not define styleName', () => { it('does not affect element properties', () => { - expect(linkClass(
)).to.deep.equal(
); + expect(linkClass(
)).to.deep.equal(
); }); it('does not affect element properties with a single element child', () => { - expect(linkClass(

)).to.deep.equal(

); + expect(linkClass(

)).to.deep.equal(

); }); it('does not affect element properties with a single text child', () => { @@ -23,7 +23,7 @@ describe('linkClass', () => { }); it('does not affect the className', () => { - expect(linkClass(
)).to.deep.equal(
); + expect(linkClass(
)).to.deep.equal(
); }); xit('does not affect element with a single children when that children is contained in an array', () => { @@ -71,7 +71,7 @@ describe('linkClass', () => { let subject; subject =
-

+

; subject = linkClass(subject, { @@ -86,8 +86,8 @@ describe('linkClass', () => { let subject; subject =
-

-

+

+

; subject = linkClass(subject, { @@ -102,8 +102,8 @@ describe('linkClass', () => { let subject; subject =
-

-

+

+

; subject = linkClass(subject, { @@ -120,8 +120,8 @@ describe('linkClass', () => { let subject; const iterable = { - 0:

, - 1:

, + 0:

, + 1:

, length: 2, /* eslint-disable no-use-extend-native/no-use-extend-native */ [Symbol.iterator]: Array.prototype[Symbol.iterator] @@ -143,7 +143,7 @@ describe('linkClass', () => { it('uses the generated class name to set the className property', () => { let subject; - subject =

; + subject =
; subject = linkClass(subject, { foo: 'foo-1' @@ -156,7 +156,7 @@ describe('linkClass', () => { it('appends the generated class name to the className property', () => { let subject; - subject =
; + subject =
; subject = linkClass(subject, { bar: 'bar-1' @@ -172,7 +172,7 @@ describe('linkClass', () => { let subject; subject =
-

+

; subject = linkClass(subject, { @@ -191,7 +191,7 @@ describe('linkClass', () => { context('when false', () => { it('throws an error', () => { expect(() => { - linkClass(
, {}, {allowMultiple: false}); + linkClass(
, {}, {allowMultiple: false}); }).to.throw(Error, 'ReactElement styleName property defines multiple module names ("foo bar").'); }); }); @@ -199,7 +199,7 @@ describe('linkClass', () => { it('appends a generated class name for every referenced CSS module', () => { let subject; - subject =
; + subject =
; subject = linkClass(subject, { bar: 'bar-1', @@ -220,7 +220,7 @@ describe('linkClass', () => { it('ignores the missing CSS module', () => { let subject; - subject =
; + subject =
; subject = linkClass(subject, {}, {errorWhenNotFound: false}); @@ -230,7 +230,7 @@ describe('linkClass', () => { context('when is true', () => { it('throws an error', () => { expect(() => { - linkClass(
, {}, {errorWhenNotFound: true}); + linkClass(
, {}, {errorWhenNotFound: true}); }).to.throw(Error, '"foo" CSS module is undefined.'); }); }); @@ -264,7 +264,7 @@ describe('linkClass', () => { it('deletes styleName property from the target element', () => { let subject; - subject =
; + subject =
; subject = linkClass(subject, { foo: 'foo-1' @@ -278,8 +278,8 @@ describe('linkClass', () => { let subject; subject =
-
-
+
+
; subject = linkClass(subject, { diff --git a/tests/reactCssModules.js b/tests/reactCssModules.js index 44f7ad6..3d11c9b 100644 --- a/tests/reactCssModules.js +++ b/tests/reactCssModules.js @@ -174,7 +174,7 @@ describe('reactCssModules', () => { subject = TestUtils.renderIntoDocument(); - subject = ReactDOM.findDOMNode(subject); + subject = ReactDOM.findDOMNode(subject); // eslint-disable-line react/no-find-dom-node expect(subject.firstChild.className).to.equal('foo-0'); });