Skip to content

Commit a05a72d

Browse files
committed
Add import and destructuring support to no-deprecated
1 parent eae04d4 commit a05a72d

File tree

2 files changed

+154
-43
lines changed

2 files changed

+154
-43
lines changed

lib/rules/no-deprecated.js

Lines changed: 100 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,21 @@
55
*/
66
'use strict';
77

8+
var has = require('has');
9+
var find = require('array.prototype.find');
10+
811
var pragmaUtil = require('../util/pragma');
912
var versionUtil = require('../util/version');
1013

1114
// ------------------------------------------------------------------------------
1215
// Constants
1316
// ------------------------------------------------------------------------------
1417

18+
var MODULES = {
19+
react: ['React'],
20+
'react-addons-perf': ['ReactPerf', 'Perf']
21+
};
22+
1523
var DEPRECATED_MESSAGE = '{{oldMethod}} is deprecated since React {{version}}{{newMethod}}';
1624

1725
// ------------------------------------------------------------------------------
@@ -34,73 +42,123 @@ module.exports = {
3442
var pragma = pragmaUtil.getFromContext(context);
3543

3644
function getDeprecated() {
37-
var deprecated = {
38-
MemberExpression: {}
39-
};
45+
var deprecated = {};
4046
// 0.12.0
41-
deprecated.MemberExpression[pragma + '.renderComponent'] = ['0.12.0', pragma + '.render'];
42-
deprecated.MemberExpression[pragma + '.renderComponentToString'] = ['0.12.0', pragma + '.renderToString'];
43-
deprecated.MemberExpression[pragma + '.renderComponentToStaticMarkup'] = [
44-
'0.12.0',
45-
pragma + '.renderToStaticMarkup'
46-
];
47-
deprecated.MemberExpression[pragma + '.isValidComponent'] = ['0.12.0', pragma + '.isValidElement'];
48-
deprecated.MemberExpression[pragma + '.PropTypes.component'] = ['0.12.0', pragma + '.PropTypes.element'];
49-
deprecated.MemberExpression[pragma + '.PropTypes.renderable'] = ['0.12.0', pragma + '.PropTypes.node'];
50-
deprecated.MemberExpression[pragma + '.isValidClass'] = ['0.12.0'];
51-
deprecated.MemberExpression['this.transferPropsTo'] = ['0.12.0', 'spread operator ({...})'];
47+
deprecated[pragma + '.renderComponent'] = ['0.12.0', pragma + '.render'];
48+
deprecated[pragma + '.renderComponentToString'] = ['0.12.0', pragma + '.renderToString'];
49+
deprecated[pragma + '.renderComponentToStaticMarkup'] = ['0.12.0', pragma + '.renderToStaticMarkup'];
50+
deprecated[pragma + '.isValidComponent'] = ['0.12.0', pragma + '.isValidElement'];
51+
deprecated[pragma + '.PropTypes.component'] = ['0.12.0', pragma + '.PropTypes.element'];
52+
deprecated[pragma + '.PropTypes.renderable'] = ['0.12.0', pragma + '.PropTypes.node'];
53+
deprecated[pragma + '.isValidClass'] = ['0.12.0'];
54+
deprecated['this.transferPropsTo'] = ['0.12.0', 'spread operator ({...})'];
5255
// 0.13.0
53-
deprecated.MemberExpression[pragma + '.addons.classSet'] = ['0.13.0', 'the npm module classnames'];
54-
deprecated.MemberExpression[pragma + '.addons.cloneWithProps'] = ['0.13.0', pragma + '.cloneElement'];
56+
deprecated[pragma + '.addons.classSet'] = ['0.13.0', 'the npm module classnames'];
57+
deprecated[pragma + '.addons.cloneWithProps'] = ['0.13.0', pragma + '.cloneElement'];
5558
// 0.14.0
56-
deprecated.MemberExpression[pragma + '.render'] = ['0.14.0', 'ReactDOM.render'];
57-
deprecated.MemberExpression[pragma + '.unmountComponentAtNode'] = ['0.14.0', 'ReactDOM.unmountComponentAtNode'];
58-
deprecated.MemberExpression[pragma + '.findDOMNode'] = ['0.14.0', 'ReactDOM.findDOMNode'];
59-
deprecated.MemberExpression[pragma + '.renderToString'] = ['0.14.0', 'ReactDOMServer.renderToString'];
60-
deprecated.MemberExpression[pragma + '.renderToStaticMarkup'] = ['0.14.0', 'ReactDOMServer.renderToStaticMarkup'];
59+
deprecated[pragma + '.render'] = ['0.14.0', 'ReactDOM.render'];
60+
deprecated[pragma + '.unmountComponentAtNode'] = ['0.14.0', 'ReactDOM.unmountComponentAtNode'];
61+
deprecated[pragma + '.findDOMNode'] = ['0.14.0', 'ReactDOM.findDOMNode'];
62+
deprecated[pragma + '.renderToString'] = ['0.14.0', 'ReactDOMServer.renderToString'];
63+
deprecated[pragma + '.renderToStaticMarkup'] = ['0.14.0', 'ReactDOMServer.renderToStaticMarkup'];
6164
// 15.0.0
62-
deprecated.MemberExpression[pragma + '.addons.LinkedStateMixin'] = ['15.0.0'];
63-
deprecated.MemberExpression['ReactPerf.printDOM'] = ['15.0.0', 'ReactPerf.printOperations'];
64-
deprecated.MemberExpression['Perf.printDOM'] = ['15.0.0', 'Perf.printOperations'];
65-
deprecated.MemberExpression['ReactPerf.getMeasurementsSummaryMap'] = ['15.0.0', 'ReactPerf.getWasted'];
66-
deprecated.MemberExpression['Perf.getMeasurementsSummaryMap'] = ['15.0.0', 'Perf.getWasted'];
65+
deprecated[pragma + '.addons.LinkedStateMixin'] = ['15.0.0'];
66+
deprecated['ReactPerf.printDOM'] = ['15.0.0', 'ReactPerf.printOperations'];
67+
deprecated['Perf.printDOM'] = ['15.0.0', 'Perf.printOperations'];
68+
deprecated['ReactPerf.getMeasurementsSummaryMap'] = ['15.0.0', 'ReactPerf.getWasted'];
69+
deprecated['Perf.getMeasurementsSummaryMap'] = ['15.0.0', 'Perf.getWasted'];
6770
// 15.5.0
68-
deprecated.MemberExpression[pragma + '.createClass'] = ['15.5.0', 'the npm module create-react-class'];
69-
deprecated.MemberExpression[pragma + '.PropTypes'] = ['15.5.0', 'the npm module prop-types'];
71+
deprecated[pragma + '.createClass'] = ['15.5.0', 'the npm module create-react-class'];
72+
deprecated[pragma + '.PropTypes'] = ['15.5.0', 'the npm module prop-types'];
7073

7174
return deprecated;
7275
}
7376

74-
function isDeprecated(type, method) {
77+
function isDeprecated(method) {
7578
var deprecated = getDeprecated();
7679

7780
return (
78-
deprecated[type] &&
79-
deprecated[type][method] &&
80-
versionUtil.test(context, deprecated[type][method][0])
81+
deprecated &&
82+
deprecated[method] &&
83+
versionUtil.test(context, deprecated[method][0])
8184
);
8285
}
8386

87+
function checkDeprecation(node, method) {
88+
if (!isDeprecated(method)) {
89+
return;
90+
}
91+
var deprecated = getDeprecated();
92+
context.report({
93+
node: node,
94+
message: DEPRECATED_MESSAGE,
95+
data: {
96+
oldMethod: method,
97+
version: deprecated[method][0],
98+
newMethod: deprecated[method][1] ? ', use ' + deprecated[method][1] + ' instead' : ''
99+
}
100+
});
101+
}
102+
103+
function getReactModuleName(node) {
104+
var moduleName = false;
105+
if (!node.init) {
106+
return moduleName;
107+
}
108+
for (var module in MODULES) {
109+
if (!has(MODULES, module)) {
110+
continue;
111+
}
112+
moduleName = find(MODULES[module], function(name) {
113+
return name === node.init.name;
114+
});
115+
if (moduleName) {
116+
break;
117+
}
118+
}
119+
return moduleName;
120+
}
121+
84122
// --------------------------------------------------------------------------
85123
// Public
86124
// --------------------------------------------------------------------------
87125

88126
return {
89127

90128
MemberExpression: function(node) {
91-
var method = sourceCode.getText(node);
92-
if (!isDeprecated(node.type, method)) {
129+
checkDeprecation(node, sourceCode.getText(node));
130+
},
131+
132+
ImportDeclaration: function(node) {
133+
var isReactImport = typeof MODULES[node.source.value] !== 'undefined';
134+
if (!isReactImport) {
93135
return;
94136
}
95-
var deprecated = getDeprecated();
96-
context.report({
97-
node: node,
98-
message: DEPRECATED_MESSAGE,
99-
data: {
100-
oldMethod: method,
101-
version: deprecated[node.type][method][0],
102-
newMethod: deprecated[node.type][method][1] ? ', use ' + deprecated[node.type][method][1] + ' instead' : ''
137+
node.specifiers.forEach(function(specifier) {
138+
if (!specifier.imported) {
139+
return;
103140
}
141+
checkDeprecation(node, MODULES[node.source.value][0] + '.' + specifier.imported.name);
142+
});
143+
},
144+
145+
VariableDeclarator: function(node) {
146+
var reactModuleName = getReactModuleName(node);
147+
var isRequire = node.init && node.init.callee && node.init.callee.name === 'require';
148+
var isReactRequire =
149+
node.init && node.init.arguments &&
150+
node.init.arguments.length && typeof MODULES[node.init.arguments[0].value] !== 'undefined'
151+
;
152+
var isDestructuring = node.id && node.id.type === 'ObjectPattern';
153+
154+
if (
155+
!(isDestructuring && reactModuleName) &&
156+
!(isDestructuring && isRequire && isReactRequire)
157+
) {
158+
return;
159+
}
160+
node.id.properties.forEach(function(property) {
161+
checkDeprecation(node, (reactModuleName || pragma) + '.' + property.key.name);
104162
});
105163
},
106164

tests/lib/rules/no-deprecated.js

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,59 @@ ruleTester.run('no-deprecated', rule, {
111111
errors: [{
112112
message: 'React.PropTypes is deprecated since React 15.5.0, use the npm module prop-types instead'
113113
}]
114+
}, {
115+
code: 'var {createClass} = require(\'react\');',
116+
parser: 'babel-eslint',
117+
errors: [{
118+
message: 'React.createClass is deprecated since React 15.5.0, use the npm module create-react-class instead'
119+
}]
120+
}, {
121+
code: 'var {createClass, PropTypes} = require(\'react\');',
122+
parser: 'babel-eslint',
123+
errors: [{
124+
message: 'React.createClass is deprecated since React 15.5.0, use the npm module create-react-class instead'
125+
}, {
126+
message: 'React.PropTypes is deprecated since React 15.5.0, use the npm module prop-types instead'
127+
}]
128+
}, {
129+
code: 'import {createClass} from \'react\';',
130+
parser: 'babel-eslint',
131+
errors: [{
132+
message: 'React.createClass is deprecated since React 15.5.0, use the npm module create-react-class instead'
133+
}]
134+
}, {
135+
code: 'import {createClass, PropTypes} from \'react\';',
136+
parser: 'babel-eslint',
137+
errors: [{
138+
message: 'React.createClass is deprecated since React 15.5.0, use the npm module create-react-class instead'
139+
}, {
140+
message: 'React.PropTypes is deprecated since React 15.5.0, use the npm module prop-types instead'
141+
}]
142+
}, {
143+
code: [
144+
'import React from \'react\';',
145+
'const {createClass, PropTypes} = React;'
146+
].join('\n'),
147+
parser: 'babel-eslint',
148+
errors: [{
149+
message: 'React.createClass is deprecated since React 15.5.0, use the npm module create-react-class instead'
150+
}, {
151+
message: 'React.PropTypes is deprecated since React 15.5.0, use the npm module prop-types instead'
152+
}]
153+
}, {
154+
code: 'import {printDOM} from \'react-addons-perf\';',
155+
parser: 'babel-eslint',
156+
errors: [{
157+
message: 'ReactPerf.printDOM is deprecated since React 15.0.0, use ReactPerf.printOperations instead'
158+
}]
159+
}, {
160+
code: [
161+
'import ReactPerf from \'react-addons-perf\';',
162+
'const {printDOM} = ReactPerf;'
163+
].join('\n'),
164+
parser: 'babel-eslint',
165+
errors: [{
166+
message: 'ReactPerf.printDOM is deprecated since React 15.0.0, use ReactPerf.printOperations instead'
167+
}]
114168
}]
115-
116169
});

0 commit comments

Comments
 (0)