Skip to content

Commit d443bde

Browse files
dmason30ljharb
dmason30
authored andcommitted
[fix] static-property-placement: fix bug with static property refs inside methods
Fixes #2283
1 parent bdd6192 commit d443bde

File tree

4 files changed

+75
-38
lines changed

4 files changed

+75
-38
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ Enable the rules that you would like to use.
143143
* [react/sort-comp](docs/rules/sort-comp.md): Enforce component methods order (fixable)
144144
* [react/sort-prop-types](docs/rules/sort-prop-types.md): Enforce propTypes declarations alphabetical sorting
145145
* [react/state-in-constructor](docs/rules/state-in-constructor.md): Enforce the state initialization style to be either in a constructor or with a class property
146-
* [react/static-property-placement](docs/rules/static-property-placement.md): Defines where React component static properties should be positioned.
146+
* [react/static-property-placement](docs/rules/static-property-placement.md): Enforces where React component static properties should be positioned.
147147
* [react/style-prop-object](docs/rules/style-prop-object.md): Enforce style prop value being an object
148148
* [react/void-dom-elements-no-children](docs/rules/void-dom-elements-no-children.md): Prevent void DOM elements (e.g. `<img />`, `<br />`) from receiving children
149149

docs/rules/static-property-placement.md

+32-32
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,19 @@ and `propTypes` are declared in an ES6 class.
88

99
By default, this rule will check for and warn about declaring any of the above properties outside of the class body.
1010

11-
There are three key options are `static public field`, `static getter`, and `property assignment`.
11+
The three key options are `static public field`, `static getter`, and `property assignment`.
1212

1313
### When `static public field` is enabled (default):
1414

1515
Examples of **incorrect** code for this rule:
1616

1717
```js
1818
class MyComponent extends React.Component {
19-
static get childContextTypes() { /*...*/ }
20-
static get contextTypes() { /*...*/ }
21-
static get contextType() { /*...*/ }
22-
static get displayName() { /*...*/ }
23-
static get defaultProps() { /*...*/ }
19+
static get childContextTypes() { /*...*/ }
20+
static get contextTypes() { /*...*/ }
21+
static get contextType() { /*...*/ }
22+
static get displayName() { /*...*/ }
23+
static get defaultProps() { /*...*/ }
2424
static get propTypes() { /*...*/ }
2525
}
2626
```
@@ -39,11 +39,11 @@ Examples of **correct** code for this rule:
3939

4040
```js
4141
class MyComponent extends React.Component {
42-
static childContextTypes = { /*...*/ };
43-
static contextTypes = { /*...*/ };
44-
static contextType = { /*...*/ };
45-
static displayName = "Hello";
46-
static defaultProps = { /*...*/ };
42+
static childContextTypes = { /*...*/ };
43+
static contextTypes = { /*...*/ };
44+
static contextType = { /*...*/ };
45+
static displayName = "Hello";
46+
static defaultProps = { /*...*/ };
4747
static propTypes = { /*...*/ };
4848
}
4949
```
@@ -54,11 +54,11 @@ Examples of **incorrect** code for this rule:
5454

5555
```js
5656
class MyComponent extends React.Component {
57-
static childContextTypes = { /*...*/ };
58-
static contextTypes = { /*...*/ };
59-
static contextType = { /*...*/ };
60-
static displayName = "Hello";
61-
static defaultProps = { /*...*/ };
57+
static childContextTypes = { /*...*/ };
58+
static contextTypes = { /*...*/ };
59+
static contextType = { /*...*/ };
60+
static displayName = "Hello";
61+
static defaultProps = { /*...*/ };
6262
static propTypes = { /*...*/ };
6363
}
6464
```
@@ -77,11 +77,11 @@ Examples of **correct** code for this rule:
7777

7878
```js
7979
class MyComponent extends React.Component {
80-
static get childContextTypes() { /*...*/ }
81-
static get contextTypes() { /*...*/ }
82-
static get contextType() { /*...*/ }
83-
static get displayName() { /*...*/ }
84-
static get defaultProps() { /*...*/ }
80+
static get childContextTypes() { /*...*/ }
81+
static get contextTypes() { /*...*/ }
82+
static get contextType() { /*...*/ }
83+
static get displayName() { /*...*/ }
84+
static get defaultProps() { /*...*/ }
8585
static get propTypes() { /*...*/ }
8686
}
8787
```
@@ -92,22 +92,22 @@ Examples of **incorrect** code for this rule:
9292

9393
```js
9494
class MyComponent extends React.Component {
95-
static childContextTypes = { /*...*/ };
96-
static contextTypes = { /*...*/ };
97-
static contextType = { /*...*/ };
98-
static displayName = "Hello";
99-
static defaultProps = { /*...*/ };
95+
static childContextTypes = { /*...*/ };
96+
static contextTypes = { /*...*/ };
97+
static contextType = { /*...*/ };
98+
static displayName = "Hello";
99+
static defaultProps = { /*...*/ };
100100
static propTypes = { /*...*/ };
101101
}
102102
```
103103

104104
```js
105105
class MyComponent extends React.Component {
106-
static get childContextTypes() { /*...*/ }
107-
static get contextTypes() { /*...*/ }
108-
static get contextType() { /*...*/ }
109-
static get displayName() { /*...*/ }
110-
static get defaultProps() { /*...*/ }
106+
static get childContextTypes() { /*...*/ }
107+
static get contextTypes() { /*...*/ }
108+
static get contextType() { /*...*/ }
109+
static get displayName() { /*...*/ }
110+
static get defaultProps() { /*...*/ }
111111
static get propTypes() { /*...*/ }
112112
}
113113
```
@@ -159,7 +159,7 @@ The `<string>` value must be one these options:
159159
* `static getter`
160160
* `property assignment`
161161

162-
The `options` schema defined above allows you to specify different rules for the different property fields available.
162+
The `options` schema defined above allows you to specify different rules for the different property fields available.
163163

164164
##### Example configuration:
165165
_This is only an example, we do not recommend this as a configuration._

lib/rules/static-property-placement.js

+13-5
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,10 @@ module.exports = {
8383
// ----------------------------------------------------------------------
8484

8585
/**
86-
* Checks if we are declaring function in class
87-
* @returns {Boolean} True if we are declaring function in class, false if not.
86+
* Checks if we are declaring context in class
87+
* @returns {Boolean} True if we are declaring context in class, false if not.
8888
*/
89-
function isFunctionInClass () {
89+
function isContextInClass() {
9090
let blockNode;
9191
let scope = context.getScope();
9292
while (scope) {
@@ -129,9 +129,17 @@ module.exports = {
129129
ClassProperty: node => reportNodeIncorrectlyPositioned(node, STATIC_PUBLIC_FIELD),
130130

131131
MemberExpression: node => {
132+
// If definition type is undefined then it must not be a defining expression or if the definition is inside a
133+
// class body then skip this node.
134+
const right = node.parent.right;
135+
if (!right || right.type === 'undefined' || isContextInClass()) {
136+
return;
137+
}
138+
139+
// Get the related component
132140
const relatedComponent = utils.getRelatedComponent(node);
133141

134-
// Only check es6 components
142+
// If the related component is not an ES6 component then skip this node
135143
if (!relatedComponent || !utils.isES6Component(relatedComponent.node)) {
136144
return;
137145
}
@@ -142,7 +150,7 @@ module.exports = {
142150

143151
MethodDefinition: node => {
144152
// If the function is inside a class and is static getter then check if correctly positioned
145-
if (isFunctionInClass() && node.static && node.kind === 'get') {
153+
if (isContextInClass() && node.static && node.kind === 'get') {
146154
// Report error if needed
147155
reportNodeIncorrectlyPositioned(node, STATIC_GETTER);
148156
}

tests/lib/rules/static-property-placement.js

+29
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,35 @@ ruleTester.run('static-property-placement', rule, {
10721072
}
10731073
}
10741074
`].join('\n')
1075+
},
1076+
// ------------------------------------------------------------------------------
1077+
// edge cases
1078+
// ------------------------------------------------------------------------------
1079+
{
1080+
// Do not error if property assignment is inside a class function
1081+
code: [`
1082+
class MyComponent extends React.Component {
1083+
static displayName = "Hello";
1084+
1085+
myMethod() {
1086+
console.log(MyComponent.displayName);
1087+
}
1088+
}
1089+
`].join('\n'),
1090+
options: [STATIC_PUBLIC_FIELD]
1091+
},
1092+
{
1093+
// Do not error if display name value changed
1094+
code: [`
1095+
class MyComponent extends React.Component {
1096+
static displayName = "Hello";
1097+
1098+
myMethod() {
1099+
MyComponent.displayName = "Bonjour";
1100+
}
1101+
}
1102+
`].join('\n'),
1103+
options: [STATIC_PUBLIC_FIELD]
10751104
}
10761105
],
10771106

0 commit comments

Comments
 (0)