Skip to content

Commit

Permalink
chore(utils): merge AccessorNode guards
Browse files Browse the repository at this point in the history
  • Loading branch information
G-Rath committed Aug 8, 2019
1 parent acebbf9 commit bbe5238
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 19 deletions.
4 changes: 2 additions & 2 deletions src/rules/prefer-to-have-length.ts
@@ -1,9 +1,9 @@
import { AST_NODE_TYPES } from '@typescript-eslint/experimental-utils';
import {
createRule,
isAccessorNode,
isExpectCall,
isParsedEqualityMatcherCall,
isSupportedAccessor,
parseExpectCall,
} from './utils';

Expand Down Expand Up @@ -42,7 +42,7 @@ export default createRule({
!isParsedEqualityMatcherCall(matcher) ||
!argument ||
argument.type !== AST_NODE_TYPES.MemberExpression ||
!isAccessorNode(argument.property, 'length') ||
!isSupportedAccessor(argument.property, 'length') ||
argument.property.type !== AST_NODE_TYPES.Identifier
) {
return;
Expand Down
50 changes: 33 additions & 17 deletions src/rules/utils.ts
Expand Up @@ -162,35 +162,51 @@ const isIdentifier = <V extends string>(
node.type === AST_NODE_TYPES.Identifier &&
(name === undefined || node.name === name);

/**
* Checks if the given `node` is a "supported accessor".
*
* This means that it's a node can be used to access properties,
* and who's "value" can be statically determined.
*
* `MemberExpression` nodes most commonly contain accessors,
* but it's possible for other nodes to contain them.
*
* If a `value` is provided & the `node` is an `AccessorNode`,
* the `value` will be compared to that of the `AccessorNode`.
*
* Note that `value` here refers to the normalised value.
* The property that holds the value is not always called `name`.
*
* @param {Node} node
* @param {V?} value
*
* @return {node is AccessorNode<V>}
*
* @template V
*/
export const isSupportedAccessor = <V extends string>(
node: TSESTree.Node,
value?: V,
): node is AccessorNode<V> =>
isIdentifier(node, value) || isStringNode(node, value);

/**
* Gets the value of the given `AccessorNode`,
* account for the different node types.
*
* @param {AccessorNode<S>} accessor
*
* @return {S}
*
* @template S
*/
export const getAccessorValue = <S extends string = string>(
accessor: AccessorNode<S>,
): S =>
accessor.type === AST_NODE_TYPES.Identifier
? accessor.name
: getStringValue(accessor);

/**
* Checks if the given `node` is an `AccessorExpression` with the specific `value`.
*
* @param {Node} node
* @param {V} accessor
*
* @return {node is SpecificAccessorExpression<V>}
*
* @template V
*/
export const isAccessorNode = <V extends string>(
node: TSESTree.Node,
accessor: V,
): node is AccessorNode<V> =>
isIdentifier(node, accessor) || isStringNode(node, accessor);

export interface ValidExpectCall<
Argument extends TSESTree.Expression = TSESTree.Expression
> extends ExpectCall {
Expand All @@ -215,7 +231,7 @@ type AccessorNode<Specifics extends string = string> =
type ExpectAccessor = AccessorNode<'expect'>;

export const isExpectAccessor = (node: TSESTree.Node): node is ExpectAccessor =>
isAccessorNode(node, 'expect');
isSupportedAccessor(node, 'expect');

export interface ExpectCall extends TSESTree.CallExpression {
callee: AccessorNode<'expect'>;
Expand Down

0 comments on commit bbe5238

Please sign in to comment.