From 713fd774968c187da52e0b249155c6f3543bfb1d Mon Sep 17 00:00:00 2001 From: Rafael Santana Date: Sun, 17 Oct 2021 22:48:47 -0300 Subject: [PATCH] refactor(eslint-plugin): avoid looking for nodes that do not match the provided options (#3922) * refactor(eslint-plugin): avoid looking for nodes that do not match the provided options * refactor: normalize options indexes access Co-authored-by: Josh Goldberg --- .../eslint-plugin-tslint/src/rules/config.ts | 8 +- .../src/rules/class-literal-property-style.ts | 67 ++++--- .../rules/consistent-indexed-object-style.ts | 98 +++++----- .../src/rules/consistent-type-definitions.ts | 20 +- .../rules/explicit-module-boundary-types.ts | 1 - .../src/rules/init-declarations.ts | 9 +- .../src/rules/lines-between-class-members.ts | 4 +- .../src/rules/method-signature-style.ts | 182 +++++++++--------- .../src/rules/no-duplicate-imports.ts | 3 +- .../src/rules/no-unused-expressions.ts | 3 +- .../eslint-plugin/src/rules/no-unused-vars.ts | 2 +- .../src/rules/object-curly-spacing.ts | 7 +- .../rules/prefer-readonly-parameter-types.ts | 10 +- .../src/rules/promise-function-async.ts | 24 +-- .../src/rules/restrict-plus-operands.ts | 8 +- .../sort-type-union-intersection-members.ts | 16 +- .../src/rules/space-before-function-paren.ts | 8 +- packages/eslint-plugin/src/rules/typedef.ts | 154 ++++++++------- 18 files changed, 310 insertions(+), 314 deletions(-) diff --git a/packages/eslint-plugin-tslint/src/rules/config.ts b/packages/eslint-plugin-tslint/src/rules/config.ts index e865d8cbcdc..7bf51826541 100644 --- a/packages/eslint-plugin-tslint/src/rules/config.ts +++ b/packages/eslint-plugin-tslint/src/rules/config.ts @@ -104,11 +104,9 @@ export default createRule({ /** * The TSLint rules configuration passed in by the user */ - const { - rules: tslintRules, - rulesDirectory: tslintRulesDirectory, - lintFile, - } = context.options[0]; + const [ + { rules: tslintRules, rulesDirectory: tslintRulesDirectory, lintFile }, + ] = context.options; const program = parserServices.program; diff --git a/packages/eslint-plugin/src/rules/class-literal-property-style.ts b/packages/eslint-plugin/src/rules/class-literal-property-style.ts index b0816145015..b3f9fb401c2 100644 --- a/packages/eslint-plugin/src/rules/class-literal-property-style.ts +++ b/packages/eslint-plugin/src/rules/class-literal-property-style.ts @@ -55,9 +55,9 @@ export default util.createRule({ }, defaultOptions: ['fields'], create(context, [style]) { - if (style === 'fields') { - return { - MethodDefinition(node: TSESTree.MethodDefinition): void { + return { + ...(style === 'fields' && { + MethodDefinition(node): void { if ( node.kind !== 'get' || !node.value.body || @@ -95,38 +95,37 @@ export default util.createRule({ }, }); }, - }; - } + }), + ...(style === 'getters' && { + PropertyDefinition(node): void { + if (!node.readonly || node.declare) { + return; + } - return { - PropertyDefinition(node: TSESTree.PropertyDefinition): void { - if (!node.readonly || node.declare) { - return; - } - - const { value } = node; - - if (!value || !isSupportedLiteral(value)) { - return; - } - - context.report({ - node: node.key, - messageId: 'preferGetterStyle', - fix(fixer) { - const sourceCode = context.getSourceCode(); - const name = sourceCode.getText(node.key); - - let text = ''; - - text += printNodeModifiers(node, 'get'); - text += node.computed ? `[${name}]` : name; - text += `() { return ${sourceCode.getText(value)}; }`; - - return fixer.replaceText(node, text); - }, - }); - }, + const { value } = node; + + if (!value || !isSupportedLiteral(value)) { + return; + } + + context.report({ + node: node.key, + messageId: 'preferGetterStyle', + fix(fixer) { + const sourceCode = context.getSourceCode(); + const name = sourceCode.getText(node.key); + + let text = ''; + + text += printNodeModifiers(node, 'get'); + text += node.computed ? `[${name}]` : name; + text += `() { return ${sourceCode.getText(value)}; }`; + + return fixer.replaceText(node, text); + }, + }); + }, + }), }; }, }); diff --git a/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts b/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts index 29c5e534b4a..8c2081adebf 100644 --- a/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts +++ b/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts @@ -1,9 +1,9 @@ -import { createRule } from '../util'; import { AST_NODE_TYPES, - TSESTree, TSESLint, + TSESTree, } from '@typescript-eslint/experimental-utils'; +import { createRule } from '../util'; type MessageIds = 'preferRecord' | 'preferIndexSignature'; type Options = ['record' | 'index-signature']; @@ -29,38 +29,9 @@ export default createRule({ ], }, defaultOptions: ['record'], - create(context) { + create(context, [mode]) { const sourceCode = context.getSourceCode(); - if (context.options[0] === 'index-signature') { - return { - TSTypeReference(node): void { - const typeName = node.typeName; - if (typeName.type !== AST_NODE_TYPES.Identifier) { - return; - } - if (typeName.name !== 'Record') { - return; - } - - const params = node.typeParameters?.params; - if (params?.length !== 2) { - return; - } - - context.report({ - node, - messageId: 'preferIndexSignature', - fix(fixer) { - const key = sourceCode.getText(params[0]); - const type = sourceCode.getText(params[1]); - return fixer.replaceText(node, `{ [key: ${key}]: ${type} }`); - }, - }); - }, - }; - } - function checkMembers( members: TSESTree.TypeElement[], node: TSESTree.Node, @@ -113,27 +84,54 @@ export default createRule({ } return { - TSTypeLiteral(node): void { - checkMembers(node.members, node, '', ''); - }, + ...(mode === 'index-signature' && { + TSTypeReference(node): void { + const typeName = node.typeName; + if (typeName.type !== AST_NODE_TYPES.Identifier) { + return; + } + if (typeName.name !== 'Record') { + return; + } - TSInterfaceDeclaration(node): void { - let genericTypes = ''; + const params = node.typeParameters?.params; + if (params?.length !== 2) { + return; + } - if ((node.typeParameters?.params ?? []).length > 0) { - genericTypes = `<${node.typeParameters?.params - .map(p => p.name.name) - .join(', ')}>`; - } + context.report({ + node, + messageId: 'preferIndexSignature', + fix(fixer) { + const key = sourceCode.getText(params[0]); + const type = sourceCode.getText(params[1]); + return fixer.replaceText(node, `{ [key: ${key}]: ${type} }`); + }, + }); + }, + }), + ...(mode === 'record' && { + TSTypeLiteral(node): void { + checkMembers(node.members, node, '', ''); + }, + TSInterfaceDeclaration(node): void { + let genericTypes = ''; - checkMembers( - node.body.body, - node, - `type ${node.id.name}${genericTypes} = `, - ';', - !node.extends?.length, - ); - }, + if ((node.typeParameters?.params ?? []).length > 0) { + genericTypes = `<${node.typeParameters?.params + .map(p => p.name.name) + .join(', ')}>`; + } + + checkMembers( + node.body.body, + node, + `type ${node.id.name}${genericTypes} = `, + ';', + !node.extends?.length, + ); + }, + }), }; }, }); diff --git a/packages/eslint-plugin/src/rules/consistent-type-definitions.ts b/packages/eslint-plugin/src/rules/consistent-type-definitions.ts index bacccf9143f..efb7bdd8d5d 100644 --- a/packages/eslint-plugin/src/rules/consistent-type-definitions.ts +++ b/packages/eslint-plugin/src/rules/consistent-type-definitions.ts @@ -47,10 +47,10 @@ export default util.createRule({ } return { - "TSTypeAliasDeclaration[typeAnnotation.type='TSTypeLiteral']"( - node: TSESTree.TSTypeAliasDeclaration, - ): void { - if (option === 'interface') { + ...(option === 'interface' && { + "TSTypeAliasDeclaration[typeAnnotation.type='TSTypeLiteral']"( + node: TSESTree.TSTypeAliasDeclaration, + ): void { context.report({ node: node.id, messageId: 'interfaceOverType', @@ -81,10 +81,10 @@ export default util.createRule({ return fixes; }, }); - } - }, - TSInterfaceDeclaration(node): void { - if (option === 'type') { + }, + }), + ...(option === 'type' && { + TSInterfaceDeclaration(node): void { context.report({ node: node.id, messageId: 'typeOverInterface', @@ -137,8 +137,8 @@ export default util.createRule({ return fixes; }, }); - } - }, + }, + }), }; }, }); diff --git a/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts b/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts index 94f492bf06c..e189727463f 100644 --- a/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts +++ b/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts @@ -129,7 +129,6 @@ export default util.createRule({ TSExportAssignment(node): void { checkNode(node.expression); }, - 'ArrowFunctionExpression, FunctionDeclaration, FunctionExpression'( node: FunctionNode, ): void { diff --git a/packages/eslint-plugin/src/rules/init-declarations.ts b/packages/eslint-plugin/src/rules/init-declarations.ts index 3a97a2c8eda..6cd83e636f9 100644 --- a/packages/eslint-plugin/src/rules/init-declarations.ts +++ b/packages/eslint-plugin/src/rules/init-declarations.ts @@ -1,12 +1,12 @@ import { - TSESTree, AST_NODE_TYPES, + TSESTree, } from '@typescript-eslint/experimental-utils'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; import { - InferOptionsTypeFromRule, - InferMessageIdsTypeFromRule, createRule, + InferMessageIdsTypeFromRule, + InferOptionsTypeFromRule, } from '../util'; const baseRule = getESLintCoreRule('init-declarations'); @@ -29,9 +29,8 @@ export default createRule({ messages: baseRule.meta.messages, }, defaultOptions: ['always'], - create(context) { + create(context, [mode]) { const rules = baseRule.create(context); - const mode = context.options[0] || 'always'; return { 'VariableDeclaration:exit'(node: TSESTree.VariableDeclaration): void { diff --git a/packages/eslint-plugin/src/rules/lines-between-class-members.ts b/packages/eslint-plugin/src/rules/lines-between-class-members.ts index 95c2f811e8a..c78216b125f 100644 --- a/packages/eslint-plugin/src/rules/lines-between-class-members.ts +++ b/packages/eslint-plugin/src/rules/lines-between-class-members.ts @@ -43,10 +43,10 @@ export default util.createRule({ exceptAfterSingleLine: false, }, ], - create(context, options) { + create(context, [firstOption, secondOption]) { const rules = baseRule.create(context); const exceptAfterOverload = - options[1]?.exceptAfterOverload && options[0] === 'always'; + secondOption?.exceptAfterOverload && firstOption === 'always'; function isOverload(node: TSESTree.Node): boolean { return ( diff --git a/packages/eslint-plugin/src/rules/method-signature-style.ts b/packages/eslint-plugin/src/rules/method-signature-style.ts index 3e24263ab50..b05c4f9fbd1 100644 --- a/packages/eslint-plugin/src/rules/method-signature-style.ts +++ b/packages/eslint-plugin/src/rules/method-signature-style.ts @@ -116,29 +116,72 @@ export default util.createRule({ } return { - TSMethodSignature(methodNode): void { - if (mode === 'method') { - return; - } - - const parent = methodNode.parent; - const members = - parent?.type === AST_NODE_TYPES.TSInterfaceBody - ? parent.body - : parent?.type === AST_NODE_TYPES.TSTypeLiteral - ? parent.members - : []; - - const duplicatedKeyMethodNodes: TSESTree.TSMethodSignature[] = - members.filter( - (element): element is TSESTree.TSMethodSignature => - element.type === AST_NODE_TYPES.TSMethodSignature && - element !== methodNode && - getMethodKey(element) === getMethodKey(methodNode), - ); - const isParentModule = isNodeParentModuleDeclaration(methodNode); - - if (duplicatedKeyMethodNodes.length > 0) { + ...(mode === 'property' && { + TSMethodSignature(methodNode): void { + const parent = methodNode.parent; + const members = + parent?.type === AST_NODE_TYPES.TSInterfaceBody + ? parent.body + : parent?.type === AST_NODE_TYPES.TSTypeLiteral + ? parent.members + : []; + + const duplicatedKeyMethodNodes: TSESTree.TSMethodSignature[] = + members.filter( + (element): element is TSESTree.TSMethodSignature => + element.type === AST_NODE_TYPES.TSMethodSignature && + element !== methodNode && + getMethodKey(element) === getMethodKey(methodNode), + ); + const isParentModule = isNodeParentModuleDeclaration(methodNode); + + if (duplicatedKeyMethodNodes.length > 0) { + if (isParentModule) { + context.report({ + node: methodNode, + messageId: 'errorMethod', + }); + } else { + context.report({ + node: methodNode, + messageId: 'errorMethod', + *fix(fixer) { + const methodNodes = [ + methodNode, + ...duplicatedKeyMethodNodes, + ].sort((a, b) => (a.range[0] < b.range[0] ? -1 : 1)); + const typeString = methodNodes + .map(node => { + const params = getMethodParams(node); + const returnType = getMethodReturnType(node); + return `(${params} => ${returnType})`; + }) + .join(' & '); + const key = getMethodKey(methodNode); + const delimiter = getDelimiter(methodNode); + yield fixer.replaceText( + methodNode, + `${key}: ${typeString}${delimiter}`, + ); + for (const node of duplicatedKeyMethodNodes) { + const lastToken = sourceCode.getLastToken(node); + if (lastToken) { + const nextToken = sourceCode.getTokenAfter(lastToken); + if (nextToken) { + yield fixer.remove(node); + yield fixer.replaceTextRange( + [lastToken.range[1], nextToken.range[0]], + '', + ); + } + } + } + }, + }); + } + return; + } + if (isParentModule) { context.report({ node: methodNode, @@ -148,90 +191,43 @@ export default util.createRule({ context.report({ node: methodNode, messageId: 'errorMethod', - *fix(fixer) { - const methodNodes = [ - methodNode, - ...duplicatedKeyMethodNodes, - ].sort((a, b) => (a.range[0] < b.range[0] ? -1 : 1)); - const typeString = methodNodes - .map(node => { - const params = getMethodParams(node); - const returnType = getMethodReturnType(node); - return `(${params} => ${returnType})`; - }) - .join(' & '); + fix: fixer => { const key = getMethodKey(methodNode); + const params = getMethodParams(methodNode); + const returnType = getMethodReturnType(methodNode); const delimiter = getDelimiter(methodNode); - yield fixer.replaceText( + return fixer.replaceText( methodNode, - `${key}: ${typeString}${delimiter}`, + `${key}: ${params} => ${returnType}${delimiter}`, ); - for (const node of duplicatedKeyMethodNodes) { - const lastToken = sourceCode.getLastToken(node); - if (lastToken) { - const nextToken = sourceCode.getTokenAfter(lastToken); - if (nextToken) { - yield fixer.remove(node); - yield fixer.replaceTextRange( - [lastToken.range[1], nextToken.range[0]], - '', - ); - } - } - } }, }); } - return; - } + }, + }), + ...(mode === 'method' && { + TSPropertySignature(propertyNode): void { + const typeNode = propertyNode.typeAnnotation?.typeAnnotation; + if (typeNode?.type !== AST_NODE_TYPES.TSFunctionType) { + return; + } - if (isParentModule) { - context.report({ - node: methodNode, - messageId: 'errorMethod', - }); - } else { context.report({ - node: methodNode, - messageId: 'errorMethod', + node: propertyNode, + messageId: 'errorProperty', fix: fixer => { - const key = getMethodKey(methodNode); - const params = getMethodParams(methodNode); - const returnType = getMethodReturnType(methodNode); - const delimiter = getDelimiter(methodNode); + const key = getMethodKey(propertyNode); + const params = getMethodParams(typeNode); + const returnType = getMethodReturnType(typeNode); + const delimiter = getDelimiter(propertyNode); return fixer.replaceText( - methodNode, - `${key}: ${params} => ${returnType}${delimiter}`, + propertyNode, + `${key}${params}: ${returnType}${delimiter}`, ); }, }); - } - }, - TSPropertySignature(propertyNode): void { - const typeNode = propertyNode.typeAnnotation?.typeAnnotation; - if (typeNode?.type !== AST_NODE_TYPES.TSFunctionType) { - return; - } - - if (mode === 'property') { - return; - } - - context.report({ - node: propertyNode, - messageId: 'errorProperty', - fix: fixer => { - const key = getMethodKey(propertyNode); - const params = getMethodParams(typeNode); - const returnType = getMethodReturnType(typeNode); - const delimiter = getDelimiter(propertyNode); - return fixer.replaceText( - propertyNode, - `${key}${params}: ${returnType}${delimiter}`, - ); - }, - }); - }, + }, + }), }; }, }); diff --git a/packages/eslint-plugin/src/rules/no-duplicate-imports.ts b/packages/eslint-plugin/src/rules/no-duplicate-imports.ts index 5445b50cec4..b2ded1a2ea7 100644 --- a/packages/eslint-plugin/src/rules/no-duplicate-imports.ts +++ b/packages/eslint-plugin/src/rules/no-duplicate-imports.ts @@ -34,9 +34,8 @@ export default util.createRule({ includeExports: false, }, ], - create(context, [option]) { + create(context, [{ includeExports }]) { const rules = baseRule.create(context); - const includeExports = option.includeExports; const typeMemberImports = new Set(); const typeDefaultImports = new Set(); const typeExports = new Set(); diff --git a/packages/eslint-plugin/src/rules/no-unused-expressions.ts b/packages/eslint-plugin/src/rules/no-unused-expressions.ts index 4bef50b44a8..91d9f4e4a38 100644 --- a/packages/eslint-plugin/src/rules/no-unused-expressions.ts +++ b/packages/eslint-plugin/src/rules/no-unused-expressions.ts @@ -34,9 +34,8 @@ export default util.createRule({ allowTaggedTemplates: false, }, ], - create(context, options) { + create(context, [{ allowShortCircuit = false, allowTernary = false }]) { const rules = baseRule.create(context); - const { allowShortCircuit = false, allowTernary = false } = options[0]; function isValidExpression(node: TSESTree.Node): boolean { if (allowShortCircuit && node.type === AST_NODE_TYPES.LogicalExpression) { diff --git a/packages/eslint-plugin/src/rules/no-unused-vars.ts b/packages/eslint-plugin/src/rules/no-unused-vars.ts index bf9548ec888..7cce473557c 100644 --- a/packages/eslint-plugin/src/rules/no-unused-vars.ts +++ b/packages/eslint-plugin/src/rules/no-unused-vars.ts @@ -94,7 +94,7 @@ export default util.createRule({ caughtErrors: 'none', }; - const firstOption = context.options[0]; + const [firstOption] = context.options; if (firstOption) { if (typeof firstOption === 'string') { diff --git a/packages/eslint-plugin/src/rules/object-curly-spacing.ts b/packages/eslint-plugin/src/rules/object-curly-spacing.ts index 5e93dff61a0..fe74c8f7da4 100644 --- a/packages/eslint-plugin/src/rules/object-curly-spacing.ts +++ b/packages/eslint-plugin/src/rules/object-curly-spacing.ts @@ -30,7 +30,8 @@ export default createRule({ }, defaultOptions: ['never'], create(context) { - const spaced = context.options[0] === 'always'; + const [firstOption, secondOption] = context.options; + const spaced = firstOption === 'always'; const sourceCode = context.getSourceCode(); /** @@ -43,9 +44,7 @@ export default createRule({ function isOptionSet( option: 'arraysInObjects' | 'objectsInObjects', ): boolean { - return context.options[1] - ? context.options[1][option] === !spaced - : false; + return secondOption ? secondOption[option] === !spaced : false; } const options = { diff --git a/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts b/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts index 478a15b66b7..ed3e4ba284b 100644 --- a/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts +++ b/packages/eslint-plugin/src/rules/prefer-readonly-parameter-types.ts @@ -1,6 +1,6 @@ import { - TSESTree, AST_NODE_TYPES, + TSESTree, } from '@typescript-eslint/experimental-utils'; import * as util from '../util'; @@ -48,10 +48,10 @@ export default util.createRule({ ...util.readonlynessOptionsDefaults, }, ], - create(context, options) { - const [ - { checkParameterProperties, ignoreInferredTypes, treatMethodsAsReadonly }, - ] = options; + create( + context, + [{ checkParameterProperties, ignoreInferredTypes, treatMethodsAsReadonly }], + ) { const { esTreeNodeToTSNodeMap, program } = util.getParserServices(context); const checker = program.getTypeChecker(); diff --git a/packages/eslint-plugin/src/rules/promise-function-async.ts b/packages/eslint-plugin/src/rules/promise-function-async.ts index 6b3f29b8d97..083afcebe71 100644 --- a/packages/eslint-plugin/src/rules/promise-function-async.ts +++ b/packages/eslint-plugin/src/rules/promise-function-async.ts @@ -196,20 +196,20 @@ export default util.createRule({ } return { - 'ArrowFunctionExpression[async = false]'( - node: TSESTree.ArrowFunctionExpression, - ): void { - if (checkArrowFunctions) { + ...(checkArrowFunctions && { + 'ArrowFunctionExpression[async = false]'( + node: TSESTree.ArrowFunctionExpression, + ): void { validateNode(node); - } - }, - 'FunctionDeclaration[async = false]'( - node: TSESTree.FunctionDeclaration, - ): void { - if (checkFunctionDeclarations) { + }, + }), + ...(checkFunctionDeclarations && { + 'FunctionDeclaration[async = false]'( + node: TSESTree.FunctionDeclaration, + ): void { validateNode(node); - } - }, + }, + }), 'FunctionExpression[async = false]'( node: TSESTree.FunctionExpression, ): void { diff --git a/packages/eslint-plugin/src/rules/restrict-plus-operands.ts b/packages/eslint-plugin/src/rules/restrict-plus-operands.ts index 659509f81ef..51b4da9be46 100644 --- a/packages/eslint-plugin/src/rules/restrict-plus-operands.ts +++ b/packages/eslint-plugin/src/rules/restrict-plus-operands.ts @@ -132,11 +132,11 @@ export default util.createRule({ return { "BinaryExpression[operator='+']": checkPlusOperands, - "AssignmentExpression[operator='+=']"(node): void { - if (checkCompoundAssignments) { + ...(checkCompoundAssignments && { + "AssignmentExpression[operator='+=']"(node): void { checkPlusOperands(node); - } - }, + }, + }), }; }, }); diff --git a/packages/eslint-plugin/src/rules/sort-type-union-intersection-members.ts b/packages/eslint-plugin/src/rules/sort-type-union-intersection-members.ts index 3d14b55e9d7..942cae423df 100644 --- a/packages/eslint-plugin/src/rules/sort-type-union-intersection-members.ts +++ b/packages/eslint-plugin/src/rules/sort-type-union-intersection-members.ts @@ -241,16 +241,16 @@ export default util.createRule({ } return { - TSIntersectionType(node): void { - if (checkIntersections === true) { + ...(checkIntersections && { + TSIntersectionType(node): void { checkSorting(node); - } - }, - TSUnionType(node): void { - if (checkUnions === true) { + }, + }), + ...(checkUnions && { + TSUnionType(node): void { checkSorting(node); - } - }, + }, + }), }; }, }); diff --git a/packages/eslint-plugin/src/rules/space-before-function-paren.ts b/packages/eslint-plugin/src/rules/space-before-function-paren.ts index b13af67163c..8f848f92742 100644 --- a/packages/eslint-plugin/src/rules/space-before-function-paren.ts +++ b/packages/eslint-plugin/src/rules/space-before-function-paren.ts @@ -58,12 +58,10 @@ export default util.createRule({ }, defaultOptions: ['always'], - create(context) { + create(context, [firstOption]) { const sourceCode = context.getSourceCode(); - const baseConfig = - typeof context.options[0] === 'string' ? context.options[0] : 'always'; - const overrideConfig = - typeof context.options[0] === 'object' ? context.options[0] : {}; + const baseConfig = typeof firstOption === 'string' ? firstOption : 'always'; + const overrideConfig = typeof firstOption === 'object' ? firstOption : {}; /** * Determines whether a function has a name. diff --git a/packages/eslint-plugin/src/rules/typedef.ts b/packages/eslint-plugin/src/rules/typedef.ts index eaca1be209e..602df98e060 100644 --- a/packages/eslint-plugin/src/rules/typedef.ts +++ b/packages/eslint-plugin/src/rules/typedef.ts @@ -1,6 +1,6 @@ import { - TSESTree, AST_NODE_TYPES, + TSESTree, } from '@typescript-eslint/experimental-utils'; import * as util from '../util'; @@ -59,7 +59,21 @@ export default util.createRule<[Options], MessageIds>({ [OptionKeys.VariableDeclarationIgnoreFunction]: false, }, ], - create(context, [options]) { + create( + context, + [ + { + arrayDestructuring, + arrowParameter, + memberVariableDeclaration, + objectDestructuring, + parameter, + propertyDeclaration, + variableDeclaration, + variableDeclarationIgnoreFunction, + }, + ], + ) { function report(location: TSESTree.Node, name?: string): void { context.report({ node: location, @@ -132,86 +146,84 @@ export default util.createRule<[Options], MessageIds>({ function isVariableDeclarationIgnoreFunction(node: TSESTree.Node): boolean { return ( - !!options[OptionKeys.VariableDeclarationIgnoreFunction] && - (node.type === AST_NODE_TYPES.FunctionExpression || - node.type === AST_NODE_TYPES.ArrowFunctionExpression) + variableDeclarationIgnoreFunction === true && + (node.type === AST_NODE_TYPES.ArrowFunctionExpression || + node.type === AST_NODE_TYPES.FunctionExpression) ); } return { - ArrayPattern(node): void { - if ( - node.parent?.type === AST_NODE_TYPES.RestElement && - node.parent.typeAnnotation - ) { - return; - } - if ( - options[OptionKeys.ArrayDestructuring] && - !node.typeAnnotation && - !isForOfStatementContext(node) - ) { - report(node); - } - }, - ArrowFunctionExpression(node): void { - if (options[OptionKeys.ArrowParameter]) { - checkParameters(node.params); - } - }, - PropertyDefinition(node): void { - if (node.value && isVariableDeclarationIgnoreFunction(node.value)) { - return; - } + ...(arrayDestructuring && { + ArrayPattern(node): void { + if ( + node.parent?.type === AST_NODE_TYPES.RestElement && + node.parent.typeAnnotation + ) { + return; + } - if ( - options[OptionKeys.MemberVariableDeclaration] && - !node.typeAnnotation - ) { - report( - node, - node.key.type === AST_NODE_TYPES.Identifier - ? node.key.name - : undefined, - ); - } - }, - 'FunctionDeclaration, FunctionExpression'( - node: TSESTree.FunctionDeclaration | TSESTree.FunctionExpression, - ): void { - if (options[OptionKeys.Parameter]) { + if (!node.typeAnnotation && !isForOfStatementContext(node)) { + report(node); + } + }, + }), + ...(arrowParameter && { + ArrowFunctionExpression(node): void { checkParameters(node.params); - } - }, - ObjectPattern(node): void { - if ( - options[OptionKeys.ObjectDestructuring] && - !node.typeAnnotation && - !isForOfStatementContext(node) - ) { - report(node); - } - }, - 'TSIndexSignature, TSPropertySignature'( - node: TSESTree.TSIndexSignature | TSESTree.TSPropertySignature, - ): void { - if (options[OptionKeys.PropertyDeclaration] && !node.typeAnnotation) { - report( - node, - node.type === AST_NODE_TYPES.TSPropertySignature - ? getNodeName(node.key) - : undefined, - ); - } - }, + }, + }), + ...(memberVariableDeclaration && { + PropertyDefinition(node): void { + if ( + !node.value || + !isVariableDeclarationIgnoreFunction(node.value) || + !node.typeAnnotation + ) { + report( + node, + node.key.type === AST_NODE_TYPES.Identifier + ? node.key.name + : undefined, + ); + } + }, + }), + ...(parameter && { + 'FunctionDeclaration, FunctionExpression'( + node: TSESTree.FunctionDeclaration | TSESTree.FunctionExpression, + ): void { + checkParameters(node.params); + }, + }), + ...(objectDestructuring && { + ObjectPattern(node): void { + if (!node.typeAnnotation && !isForOfStatementContext(node)) { + report(node); + } + }, + }), + ...(propertyDeclaration && { + 'TSIndexSignature, TSPropertySignature'( + node: TSESTree.TSIndexSignature | TSESTree.TSPropertySignature, + ): void { + if (!node.typeAnnotation) { + report( + node, + node.type === AST_NODE_TYPES.TSPropertySignature + ? getNodeName(node.key) + : undefined, + ); + } + }, + }), VariableDeclarator(node): void { if ( - !options[OptionKeys.VariableDeclaration] || + !variableDeclaration || node.id.typeAnnotation || (node.id.type === AST_NODE_TYPES.ArrayPattern && - !options[OptionKeys.ArrayDestructuring]) || + !arrayDestructuring) || (node.id.type === AST_NODE_TYPES.ObjectPattern && - !options[OptionKeys.ObjectDestructuring]) || + !objectDestructuring) || (node.init && isVariableDeclarationIgnoreFunction(node.init)) ) { return;