Skip to content

Commit ec01d9a

Browse files
jseminckljharb
authored andcommitted
Add react import detection
1 parent ddba876 commit ec01d9a

File tree

2 files changed

+63
-23
lines changed

2 files changed

+63
-23
lines changed

lib/rules/no-typos.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ module.exports = {
3737

3838
create: Components.detect((context, components, utils) => {
3939
let propTypesPackageName;
40+
let reactPackageName;
4041

4142
function checkValidPropTypeQualfier(node) {
4243
if (node.name !== 'isRequired') {
@@ -58,7 +59,7 @@ module.exports = {
5859

5960
/* eslint-disable no-use-before-define */
6061
function checkValidProp(node) {
61-
if (!propTypesPackageName || !node) {
62+
if ((!propTypesPackageName && !reactPackageName) || !node) {
6263
return;
6364
}
6465

@@ -132,12 +133,14 @@ module.exports = {
132133
ImportDeclaration: function(node) {
133134
if (node.source && node.source.value === 'prop-types') { // import PropType from "prop-types"
134135
propTypesPackageName = node.specifiers[0].local.name;
135-
}
136-
},
137-
138-
CallExpression: function(node) {
139-
if (node.callee.name === 'require' && node.arguments[0].value === 'prop-types') {
140-
propTypesPackageName = node.parent.id.name;
136+
} else if (node.source && node.source.value === 'react') { // import { PropTypes } from "react"
137+
reactPackageName = node.specifiers[0].local.name;
138+
139+
propTypesPackageName = node.specifiers.length > 1 && (
140+
node.specifiers
141+
.filter(specifier => specifier.imported && specifier.imported.name === 'PropTypes')
142+
.map(specifier => specifier.local.name)
143+
);
141144
}
142145
},
143146

tests/lib/rules/no-typos.js

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ const parserOptions = {
1414
ecmaVersion: 6,
1515
ecmaFeatures: {
1616
jsx: true
17-
}
17+
},
18+
sourceType: 'module'
1819
};
1920

2021
// -----------------------------------------------------------------------------
@@ -337,6 +338,34 @@ ruleTester.run('no-typos', rule, {
337338
`,
338339
parser: 'babel-eslint',
339340
parserOptions: parserOptions
341+
}, {
342+
code: `
343+
import PropTypes from "prop-types";
344+
class Component extends React.Component {};
345+
Component.propTypes = {
346+
a: PropTypes.oneOf([
347+
'hello',
348+
'hi'
349+
])
350+
}
351+
`,
352+
parser: 'babel-eslint',
353+
parserOptions: parserOptions
354+
}, {
355+
code: `
356+
import PropTypes from "prop-types";
357+
class Component extends React.Component {};
358+
Component.childContextTypes = {
359+
a: PropTypes.string,
360+
b: PropTypes.string.isRequired,
361+
c: PropTypes.shape({
362+
d: PropTypes.string,
363+
e: PropTypes.number.isRequired,
364+
}).isRequired
365+
}
366+
`,
367+
parser: 'babel-eslint',
368+
parserOptions: parserOptions
340369
}, {
341370
code: `
342371
import PropTypes from "prop-types";
@@ -367,26 +396,22 @@ ruleTester.run('no-typos', rule, {
367396
parserOptions: parserOptions
368397
}, {
369398
code: `
370-
const PropTypes = require('prop-types');
371-
const MyPropTypes = require('lib/my-prop-types')
399+
import PropTypes from "prop-types"
400+
import * as MyPropTypes from 'lib/my-prop-types'
372401
class Component extends React.Component {};
373402
Component.propTypes = {
374-
a: PropTypes.string,
375-
b: MyPropTypes.MYSTRING,
376-
c: MyPropTypes.MYSTRING.isRequired,
403+
b: PropTypes.string,
404+
a: MyPropTypes.MYSTRING,
377405
}
378406
`,
379407
parser: 'babel-eslint',
380408
parserOptions: parserOptions
381409
}, {
382410
code: `
383-
const RealPropTypes = require('prop-types');
384-
const MyPropTypes = require('lib/my-prop-types')
411+
import CustomReact from "react"
385412
class Component extends React.Component {};
386413
Component.propTypes = {
387-
a: RealPropTypes.string,
388-
b: MyPropTypes.MYSTRING,
389-
c: MyPropTypes.MYSTRING.isRequired,
414+
b: CustomReact.PropTypes.string,
390415
}
391416
`,
392417
parser: 'babel-eslint',
@@ -878,7 +903,7 @@ ruleTester.run('no-typos', rule, {
878903
}]
879904
}, {
880905
code: `
881-
const PropTypes = require('prop-types');
906+
import PropTypes from 'prop-types';
882907
class Component extends React.Component {};
883908
Component.childContextTypes = {
884909
a: PropTypes.bools,
@@ -900,15 +925,15 @@ ruleTester.run('no-typos', rule, {
900925
}]
901926
}, {
902927
code: `
903-
const PropTypes = require('prop-types');
928+
import PropTypes from 'prop-types';
904929
class Component extends React.Component {};
905930
Component.propTypes = {
906931
a: PropTypes.string.isrequired,
907932
b: PropTypes.shape({
908933
c: PropTypes.number
909934
}).isrequired
910935
}
911-
`,
936+
`,
912937
parserOptions: parserOptions,
913938
errors: [{
914939
message: 'Typo in prop type chain qualifier: isrequired'
@@ -917,7 +942,7 @@ ruleTester.run('no-typos', rule, {
917942
}]
918943
}, {
919944
code: `
920-
const PropTypes = require('prop-types');
945+
import PropTypes from 'prop-types';
921946
class Component extends React.Component {};
922947
Component.propTypes = {
923948
a: PropTypes.string.isrequired,
@@ -935,7 +960,7 @@ ruleTester.run('no-typos', rule, {
935960
}]
936961
}, {
937962
code: `
938-
const RealPropTypes = require('prop-types');
963+
import RealPropTypes from 'prop-types';
939964
class Component extends React.Component {};
940965
Component.childContextTypes = {
941966
a: RealPropTypes.bools,
@@ -955,5 +980,17 @@ ruleTester.run('no-typos', rule, {
955980
}, {
956981
message: 'Typo in declared prop type: objectof'
957982
}]
983+
}, {
984+
code: `
985+
import RealReactDifferentName from "react"
986+
Component.propTypes = {
987+
b: RealReactDifferentName.PropTypes.STRING,
988+
}
989+
`,
990+
parser: 'babel-eslint',
991+
parserOptions: parserOptions,
992+
errors: [{
993+
message: 'Typo in prop type chain qualifier: STRING'
994+
}]
958995
}]
959996
});

0 commit comments

Comments
 (0)