Skip to content

Commit

Permalink
[Fix] no-unused-prop-types: improve component declared props detection
Browse files Browse the repository at this point in the history
Fixes #2752.
  • Loading branch information
jzabala authored and ljharb committed Aug 13, 2020
1 parent 5029bd1 commit 97ac0fa
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 9 deletions.
9 changes: 1 addition & 8 deletions lib/util/Components.js
Expand Up @@ -16,6 +16,7 @@ const propTypesUtil = require('./propTypes');
const jsxUtil = require('./jsx');
const usedPropTypesUtil = require('./usedPropTypes');
const defaultPropsUtil = require('./defaultProps');
const isFirstLetterCapitalized = require('./isFirstLetterCapitalized');

function getId(node) {
return node && node.range.join(':');
Expand Down Expand Up @@ -70,14 +71,6 @@ function isReturnsLogicalJSX(node, property, strict) {
: (returnsLogicalJSXLeft || returnsLogicalJSXRight);
}

function isFirstLetterCapitalized(word) {
if (!word) {
return false;
}
const firstLetter = word.charAt(0);
return firstLetter.toUpperCase() === firstLetter;
}

const Lists = new WeakMap();

/**
Expand Down
16 changes: 16 additions & 0 deletions lib/util/isFirstLetterCapitalized.js
@@ -0,0 +1,16 @@
'use strict';

/**
* Check if the first letter of a string is capitalized.
* @param {String} word String to check
* @returns {Boolean} True if first letter is capitalized.
*/
function isFirstLetterCapitalized(word) {
if (!word) {
return false;
}
const firstLetter = word.charAt(0);
return firstLetter.toUpperCase() === firstLetter;
}

module.exports = isFirstLetterCapitalized;
10 changes: 9 additions & 1 deletion lib/util/propTypes.js
Expand Up @@ -12,6 +12,7 @@ const variableUtil = require('./variable');
const versionUtil = require('./version');
const propWrapperUtil = require('./propWrapper');
const astUtil = require('./ast');
const isFirstLetterCapitalized = require('./isFirstLetterCapitalized');

/**
* Check if node is function type.
Expand Down Expand Up @@ -83,6 +84,13 @@ function isInsideClassBody(node) {
return false;
}

function startWithCapitalizedLetter(node) {
return (
node.parent.type === 'VariableDeclarator'
&& !isFirstLetterCapitalized(node.parent.id.name)
);
}

module.exports = function propTypesInstructions(context, components, utils) {
// Used to track the type annotations in scope.
// Necessary because babel's scopes do not track type annotations.
Expand Down Expand Up @@ -878,7 +886,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
}

// Should ignore function that not return JSXElement
if (!utils.isReturningJSXOrNull(node)) {
if (!utils.isReturningJSXOrNull(node) || startWithCapitalizedLetter(node)) {
return;
}

Expand Down
74 changes: 74 additions & 0 deletions tests/lib/rules/no-unused-prop-types.js
Expand Up @@ -3689,6 +3689,80 @@ ruleTester.run('no-unused-prop-types', rule, {
}
`,
parser: parsers.BABEL_ESLINT
},
{
code: `
const Home = () => {
const renderStaticList = ({
item,
}: {
item: IContent;
}) => (
<Section
icon={<FlashImage />}
title={item.title}
titleFontSize={theme.typography.FONT_SIZE_24}
>
<StaticFlatList
data={item.pointsOfSale}
renderItem={renderStaticItem}
keyExtractor={staticItemKeyExtractor}
/>
</Section>
);
return (
<SafeAreaViewWrapper>
<LightStatusBar />
<HomeFlatList
ListHeaderComponent={listHeaderComponent}
data={home?.static}
renderItem={renderStaticList}
keyExtractor={staticListKeyExtractor}
/>
</SafeAreaViewWrapper>
);
};
`,
parser: parsers['@TYPESCRIPT_ESLINT']
},
{
code: `
const Home = () => {
const renderStaticList = function({
item,
}: {
item: IContent;
}) {
return (
<Section
icon={<FlashImage />}
title={item.title}
titleFontSize={theme.typography.FONT_SIZE_24}
>
<StaticFlatList
data={item.pointsOfSale}
renderItem={renderStaticItem}
keyExtractor={staticItemKeyExtractor}
/>
</Section>
)
};
return (
<SafeAreaViewWrapper>
<LightStatusBar />
<HomeFlatList
ListHeaderComponent={listHeaderComponent}
data={home?.static}
renderItem={renderStaticList}
keyExtractor={staticListKeyExtractor}
/>
</SafeAreaViewWrapper>
);
};
`,
parser: parsers['@TYPESCRIPT_ESLINT']
}
])
),
Expand Down
23 changes: 23 additions & 0 deletions tests/util/isFirstLetterCapitalized.js
@@ -0,0 +1,23 @@
'use strict';

const assert = require('assert');

const isFirstLetterCapitalized = require('../../lib/util/isFirstLetterCapitalized');

describe('isFirstLetterCapitalized', () => {
it('should return false for invalid input', () => {
assert.equal(isFirstLetterCapitalized(), false);
assert.equal(isFirstLetterCapitalized(null), false);
assert.equal(isFirstLetterCapitalized(''), false);
});

it('should return false for uncapitalized string', () => {
assert.equal(isFirstLetterCapitalized('isCapitalized'), false);
assert.equal(isFirstLetterCapitalized('lowercase'), false);
});

it('should return true for capitalized string', () => {
assert.equal(isFirstLetterCapitalized('IsCapitalized'), true);
assert.equal(isFirstLetterCapitalized('UPPERCASE'), true);
});
});

0 comments on commit 97ac0fa

Please sign in to comment.