From 6969969d87a51e5f6b1e9f52ee8bcb2b728371f5 Mon Sep 17 00:00:00 2001 From: Pablo Chiappetti Date: Wed, 26 Jul 2017 02:43:05 -0300 Subject: [PATCH 1/3] implement handleNotFoundStyleName --- README.md | 18 ++++++++----- package.json | 1 + src/generateAppendClassName.js | 12 ++++++--- src/linkClass.js | 2 +- src/makeConfiguration.js | 12 ++++++--- tests/linkClass.js | 46 +++++++++++++++++++++++----------- tests/makeConfiguration.js | 6 ++--- 7 files changed, 65 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 4721800..6cf9f96 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ React CSS Modules implement automatic mapping of CSS modules. Every CSS class is - [Decorator](#decorator) - [Options](#options) - [`allowMultiple`](#allowmultiple) - - [`errorWhenNotFound`](#errorwhennotfound) + - [`handleNotFoundStyleName`](#handlenotfoundstylename) - [SASS, SCSS, LESS and other CSS Preprocessors](#sass-scss-less-and-other-css-preprocessors) - [Enable Sourcemaps](#enable-sourcemaps) - [Class Composition](#class-composition) @@ -127,7 +127,7 @@ Using `react-css-modules`:
``` -* You are warned when `styleName` refers to an undefined CSS Module ([`errorWhenNotFound`](#errorwhennotfound) option). +* You are warned when `styleName` refers to an undefined CSS Module ([`handleNotFoundStyleName`](#handlenotfoundstylename) option). * You can enforce use of a single CSS module per `ReactElement` ([`allowMultiple`](#allowmultiple) option). ## The Implementation @@ -408,7 +408,7 @@ export default CSSModules(CustomList, styles); * @typedef CSSModules~Options * @see {@link https://github.com/gajus/react-css-modules#options} * @property {Boolean} allowMultiple - * @property {Boolean} errorWhenNotFound + * @property {String} handleNotFoundStyleName */ /** @@ -492,11 +492,17 @@ When `false`, the following will cause an error:
``` -#### `errorWhenNotFound` +#### `handleNotFoundStyleName` -Default: `true`. +Default: `'throw'`. -Throws an error when `styleName` cannot be mapped to an existing CSS Module. +Define the desired action when `styleName` cannot be mapped to an existing CSS Module. + +Available options + +- `'throw'` will throw an error +- `'log'` will log a warning to the console +- `'ignore'` will silently ignore it ## SASS, SCSS, LESS and other CSS Preprocessors diff --git a/package.json b/package.json index 3253cc6..e276aa4 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "babel-preset-stage-0": "^6.16.0", "babel-register": "^6.18.0", "chai": "^4.0.0-canary.1", + "chai-spies": "^0.7.1", "eslint": "^3.10.0", "eslint-config-canonical": "^5.5.0", "husky": "^0.11.9", diff --git a/src/generateAppendClassName.js b/src/generateAppendClassName.js index 9479698..4e97430 100644 --- a/src/generateAppendClassName.js +++ b/src/generateAppendClassName.js @@ -4,7 +4,7 @@ const CustomMap = typeof Map === 'undefined' ? SimpleMap : Map; const stylesIndex = new CustomMap(); -export default (styles, styleNames: Array, errorWhenNotFound: boolean): string => { +export default (styles, styleNames: Array, handleNotFoundStyleName: "throw" | "log" | "ignore"): string => { let appendClassName; let stylesIndexMap; @@ -29,8 +29,14 @@ export default (styles, styleNames: Array, errorWhenNotFound: boolean): if (className) { appendClassName += ' ' + className; - } else if (errorWhenNotFound === true) { - throw new Error('"' + styleNames[styleName] + '" CSS module is undefined.'); + } else { + if (handleNotFoundStyleName === 'throw') { + throw new Error('"' + styleNames[styleName] + '" CSS module is undefined.'); + } + if (handleNotFoundStyleName === 'log') { + //eslint-disable-next-line + console.warn('"' + styleNames[styleName] + '" CSS module is undefined.'); + } } } } diff --git a/src/linkClass.js b/src/linkClass.js index 1a05878..959d599 100644 --- a/src/linkClass.js +++ b/src/linkClass.js @@ -68,7 +68,7 @@ const linkElement = (element: ReactElement, styles: Object, configuration: Objec }); if (styleNames.length) { - appendClassName = generateAppendClassName(styles, styleNames, configuration.errorWhenNotFound); + appendClassName = generateAppendClassName(styles, styleNames, configuration.handleNotFoundStyleName); if (appendClassName) { if (elementShallowCopy.props.className) { diff --git a/src/makeConfiguration.js b/src/makeConfiguration.js index 0eae15f..2e3a2d6 100644 --- a/src/makeConfiguration.js +++ b/src/makeConfiguration.js @@ -4,7 +4,7 @@ import _ from 'lodash'; * @typedef CSSModules~Options * @see {@link https://github.com/gajus/react-css-modules#options} * @property {boolean} allowMultiple - * @property {boolean} errorWhenNotFound + * @property {string} handleNotFoundStyleName */ /** @@ -14,7 +14,7 @@ import _ from 'lodash'; export default (userConfiguration = {}) => { const configuration = { allowMultiple: false, - errorWhenNotFound: true + handleNotFoundStyleName: 'throw' }; _.forEach(userConfiguration, (value, name) => { @@ -22,8 +22,12 @@ export default (userConfiguration = {}) => { throw new Error('Unknown configuration property "' + name + '".'); } - if (!_.isBoolean(value)) { - throw new Error('"' + name + '" property value must be a boolean.'); + if (name === 'allowMultiple' && !_.isBoolean(value)) { + throw new Error('"allowMultiple" property value must be a boolean.'); + } + + if (name === 'handleNotFoundStyleName' && !['throw', 'log', 'ignore'].includes(value)) { + throw new Error('"handleNotFoundStyleName" property value must be "throw", "log" or "ignore".'); } configuration[name] = value; diff --git a/tests/linkClass.js b/tests/linkClass.js index 0475563..fdda06b 100644 --- a/tests/linkClass.js +++ b/tests/linkClass.js @@ -1,13 +1,16 @@ -/* eslint-disable max-nested-callbacks, react/prefer-stateless-function, class-methods-use-this */ +/* eslint-disable max-nested-callbacks, react/prefer-stateless-function, class-methods-use-this, no-console */ -import { +import chai, { expect } from 'chai'; +import spies from 'chai-spies'; import React from 'react'; import TestUtils from 'react-addons-test-utils'; import jsdom from 'jsdom'; import linkClass from './../src/linkClass'; +chai.use(spies); + describe('linkClass', () => { context('ReactElement does not define styleName', () => { it('does not affect element properties', () => { @@ -264,24 +267,37 @@ describe('linkClass', () => { }); }); - describe('options.errorWhenNotFound', () => { + describe('options.handleNotFoundStyleName', () => { context('when styleName does not match an existing CSS module', () => { - context('when false', () => { - it('ignores the missing CSS module', () => { - let subject; - - subject =
; - - subject = linkClass(subject, {}, {errorWhenNotFound: false}); + context('when throw', () => { + it('throws an error', () => { + expect(() => { + linkClass(
, {}, {handleNotFoundStyleName: 'throw'}); + }).to.throw(Error, '"foo" CSS module is undefined.'); + }); + }); + context('when log', () => { + it('logs a warning to the console', () => { + const warnSpy = chai.spy(() => {}); - expect(subject.props.className).to.be.an('undefined'); + console.warn = warnSpy; + linkClass(
, {}, {handleNotFoundStyleName: 'log'}); + expect(warnSpy).to.have.been.called(); }); }); - context('when is true', () => { - it('throws an error', () => { + context('when ignore', () => { + it('does not log a warning', () => { + const warnSpy = chai.spy(() => {}); + + console.warn = warnSpy; + linkClass(
, {}, {handleNotFoundStyleName: 'ignore'}); + expect(warnSpy).to.not.have.been.called(); + }); + + it('does not throw an error', () => { expect(() => { - linkClass(
, {}, {errorWhenNotFound: true}); - }).to.throw(Error, '"foo" CSS module is undefined.'); + linkClass(
, {}, {handleNotFoundStyleName: 'ignore'}); + }).to.not.throw(Error, '"foo" CSS module is undefined.'); }); }); }); diff --git a/tests/makeConfiguration.js b/tests/makeConfiguration.js index 94129fc..4193311 100644 --- a/tests/makeConfiguration.js +++ b/tests/makeConfiguration.js @@ -17,9 +17,9 @@ describe('makeConfiguration', () => { expect(configuration.allowMultiple).to.equal(false); }); }); - describe('errorWhenNotFound property', () => { - it('defaults to true', () => { - expect(configuration.errorWhenNotFound).to.equal(true); + describe('handleNotFoundStyleName property', () => { + it('defaults to "throw"', () => { + expect(configuration.handleNotFoundStyleName).to.equal('throw'); }); }); }); From b89ffc9497ced173fad143e6b46d97f2a234c243 Mon Sep 17 00:00:00 2001 From: Pablo Chiappetti Date: Wed, 26 Jul 2017 02:56:16 -0300 Subject: [PATCH 2/3] disable linter only for console --- src/generateAppendClassName.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generateAppendClassName.js b/src/generateAppendClassName.js index 4e97430..127aa2a 100644 --- a/src/generateAppendClassName.js +++ b/src/generateAppendClassName.js @@ -34,7 +34,7 @@ export default (styles, styleNames: Array, handleNotFoundStyleName: "thr throw new Error('"' + styleNames[styleName] + '" CSS module is undefined.'); } if (handleNotFoundStyleName === 'log') { - //eslint-disable-next-line + // eslint-disable-next-line no-console console.warn('"' + styleNames[styleName] + '" CSS module is undefined.'); } } From 2336fc7ee4a4433576bab4b409e55949c47e285f Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Wed, 26 Jul 2017 21:01:30 +0100 Subject: [PATCH 3/3] docs: reword --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 6cf9f96..02e006d 100644 --- a/README.md +++ b/README.md @@ -494,15 +494,15 @@ When `false`, the following will cause an error: #### `handleNotFoundStyleName` -Default: `'throw'`. +Default: `throw`. -Define the desired action when `styleName` cannot be mapped to an existing CSS Module. +Defines the desired action when `styleName` cannot be mapped to an existing CSS Module. -Available options +Available options: -- `'throw'` will throw an error -- `'log'` will log a warning to the console -- `'ignore'` will silently ignore it +* `throw` throws an error +* `log` logs a warning using `console.warn` +* `ignore` silently ignores the missing style name ## SASS, SCSS, LESS and other CSS Preprocessors