diff --git a/README.md b/README.md index 0c8132c1b..9eb46ff62 100644 --- a/README.md +++ b/README.md @@ -487,6 +487,26 @@ Example configuration: */ "disallowImplicitTypeConversion": ["numeric", "boolean", "binary", "string"], + /* + Option: requireCamelCaseOrUpperCaseIdentifiers + Requires identifiers to be camelCased or UPPERCASE_WITH_UNDERSCORES + + Valid example: + + var camelCase = 0; + var CamelCase = 1; + var _camelCase = 2; + var camelCase_ = 3; + var UPPER_CASE = 4; + + Invalid examples: + + var lower_case = 1; + var Mixed_case = 2; + var mixed_Case = 3; + */ + "requireCamelCaseOrUpperCaseIdentifiers": true, + /* Option: disallowKeywords Disallows usage of specified keywords. @@ -617,7 +637,7 @@ Example configuration: /* Option: additionalRules - Pluggable rules + Pluggable rules */ "additionalRules": ["project-rules/*.js"], diff --git a/lib/rules/require-camelcase-or-uppercase-identifiers.js b/lib/rules/require-camelcase-or-uppercase-identifiers.js new file mode 100644 index 000000000..dab3c48b4 --- /dev/null +++ b/lib/rules/require-camelcase-or-uppercase-identifiers.js @@ -0,0 +1,40 @@ +var assert = require('assert'); + +module.exports = function() {}; + +module.exports.prototype = { + + configure: function(requireCamelCaseOrUpperCaseIdentifiers) { + assert( + typeof requireCamelCaseOrUpperCaseIdentifiers === 'boolean', + 'requireCamelCaseOrUpperCaseIdentifiers option requires boolean value' + ); + assert( + requireCamelCaseOrUpperCaseIdentifiers === true, + 'requireCamelCaseOrUpperCaseIdentifiers option requires true value or should be removed' + ); + }, + + getOptionName: function () { + return 'requireCamelCaseOrUpperCaseIdentifiers'; + }, + + check: function(file, errors) { + var tokens = file.getTokens(); + errors = errors; + for (var i = 0, l = tokens.length; i < l; i++) { + var token = tokens[i]; + if (token.type === 'Identifier') { + var value = token.value; + if (value.replace(/^_+|_+$/g, '').indexOf('_') > -1 && value.toUpperCase() !== value) { + errors.add( + 'All identifiers must be camelCase or UPPER_CASE', + token.loc.start.line, + token.loc.start.column + ); + } + } + } + } + +}; diff --git a/lib/string-checker.js b/lib/string-checker.js index aae1b5573..b5288b0ee 100644 --- a/lib/string-checker.js +++ b/lib/string-checker.js @@ -44,6 +44,7 @@ StringChecker.prototype = { /* deprecated rules (end) */ this.registerRule(new (require('./rules/disallow-implicit-type-conversion'))()); + this.registerRule(new (require('./rules/require-camelcase-or-uppercase-identifiers'))()); this.registerRule(new (require('./rules/disallow-keywords'))()); this.registerRule(new (require('./rules/disallow-multiple-line-breaks'))()); this.registerRule(new (require('./rules/validate-line-breaks'))()); diff --git a/test/test.require-camelcase-or-uppercase-identifiers.js b/test/test.require-camelcase-or-uppercase-identifiers.js new file mode 100644 index 000000000..d0e96c0d9 --- /dev/null +++ b/test/test.require-camelcase-or-uppercase-identifiers.js @@ -0,0 +1,44 @@ +var Checker = require('../lib/checker'); +var assert = require('assert'); + +describe('rules/require-camelcase-or-uppercase-identifiers', function() { + var checker; + + beforeEach(function() { + checker = new Checker(); + checker.registerDefaultRules(); + checker.configure({ requireCamelCaseOrUpperCaseIdentifiers: true }); + }); + + it('should report inner all-lowercase underscores', function() { + assert(checker.checkString('var x_y = "x";').getErrorCount() === 1); + }); + + it('should report inner some-lowercase underscores', function() { + assert(checker.checkString('var X_y = "x";').getErrorCount() === 1); + }); + + it('should not report inner all-uppercase underscores', function() { + assert(checker.checkString('var X_Y = "x";').isEmpty()); + }); + + it('should not report no underscores', function() { + assert(checker.checkString('var xy = "x";').isEmpty()); + }); + + it('should not report leading underscores', function() { + assert(checker.checkString('var _x = "x", __y = "y";').isEmpty()); + }); + + it('should report trailing underscores', function() { + assert(checker.checkString('var x_ = "x", y__ = "y";').isEmpty()); + }); + + it('should not report underscore.js', function() { + assert(checker.checkString('var extend = _.extend;').isEmpty()); + }); + + it('should not report node globals', function() { + assert(checker.checkString('var a = __dirname + __filename;').isEmpty()); + }); +});