Skip to content

Commit

Permalink
[Refactor] extract getKeyValue, isAssignmentLHS to ast util
Browse files Browse the repository at this point in the history
  • Loading branch information
ljharb committed May 19, 2019
1 parent 13be022 commit ef7f6eb
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 89 deletions.
18 changes: 3 additions & 15 deletions lib/rules/destructuring-assignment.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

const Components = require('../util/Components');
const docsUrl = require('../util/docsUrl');
const isAssignmentLHS = require('../util/ast').isAssignmentLHS;

const DEFAULT_OPTION = 'always';

Expand Down Expand Up @@ -38,19 +39,6 @@ module.exports = {
const configuration = context.options[0] || DEFAULT_OPTION;
const ignoreClassFields = context.options[1] && context.options[1].ignoreClassFields === true || false;

/**
* Checks if a prop is being assigned a value props.bar = 'bar'
* @param {ASTNode} node The AST node being checked.
* @returns {Boolean}
*/

function isAssignmentToProp(node) {
return (
node.parent &&
node.parent.type === 'AssignmentExpression' &&
node.parent.left === node
);
}
/**
* @param {ASTNode} node We expect either an ArrowFunctionExpression,
* FunctionDeclaration, or FunctionExpression
Expand All @@ -74,7 +62,7 @@ module.exports = {

function handleSFCUsage(node) {
// props.aProp || context.aProp
const isPropUsed = (node.object.name === 'props' || node.object.name === 'context') && !isAssignmentToProp(node);
const isPropUsed = (node.object.name === 'props' || node.object.name === 'context') && !isAssignmentLHS(node);
if (isPropUsed && configuration === 'always') {
context.report({
node,
Expand All @@ -99,7 +87,7 @@ module.exports = {
const isPropUsed = (
node.object.type === 'MemberExpression' && node.object.object.type === 'ThisExpression' &&
(node.object.property.name === 'props' || node.object.property.name === 'context' || node.object.property.name === 'state') &&
!isAssignmentToProp(node)
!isAssignmentLHS(node)
);

if (
Expand Down
9 changes: 3 additions & 6 deletions lib/rules/forbid-foreign-prop-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
'use strict';

const docsUrl = require('../util/docsUrl');
const ast = require('../util/ast');

module.exports = {
meta: {
Expand Down Expand Up @@ -37,10 +38,6 @@ module.exports = {
// Helpers
// --------------------------------------------------------------------------

function isLeftSideOfAssignment(node) {
return node.parent.type === 'AssignmentExpression' && node.parent.left === node;
}

function findParentAssignmentExpression(node) {
let parent = node.parent;

Expand Down Expand Up @@ -101,12 +98,12 @@ module.exports = {
!node.computed &&
node.property.type === 'Identifier' &&
node.property.name === 'propTypes' &&
!isLeftSideOfAssignment(node) &&
!ast.isAssignmentLHS(node) &&
!isAllowedAssignment(node)
) || (
(node.property.type === 'Literal' || node.property.type === 'JSXText') &&
node.property.value === 'propTypes' &&
!isLeftSideOfAssignment(node) &&
!ast.isAssignmentLHS(node) &&
!isAllowedAssignment(node)
)
) {
Expand Down
41 changes: 41 additions & 0 deletions lib/util/ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,54 @@ function isClass(node) {
return node.type === 'ClassDeclaration' || node.type === 'ClassExpression';
}

/**
* Removes quotes from around an identifier.
* @param {string} string the identifier to strip
*/
function stripQuotes(string) {
return string.replace(/^'|'$/g, '');
}

/**
* Retrieve the name of a key node
* @param {Context} context The AST node with the key.
* @param {ASTNode} node The AST node with the key.
* @return {string} the name of the key
*/
function getKeyValue(context, node) {
if (node.type === 'ObjectTypeProperty') {
const tokens = context.getFirstTokens(node, 2);
return (tokens[0].value === '+' || tokens[0].value === '-' ?
tokens[1].value :
stripQuotes(tokens[0].value)
);
}
const key = node.key || node.argument;
return key.type === 'Identifier' ? key.name : key.value;
}

/**
* Checks if a node is being assigned a value: props.bar = 'bar'
* @param {ASTNode} node The AST node being checked.
* @returns {Boolean}
*/
function isAssignmentLHS(node) {
return (
node.parent &&
node.parent.type === 'AssignmentExpression' &&
node.parent.left === node
);
}

module.exports = {
findReturnStatement,
getFirstNodeInLine,
getPropertyName,
getPropertyNameNode,
getComponentProperties,
getKeyValue,
isArrowFunction,
isAssignmentLHS,
isClass,
isFunction,
isFunctionLikeExpression,
Expand Down
29 changes: 2 additions & 27 deletions lib/util/propTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ const annotations = require('./annotations');
const propsUtil = require('./props');
const variableUtil = require('./variable');
const versionUtil = require('./version');
const propWrapperUtil = require('../util/propWrapper');
const propWrapperUtil = require('./propWrapper');
const getKeyValue = require('./ast').getKeyValue;

/**
* Checks if we are declaring a props as a generic type in a flow-annotated class.
Expand All @@ -25,32 +26,6 @@ function isSuperTypeParameterPropsDeclaration(node) {
return false;
}

/**
* Removes quotes from around an identifier.
* @param {string} string the identifier to strip
*/
function stripQuotes(string) {
return string.replace(/^'|'$/g, '');
}

/**
* Retrieve the name of a key node
* @param {Context} context The AST node with the key.
* @param {ASTNode} node The AST node with the key.
* @return {string} the name of the key
*/
function getKeyValue(context, node) {
if (node.type === 'ObjectTypeProperty') {
const tokens = context.getFirstTokens(node, 2);
return (tokens[0].value === '+' || tokens[0].value === '-' ?
tokens[1].value :
stripQuotes(tokens[0].value)
);
}
const key = node.key || node.argument;
return key.type === 'Identifier' ? key.name : key.value;
}

/**
* Iterates through a properties node, like a customized forEach.
* @param {Object} context Array of properties to iterate.
Expand Down
45 changes: 4 additions & 41 deletions lib/util/usedPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

const astUtil = require('./ast');
const versionUtil = require('./version');
const ast = require('./ast');

// ------------------------------------------------------------------------------
// Constants
Expand Down Expand Up @@ -176,31 +177,6 @@ module.exports = function usedPropTypesInstructions(context, components, utils)
return tokens.length && tokens[0].value === '...';
}

/**
* Removes quotes from around an identifier.
* @param {string} string the identifier to strip
*/
function stripQuotes(string) {
return string.replace(/^'|'$/g, '');
}

/**
* Retrieve the name of a key node
* @param {ASTNode} node The AST node with the key.
* @return {string} the name of the key
*/
function getKeyValue(node) {
if (node.type === 'ObjectTypeProperty') {
const tokens = context.getFirstTokens(node, 2);
return (tokens[0].value === '+' || tokens[0].value === '-' ?
tokens[1].value :
stripQuotes(tokens[0].value)
);
}
const key = node.key || node.argument;
return key.type === 'Identifier' ? key.name : key.value;
}

/**
* Retrieve the name of a property node
* @param {ASTNode} node The AST node with the property.
Expand Down Expand Up @@ -251,19 +227,6 @@ module.exports = function usedPropTypesInstructions(context, components, utils)
}
}

/**
* Checks if a prop is being assigned a value props.bar = 'bar'
* @param {ASTNode} node The AST node being checked.
* @returns {Boolean}
*/
function isAssignmentToProp(node) {
return (
node.parent &&
node.parent.type === 'AssignmentExpression' &&
node.parent.left === node
);
}

/**
* Checks if we are using a prop
* @param {ASTNode} node The AST node being checked.
Expand All @@ -276,7 +239,7 @@ module.exports = function usedPropTypesInstructions(context, components, utils)
(utils.getParentES6Component() || utils.getParentES5Component()) &&
(isThisPropsUsage || isPropArgumentInSetStateUpdater(node))
);
const isStatelessFunctionUsage = node.object.name === 'props' && !isAssignmentToProp(node);
const isStatelessFunctionUsage = node.object.name === 'props' && !ast.isAssignmentLHS(node);
return isClassUsage || isStatelessFunctionUsage || (isPropsUsage && inLifeCycleMethod());
}

Expand Down Expand Up @@ -309,7 +272,7 @@ module.exports = function usedPropTypesInstructions(context, components, utils)
node.parent.id &&
node.parent.id.properties &&
node.parent.id.properties.length &&
getKeyValue(node.parent.id.properties[0])
ast.getKeyValue(context, node.parent.id.properties[0])
) {
type = 'destructuring';
properties = node.parent.id.properties;
Expand Down Expand Up @@ -391,7 +354,7 @@ module.exports = function usedPropTypesInstructions(context, components, utils)
ignoreUnusedPropTypesValidation = true;
break;
}
const propName = getKeyValue(properties[k]);
const propName = ast.getKeyValue(context, properties[k]);

let currentNode = node;
allNames = [];
Expand Down

0 comments on commit ef7f6eb

Please sign in to comment.