Skip to content
This repository was archived by the owner on Jan 19, 2019. It is now read-only.

Commit bdf759a

Browse files
committed
Fix: camelcase properties in interfaces (fixes #177)
1 parent e936298 commit bdf759a

File tree

4 files changed

+295
-7
lines changed

4 files changed

+295
-7
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ Then configure the rules you want to use under the rules section.
5252
<!-- Please run `npm run docs` to update this section -->
5353
<!-- begin rule list -->
5454
* [`typescript/adjacent-overload-signatures`](./docs/rules/adjacent-overload-signatures.md) — Require that member overloads be consecutive
55+
* [`typescript/camelcase`](./docs/rules/camelcase.md) — Enforce camelCase naming convention
5556
* [`typescript/class-name-casing`](./docs/rules/class-name-casing.md) — Require PascalCased class and interface names (`class-name` from TSLint)
5657
* [`typescript/explicit-function-return-type`](./docs/rules/explicit-function-return-type.md) — Require explicit return types on functions and class methods
5758
* [`typescript/explicit-member-accessibility`](./docs/rules/explicit-member-accessibility.md) — Require explicit accessibility modifiers on class properties and methods (`member-access` from TSLint)

docs/rules/camelcase.md

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
# Enforce camelCase naming convention (camelcase)
2+
3+
When it comes to naming variables, style guides generally fall into one of two
4+
camps: camelcase (`variableName`) and underscores (`variable_name`). This rule
5+
focuses on using the camelcase approach. If your style guide calls for
6+
camelCasing your variable names, then this rule is for you!
7+
8+
## Rule Details
9+
10+
This rule looks for any underscores (`_`) located within the source code.
11+
It ignores leading and trailing underscores and only checks those in the middle
12+
of a variable name. If ESLint decides that the variable is a constant
13+
(all uppercase), then no warning will be thrown. Otherwise, a warning will be
14+
thrown. This rule only flags definitions and assignments but not function calls.
15+
In case of ES6 `import` statements, this rule only targets the name of the
16+
variable that will be imported into the local module scope.
17+
18+
***This rule was taken from the ESLint core rule `camelcase`.***
19+
***Available options and test cases may vary depending on the version of ESLint installed in the system.***
20+
21+
## Options
22+
23+
This rule has an object option:
24+
25+
* `"properties": "always"` (default) enforces camelcase style for property names
26+
* `"properties": "never"` does not check property names
27+
* `"ignoreDestructuring": false` (default) enforces camelcase style for destructured identifiers
28+
* `"ignoreDestructuring": true` does not check destructured identifiers
29+
* `allow` (`string[]`) list of properties to accept. Accept regex.
30+
31+
### properties: "always"
32+
33+
Examples of **incorrect** code for this rule with the default `{ "properties": "always" }` option:
34+
35+
```js
36+
/*eslint camelcase: "error"*/
37+
38+
import { no_camelcased } from "external-module"
39+
40+
var my_favorite_color = "#112C85";
41+
42+
function do_something() {
43+
// ...
44+
}
45+
46+
obj.do_something = function() {
47+
// ...
48+
};
49+
50+
function foo({ no_camelcased }) {
51+
// ...
52+
};
53+
54+
function foo({ isCamelcased: no_camelcased }) {
55+
// ...
56+
}
57+
58+
function foo({ no_camelcased = 'default value' }) {
59+
// ...
60+
};
61+
62+
var obj = {
63+
my_pref: 1
64+
};
65+
66+
var { category_id = 1 } = query;
67+
68+
var { foo: no_camelcased } = bar;
69+
70+
var { foo: bar_baz = 1 } = quz;
71+
```
72+
73+
Examples of **correct** code for this rule with the default `{ "properties": "always" }` option:
74+
75+
```js
76+
/*eslint camelcase: "error"*/
77+
78+
import { no_camelcased as camelCased } from "external-module";
79+
80+
var myFavoriteColor = "#112C85";
81+
var _myFavoriteColor = "#112C85";
82+
var myFavoriteColor_ = "#112C85";
83+
var MY_FAVORITE_COLOR = "#112C85";
84+
var foo = bar.baz_boom;
85+
var foo = { qux: bar.baz_boom };
86+
87+
obj.do_something();
88+
do_something();
89+
new do_something();
90+
91+
var { category_id: category } = query;
92+
93+
function foo({ isCamelCased }) {
94+
// ...
95+
};
96+
97+
function foo({ isCamelCased: isAlsoCamelCased }) {
98+
// ...
99+
}
100+
101+
function foo({ isCamelCased = 'default value' }) {
102+
// ...
103+
};
104+
105+
var { categoryId = 1 } = query;
106+
107+
var { foo: isCamelCased } = bar;
108+
109+
var { foo: isCamelCased = 1 } = quz;
110+
111+
```
112+
113+
### properties: "never"
114+
115+
Examples of **correct** code for this rule with the `{ "properties": "never" }` option:
116+
117+
```js
118+
/*eslint camelcase: ["error", {properties: "never"}]*/
119+
120+
var obj = {
121+
my_pref: 1
122+
};
123+
```
124+
125+
### ignoreDestructuring: false
126+
127+
Examples of **incorrect** code for this rule with the default `{ "ignoreDestructuring": false }` option:
128+
129+
```js
130+
/*eslint camelcase: "error"*/
131+
132+
var { category_id } = query;
133+
134+
var { category_id = 1 } = query;
135+
136+
var { category_id: category_id } = query;
137+
138+
var { category_id: category_alias } = query;
139+
140+
var { category_id: categoryId, ...other_props } = query;
141+
```
142+
143+
### ignoreDestructuring: true
144+
145+
Examples of **incorrect** code for this rule with the `{ "ignoreDestructuring": true }` option:
146+
147+
```js
148+
/*eslint camelcase: ["error", {ignoreDestructuring: true}]*/
149+
150+
var { category_id: category_alias } = query;
151+
152+
var { category_id, ...other_props } = query;
153+
```
154+
155+
Examples of **correct** code for this rule with the `{ "ignoreDestructuring": true }` option:
156+
157+
```js
158+
/*eslint camelcase: ["error", {ignoreDestructuring: true}]*/
159+
160+
var { category_id } = query;
161+
162+
var { category_id = 1 } = query;
163+
164+
var { category_id: category_id } = query;
165+
```
166+
167+
## allow
168+
169+
Examples of **correct** code for this rule with the `allow` option:
170+
171+
```js
172+
/*eslint camelcase: ["error", {allow: ["UNSAFE_componentWillMount"]}]*/
173+
174+
function UNSAFE_componentWillMount() {
175+
// ...
176+
}
177+
```
178+
179+
```js
180+
/*eslint camelcase: ["error", {allow: ["^UNSAFE_"]}]*/
181+
182+
function UNSAFE_componentWillMount() {
183+
// ...
184+
}
185+
186+
function UNSAFE_componentWillMount() {
187+
// ...
188+
}
189+
```
190+
191+
## When Not To Use It
192+
193+
If you have established coding standards using a different naming convention (separating words with underscores), turn this rule off.
194+
195+
<sup>Taken with ❤️ [from ESLint core](https://github.com/eslint/eslint/blob/master/docs/rules/camelcase.md)</sup>

lib/rules/camelcase.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/**
2+
* @fileoverview Rule to flag non-camelcased identifiers
3+
* @author Patricio Trevino
4+
*/
5+
"use strict";
6+
7+
const baseRule = require("eslint/lib/rules/camelcase");
8+
9+
//------------------------------------------------------------------------------
10+
// Rule Definition
11+
//------------------------------------------------------------------------------
12+
13+
module.exports = {
14+
meta: Object.assign({}, baseRule.meta, {
15+
docs: {
16+
description: "Enforce camelCase naming convention"
17+
}
18+
}),
19+
20+
create(context) {
21+
const rules = baseRule.create(context);
22+
23+
const options = context.options[0] || {};
24+
let properties = options.properties || "";
25+
const allow = options.allow || [];
26+
27+
if (properties !== "always" && properties !== "never") {
28+
properties = "always";
29+
}
30+
31+
/**
32+
* Checks if a string contains an underscore and isn't all upper-case
33+
* @param {string} name The string to check.
34+
* @returns {boolean} if the string is underscored
35+
* @private
36+
*/
37+
function isUnderscored(name) {
38+
// if there's an underscore, it might be A_CONSTANT, which is okay
39+
return name.indexOf("_") > -1 && name !== name.toUpperCase();
40+
}
41+
42+
/**
43+
* Checks if a string match the ignore list
44+
* @param {string} name The string to check.
45+
* @returns {boolean} if the string is ignored
46+
* @private
47+
*/
48+
function isAllowed(name) {
49+
return (
50+
allow.findIndex(
51+
entry => name === entry || name.match(new RegExp(entry))
52+
) !== -1
53+
);
54+
}
55+
56+
return {
57+
Identifier(node) {
58+
/*
59+
* Leading and trailing underscores are commonly used to flag
60+
* private/protected identifiers, strip them
61+
*/
62+
const name = node.name.replace(/^_+|_+$/g, "");
63+
64+
// First, we ignore the node if it match the ignore list
65+
if (isAllowed(name)) {
66+
return;
67+
}
68+
69+
// Check TypeScript specific nodes
70+
if (node.parent && node.parent.type === "TSPropertySignature") {
71+
if (properties === "always" && isUnderscored(name)) {
72+
context.report({
73+
node,
74+
messageId: "notCamelCase",
75+
data: { name: node.name }
76+
});
77+
}
78+
79+
return;
80+
}
81+
82+
// Let the base rule deal with the rest
83+
// eslint-disable-next-line new-cap
84+
rules.Identifier(node);
85+
}
86+
};
87+
}
88+
};

tests/lib/rules/camelcase.js

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
/**
22
* @fileoverview Tests for camelcase rule
3-
* @author Guy Lilian & Shahar Or
3+
* @author Guy Lilian
4+
* @author Shahar Or
5+
* @author Patricio Trevino
46
*/
57
"use strict";
68

79
//------------------------------------------------------------------------------
810
// Requirements
911
//------------------------------------------------------------------------------
1012

11-
const ruleCamelcase = require("eslint/lib/rules/camelcase");
13+
const ruleCamelcase = require("../../../lib/rules/camelcase");
1214
const RuleTester = require("eslint").RuleTester;
1315

14-
const parser = "typescript-eslint-parser";
15-
16-
const ruleTester = new RuleTester();
16+
const ruleTester = new RuleTester({
17+
parser: "typescript-eslint-parser"
18+
});
1719

1820
//------------------------------------------------------------------------------
1921
// Tests
@@ -23,15 +25,17 @@ ruleTester.run("camelcase", ruleCamelcase, {
2325
valid: [
2426
{
2527
code: "interface Foo { b_ar: null }",
26-
parser,
2728
options: [{ properties: "never" }]
29+
},
30+
{
31+
code: "interface Foo { bar: null }",
32+
options: [{ properties: "always" }]
2833
}
2934
],
3035

3136
invalid: [
3237
{
3338
code: "interface Foo { b_ar: null }",
34-
parser,
3539
options: [{ properties: "always" }],
3640
errors: [
3741
{

0 commit comments

Comments
 (0)