Skip to content

Commit

Permalink
chore(prefer-to-be-undefined): convert to typescript (#395)
Browse files Browse the repository at this point in the history
  • Loading branch information
G-Rath authored Aug 15, 2019
1 parent c0b0626 commit 1b94f0e
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 144 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { RuleTester } from 'eslint';
import { TSESLint } from '@typescript-eslint/experimental-utils';
import rule from '../prefer-to-be-undefined';

const ruleTester = new RuleTester();
const ruleTester = new TSESLint.RuleTester();

ruleTester.run('prefer-to-be-undefined', rule, {
valid: [
'expect(undefined).toBeUndefined();',
'expect(true).not.toBeUndefined();',
'expect({}).toEqual({});',
'expect(null).toEqual(null);',
'expect(something).toBe()',
'expect(something).toBe(somethingElse)',
'expect(something).toEqual(somethingElse)',
'expect(something).not.toBe(somethingElse)',
Expand Down
54 changes: 0 additions & 54 deletions src/rules/prefer-to-be-undefined.js

This file was deleted.

75 changes: 75 additions & 0 deletions src/rules/prefer-to-be-undefined.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import {
AST_NODE_TYPES,
TSESTree,
} from '@typescript-eslint/experimental-utils';
import {
ParsedEqualityMatcherCall,
ParsedExpectMatcher,
createRule,
isExpectCall,
isParsedEqualityMatcherCall,
parseExpectCall,
} from './tsUtils';

interface UndefinedIdentifier extends TSESTree.Identifier {
name: 'undefined';
}

const isUndefinedIdentifier = (
node: TSESTree.Node,
): node is UndefinedIdentifier =>
node.type === AST_NODE_TYPES.Identifier && node.name === 'undefined';

/**
* Checks if the given `ParsedExpectMatcher` is a call to one of the equality matchers,
* with a `undefined` identifier as the sole argument.
*
* @param {ParsedExpectMatcher} matcher
*
* @return {matcher is ParsedEqualityMatcherCall<UndefinedIdentifier>}
*/
const isUndefinedEqualityMatcher = (
matcher: ParsedExpectMatcher,
): matcher is ParsedEqualityMatcherCall<UndefinedIdentifier> =>
isParsedEqualityMatcherCall(matcher) &&
isUndefinedIdentifier(matcher.arguments[0]);

export default createRule({
name: __filename,
meta: {
docs: {
category: 'Best Practices',
description: 'Suggest using `toBeUndefined()`',
recommended: false,
},
messages: {
useToBeUndefined: 'Use toBeUndefined() instead',
},
fixable: 'code',
type: 'suggestion',
schema: [],
},
defaultOptions: [],
create(context) {
return {
CallExpression(node) {
if (!isExpectCall(node)) {
return;
}

const { matcher } = parseExpectCall(node);

if (matcher && isUndefinedEqualityMatcher(matcher)) {
context.report({
fix: fixer => [
fixer.replaceText(matcher.node.property, 'toBeUndefined'),
fixer.remove(matcher.arguments[0]),
],
messageId: 'useToBeUndefined',
node: matcher.node.property,
});
}
},
};
},
});
88 changes: 0 additions & 88 deletions src/rules/util.js
Original file line number Diff line number Diff line change
@@ -1,90 +1,2 @@
import { basename } from 'path';
import { version } from '../../package.json';

const REPO_URL = 'https://github.com/jest-community/eslint-plugin-jest';

export const expectCase = node =>
node && node.callee && node.callee.name === 'expect';

export const expectCaseWithParent = node =>
expectCase(node) &&
node.parent &&
node.parent.type === 'MemberExpression' &&
node.parent.parent;

export const expectNotCase = node =>
expectCase(node) &&
node.parent.parent.type === 'MemberExpression' &&
methodName(node) === 'not';

export const expectResolvesCase = node =>
expectCase(node) &&
node.parent.parent.type === 'MemberExpression' &&
methodName(node) === 'resolves';

export const expectRejectsCase = node =>
expectCase(node) &&
node.parent.parent.type === 'MemberExpression' &&
methodName(node) === 'rejects';

export const expectToBeCase = (node, arg) =>
!(
expectNotCase(node) ||
expectResolvesCase(node) ||
expectRejectsCase(node)
) &&
expectCase(node) &&
methodName(node) === 'toBe' &&
argument(node) &&
(argument(node).name === 'undefined' && arg === undefined);

export const expectNotToBeCase = (node, arg) =>
expectNotCase(node) &&
methodName2(node) === 'toBe' &&
argument2(node) &&
(argument2(node).name === 'undefined' && arg === undefined);

export const expectToEqualCase = (node, arg) =>
!(
expectNotCase(node) ||
expectResolvesCase(node) ||
expectRejectsCase(node)
) &&
expectCase(node) &&
methodName(node) === 'toEqual' &&
argument(node) &&
(argument(node).name === 'undefined' && arg === undefined);

export const expectNotToEqualCase = (node, arg) =>
expectNotCase(node) &&
methodName2(node) === 'toEqual' &&
argument2(node) &&
(argument2(node).name === 'undefined' && arg === undefined);

export const method = node => node.parent.property;

export const method2 = node => node.parent.parent.property;

const methodName = node => method(node) && method(node).name;

const methodName2 = node => method2(node) && method2(node).name;

export const argument = node =>
node.parent.parent.arguments && node.parent.parent.arguments[0];

export const argument2 = node =>
node.parent.parent.parent.arguments && node.parent.parent.parent.arguments[0];

/**
* Generates the URL to documentation for the given rule name. It uses the
* package version to build the link to a tagged version of the
* documentation file.
*
* @param {string} filename - Name of the eslint rule
* @returns {string} URL to the documentation for the given rule
*/
export const getDocsUrl = filename => {
const ruleName = basename(filename, '.js');

return `${REPO_URL}/blob/v${version}/docs/rules/${ruleName}.md`;
};

0 comments on commit 1b94f0e

Please sign in to comment.