Skip to content
This repository was archived by the owner on Mar 23, 2024. It is now read-only.

Commit ef9ed5e

Browse files
AlexanderOMaramarkelog
authored andcommitted
New rule: requireCapitalizedConstructorsNew
Valid var a = new B(); Invalid var d = E(); Added a new rule that behaves closer to the behavior of "newcap" in jshint Fixes #2046 Closes gh-2047
1 parent 63db340 commit ef9ed5e

File tree

3 files changed

+129
-0
lines changed

3 files changed

+129
-0
lines changed

lib/config/configuration.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,6 +1077,7 @@ Configuration.prototype.registerDefaultRules = function() {
10771077
this.registerRule(require('../rules/disallow-space-between-arguments'));
10781078

10791079
this.registerRule(require('../rules/require-capitalized-constructors'));
1080+
this.registerRule(require('../rules/require-capitalized-constructors-new'));
10801081

10811082
this.registerRule(require('../rules/safe-context-keyword'));
10821083

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* Requires capitalized constructors to to use the `new` keyword
3+
*
4+
* Types: `Boolean` or `Object`
5+
*
6+
* Values: `true` or Object with `allExcept` Array of quoted identifiers which are exempted
7+
*
8+
* JSHint: [`newcap`](http://jshint.com/docs/options/#newcap)
9+
*
10+
* #### Example
11+
*
12+
* ```js
13+
* "requireCapitalizedConstructors": true
14+
* "requireCapitalizedConstructors": {
15+
* "allExcept": ["SomethingNative"]
16+
* }
17+
* ```
18+
*
19+
* ##### Valid
20+
*
21+
* ```js
22+
* var a = new B();
23+
* var c = SomethingNative();
24+
* ```
25+
*
26+
* ##### Invalid
27+
*
28+
* ```js
29+
* var d = E();
30+
* ```
31+
*/
32+
33+
var assert = require('assert');
34+
35+
module.exports = function() {};
36+
37+
module.exports.prototype = {
38+
configure: function(options) {
39+
assert(
40+
options === true || Array.isArray(options.allExcept),
41+
this.getOptionName() + ' option requires a true value or an object of exceptions'
42+
);
43+
this._allowedConstructors = {};
44+
45+
var allExcept = options.allExcept;
46+
if (allExcept) {
47+
for (var i = 0, l = allExcept.length; i < l; i++) {
48+
this._allowedConstructors[allExcept[i]] = true;
49+
}
50+
}
51+
},
52+
53+
getOptionName: function() {
54+
return 'requireCapitalizedConstructorsNew';
55+
},
56+
57+
check: function(file, errors) {
58+
var allowedConstructors = this._allowedConstructors;
59+
60+
file.iterateNodesByType('CallExpression', function(node) {
61+
if (node.callee.type === 'Identifier' &&
62+
!allowedConstructors[node.callee.name] &&
63+
node.callee.name[0].toLowerCase() !== node.callee.name[0]
64+
) {
65+
errors.add(
66+
'Constructor functions should use the "new" keyword',
67+
node.callee.loc.start.line,
68+
node.callee.loc.start.column
69+
);
70+
}
71+
});
72+
}
73+
74+
};
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
var Checker = require('../../../lib/checker');
2+
var expect = require('chai').expect;
3+
4+
describe('rules/require-capitalized-constructors-new', function() {
5+
var checker;
6+
7+
function baseCases() {
8+
it('should report capitalized constructors without the "new" keyword', function() {
9+
expect(checker.checkString('var x = Y();'))
10+
.to.have.one.validation.error.from('requireCapitalizedConstructorsNew');
11+
});
12+
13+
it('should not report capitalized construction', function() {
14+
expect(checker.checkString('var x = new Y();')).to.have.no.errors();
15+
});
16+
17+
it('should not report member expression construction', function() {
18+
expect(checker.checkString('var x = ns.Y();')).to.have.no.errors();
19+
});
20+
21+
it('should not report lowercase function calls', function() {
22+
expect(checker.checkString('var x = y();')).to.have.no.errors();
23+
});
24+
}
25+
26+
beforeEach(function() {
27+
checker = new Checker();
28+
checker.registerDefaultRules();
29+
});
30+
31+
describe('with `true` value', function() {
32+
beforeEach(function() {
33+
checker.configure({ requireCapitalizedConstructorsNew: true });
34+
});
35+
36+
baseCases();
37+
});
38+
39+
describe('with `allExcept` value', function() {
40+
beforeEach(function() {
41+
checker.configure({
42+
requireCapitalizedConstructorsNew: {
43+
allExcept: ['SomethingNative']
44+
}
45+
});
46+
});
47+
48+
baseCases();
49+
50+
it('should not report exempted construction', function() {
51+
expect(checker.checkString('var x = SomethingNative();')).to.have.no.errors();
52+
});
53+
});
54+
});

0 commit comments

Comments
 (0)