diff --git a/lib/css-naming.js b/lib/css-naming.js index 166b461..0bc8147 100644 --- a/lib/css-naming.js +++ b/lib/css-naming.js @@ -20,11 +20,21 @@ var bemNaming = require('bem-naming'), * * @constructor * @this {CssNaming} - * @param {string[]} excludes - Исключения для проверки соответствия названий классов БЭМ-нотации + * @param {Object} options - Настройки валидации + * @param {String[]} [options.excludes] - Исключения для проверки соответствия названий классов БЭМ-нотации + * @param {Boolean} [options.requireBlockClass] - Проверять наличие класса блока в селекторе + * @param {Boolean} [options.requireBemNaming] - Проверять соответствие названий классов БЭМ-нотации * @param {CssNaming~errorCallback} errCallback - Обработчик ошибок */ -function CssNaming(excludes, errCallback) { - this._excludeRegexp = excludes && this._buildExcludeRegexp(excludes); +function CssNaming(options, errCallback) { + !options && (options = {}); + + !options.hasOwnProperty('requireBlockClass') && (options.requireBlockClass = true); + !options.hasOwnProperty('requireBemNaming') && (options.requireBemNaming = true); + + this._requireBlockClass = options.requireBlockClass; + this._requireBemNaming = options.requireBemNaming; + this._excludeRegexp = options.excludes && this._buildExcludeRegexp(options.excludes); this._errCallback = errCallback; }; @@ -80,7 +90,7 @@ CssNaming.prototype = { hasTargetBlock |= _this._validateClass(cssClass, blockName, rule); }); - hasTargetBlock || _this._errCallback( + !hasTargetBlock && _this._requireBlockClass && _this._errCallback( 'Selector does not contain block name specified in the file name', rule.selector, ruleStart.line, @@ -107,7 +117,7 @@ CssNaming.prototype = { if (cssEntity) { return cssEntity.block === blockName; } else { - this._errCallback('Invalid class naming', rule.selector, errorLine, cssClassStart.column); + this._requireBemNaming && this._errCallback('Invalid class naming', rule.selector, errorLine, cssClassStart.column); } return false; diff --git a/lib/index.js b/lib/index.js index 51de5bd..ea1257a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -34,7 +34,15 @@ module.exports = { }); } - var validator = new CssNaming(config._config.excludeClasses, addError); + var techConfig = config._config; + + var options = { + excludes: techConfig.excludeClasses, + requireBlockClass: techConfig.requireBlockClass, + requireBemNaming: techConfig.requireBemNaming + }; + + var validator = new CssNaming(options, addError); validator.validateSelectors(tech.content, tech.entity.block); } diff --git a/test/css-naming.js b/test/css-naming.js index 329c8b4..5b0e880 100644 --- a/test/css-naming.js +++ b/test/css-naming.js @@ -37,7 +37,7 @@ describe('css naming', function() { it('if selector was added to exclude but does not contain block name', function() { var errorCallback = sinon.spy(), - validator = new CssNaming(['e_x_c_l_u_d_e'], errorCallback); + validator = new CssNaming({ excludes: ['e_x_c_l_u_d_e'] }, errorCallback); validator.validateSelectors('.e_x_c_l_u_d_e{}', 'block'); @@ -67,11 +67,78 @@ describe('css naming', function() { it('if wrong class was added to excludes', function() { var errorCallback = sinon.spy(), - validator = new CssNaming(['test-*'], errorCallback); + validator = new CssNaming({ excludes: ['test-*'] }, errorCallback); validator.validateSelectors('.block .test-e_x_c_l_u_d_e_d{}', 'block'); assert.notCalled(errorCallback); }); }); + + describe('validation rules switching', function() { + + describe('requireBlockClass option', function() { + + it('validation is performed by default', function() { + var errorCallback = sinon.spy(), + validator = new CssNaming(null, errorCallback); + + validator.validateSelectors('.another-block{}', 'block'); + + assert.called(errorCallback); + assert.calledWith(errorCallback, sinon.match(/not contain block name/)); + }); + + it('validation is performed when option is true', function() { + var errorCallback = sinon.spy(), + validator = new CssNaming({ requireBlockClass: true }, errorCallback); + + validator.validateSelectors('.another-block{}', 'block'); + + assert.called(errorCallback); + assert.calledWith(errorCallback, sinon.match(/not contain block name/)); + }); + + it('validation isn\'t performed when option is false', function() { + var errorCallback = sinon.spy(), + validator = new CssNaming({ requireBlockClass: false }, errorCallback); + + validator.validateSelectors('.another-block{}', 'block'); + + assert.notCalled(errorCallback); + }); + }); + + describe('requireBemNaming option', function() { + + it('validation is performed by default', function() { + var errorCallback = sinon.spy(), + validator = new CssNaming(null, errorCallback); + + validator.validateSelectors('.block .block__el1__el2{}', 'block'); + + assert.called(errorCallback); + assert.calledWith(errorCallback, sinon.match(/Invalid class naming/)); + }); + + it('validation is performed when option is true', function() { + var errorCallback = sinon.spy(), + validator = new CssNaming({ requireBemNaming: true}, errorCallback); + + validator.validateSelectors('.block .block__el1__el2{}', 'block'); + + assert.called(errorCallback); + assert.calledWith(errorCallback, sinon.match(/Invalid class naming/)); + }); + + it('validation isn\'t performed when option is false', function() { + var errorCallback = sinon.spy(), + validator = new CssNaming({ requireBemNaming: false }, errorCallback); + + validator.validateSelectors('.block .block__el1__el2{}', 'block'); + + assert.notCalled(errorCallback); + }) + }); + }); });