Skip to content

Commit

Permalink
chore: second go at implementing with TS
Browse files Browse the repository at this point in the history
  • Loading branch information
SimenB committed May 12, 2019
1 parent f959c27 commit 03f6195
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 46 deletions.
7 changes: 7 additions & 0 deletions src/rules/__tests__/lowercase-name.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const ruleTester = new RuleTester({

ruleTester.run('lowercase-name', rule, {
valid: [
'randomFunction()',
'it()',
"it(' ', function () {})",
'it(" ", function () {})',
Expand All @@ -24,6 +25,8 @@ ruleTester.run('lowercase-name', rule, {
'it("123 foo", function () {})',
'it(42, function () {})',
'it(``)',
'it("")',
'it(42)',
'test()',
"test('foo', function () {})",
'test("foo", function () {})',
Expand All @@ -32,6 +35,8 @@ ruleTester.run('lowercase-name', rule, {
'test("123 foo", function () {})',
'test("42", function () {})',
'test(``)',
'test("")',
'test(42)',
'describe()',
"describe('foo', function () {})",
'describe("foo", function () {})',
Expand All @@ -41,6 +46,8 @@ ruleTester.run('lowercase-name', rule, {
'describe("42", function () {})',
'describe(function () {})',
'describe(``)',
'describe("")',
'describe(42)',
],

invalid: [
Expand Down
121 changes: 75 additions & 46 deletions src/rules/lowercase-name.ts
Original file line number Diff line number Diff line change
@@ -1,60 +1,85 @@
import { createRule } from './tsUtils';
import {
TSESTree,
AST_NODE_TYPES,
TSESTree,
} from '@typescript-eslint/experimental-utils';

const isIdentifier = (
callee: TSESTree.LeftHandSideExpression,
): callee is TSESTree.Identifier => !!callee;
interface JestFunctionIdentifier extends TSESTree.Identifier {
name: 'it' | 'test' | 'describe';
}

interface TestFunctionCallExpression extends TSESTree.CallExpression {
callee: JestFunctionIdentifier;
}

type ArgumentLiteral = TSESTree.Literal | TSESTree.TemplateLiteral;

interface FirstArgumentStringCallExpression extends TSESTree.CallExpression {
arguments: [ArgumentLiteral];
}

type CallExpressionWithCorrectCalleeAndArguments = TestFunctionCallExpression &
FirstArgumentStringCallExpression;

const isItTestOrDescribeFunction = (
callee: TSESTree.LeftHandSideExpression,
): callee is TSESTree.Identifier => {
if (!isIdentifier(callee)) {
node: TSESTree.CallExpression,
): node is TestFunctionCallExpression => {
const { callee } = node;

if (callee.type !== AST_NODE_TYPES.Identifier) {
return false;
}

return (
callee.name === 'it' || callee.name === 'test' || callee.name === 'describe'
);
const { name } = callee;

return name === 'it' || name === 'test' || name === 'describe';
};

const isItDescription = (
expression?: TSESTree.Expression,
): expression is TSESTree.Literal | TSESTree.TemplateLiteral =>
!!expression &&
(expression.type === AST_NODE_TYPES.Literal ||
expression.type === AST_NODE_TYPES.TemplateLiteral);
const hasStringAsFirstArgument = (
node: TSESTree.CallExpression,
): node is FirstArgumentStringCallExpression =>
node.arguments &&
node.arguments[0] &&
(node.arguments[0].type === AST_NODE_TYPES.Literal ||
node.arguments[0].type === AST_NODE_TYPES.TemplateLiteral);

const isJestFunctionWithLiteralArg = (
node: TSESTree.CallExpression,
): node is CallExpressionWithCorrectCalleeAndArguments =>
isItTestOrDescribeFunction(node) && hasStringAsFirstArgument(node);

const testDescription = (
firstArgument: TSESTree.Literal | TSESTree.TemplateLiteral,
) => {
if (firstArgument.type === AST_NODE_TYPES.Literal) {
return firstArgument.value as string;
const testDescription = (argument: ArgumentLiteral): string | null => {
if (argument.type === AST_NODE_TYPES.Literal) {
const { value } = argument;

if (typeof value === 'string') {
return value;
}
return null;
}

return firstArgument.quasis[0].value.raw;
return argument.quasis[0].value.raw;
};

const descriptionBeginsWithLowerCase = (
node: TSESTree.CallExpression,
): string | false => {
const {
arguments: [firstArgument],
callee,
} = node;
if (isItTestOrDescribeFunction(callee) && isItDescription(firstArgument)) {
const description = testDescription(firstArgument);
if (!description[0]) {
return false;
}
const jestFunctionName = (
node: CallExpressionWithCorrectCalleeAndArguments,
) => {
const description = testDescription(node.arguments[0]);
if (description === null) {
return null;
}

if (description[0] !== description[0].toLowerCase()) {
return callee.name;
}
const firstCharacter = description.charAt(0);

if (!firstCharacter) {
return null;
}

if (firstCharacter !== firstCharacter.toLowerCase()) {
return node.callee.name;
}
return false;

return null;
};

export default createRule({
Expand All @@ -81,7 +106,9 @@ export default createRule({
},
],
} as const,
defaultOptions: [{ ignore: [] } as { ignore: readonly string[] }],
defaultOptions: [
{ ignore: [] } as { ignore: readonly (JestFunctionIdentifier['name'])[] },
],
create(context, [{ ignore }]) {
const ignoredFunctionNames = ignore.reduce<
Record<string, true | undefined>
Expand All @@ -90,12 +117,16 @@ export default createRule({
return accumulator;
}, Object.create(null));

const isIgnoredFunctionName = (node: TSESTree.CallExpression) =>
ignoredFunctionNames[(node.callee as TSESTree.Identifier).name];
const isIgnoredFunctionName = (
node: CallExpressionWithCorrectCalleeAndArguments,
) => ignoredFunctionNames[node.callee.name];

return {
CallExpression(node) {
const erroneousMethod = descriptionBeginsWithLowerCase(node);
if (!isJestFunctionWithLiteralArg(node)) {
return;
}
const erroneousMethod = jestFunctionName(node);

if (erroneousMethod && !isIgnoredFunctionName(node)) {
context.report({
Expand All @@ -104,10 +135,8 @@ export default createRule({
node,
fix(fixer) {
const [firstArg] = node.arguments;
// guaranteed by descriptionBeginsWithLowerCase
const description = testDescription(firstArg as
| TSESTree.Literal
| TSESTree.TemplateLiteral);
// guaranteed by jestFunctionName
const description = testDescription(firstArg)!;

const rangeIgnoringQuotes: [number, number] = [
firstArg.range[0] + 1,
Expand Down

0 comments on commit 03f6195

Please sign in to comment.