Skip to content
This repository has been archived by the owner on Mar 25, 2021. It is now read-only.

[new-rule-option] Introduce new typedef rule option (variable-declaration-ignore-function) #4769

Merged
merged 5 commits into from Jul 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
59 changes: 46 additions & 13 deletions src/rules/typedefRule.ts
Expand Up @@ -29,6 +29,7 @@ interface Options {
"arrow-parameter"?: boolean;
"property-declaration"?: boolean;
"variable-declaration"?: boolean;
"variable-declaration-ignore-function"?: boolean;
"member-variable-declaration"?: boolean;
"object-destructuring"?: boolean;
"array-destructuring"?: boolean;
Expand All @@ -41,6 +42,7 @@ const OPTION_PARAMETER: Option = "parameter";
const OPTION_ARROW_PARAMETER: Option = "arrow-parameter";
const OPTION_PROPERTY_DECLARATION: Option = "property-declaration";
const OPTION_VARIABLE_DECLARATION: Option = "variable-declaration";
const OPTION_VARIABLE_DECLARATION_IGNORE_FUNCTION: Option = "variable-declaration-ignore-function";
const OPTION_MEMBER_VARIABLE_DECLARATION: Option = "member-variable-declaration";
const OPTION_OBJECT_DESTRUCTURING: Option = "object-destructuring";
const OPTION_ARRAY_DESTRUCTURING: Option = "array-destructuring";
Expand All @@ -67,6 +69,7 @@ export class Rule extends Lint.Rules.AbstractRule {
* \`"${OPTION_ARROW_PARAMETER}"\` checks type specifier of function parameters for arrow functions.
* \`"${OPTION_PROPERTY_DECLARATION}"\` checks return types of interface properties.
* \`"${OPTION_VARIABLE_DECLARATION}"\` checks non-binding variable declarations.
* \`"${OPTION_VARIABLE_DECLARATION_IGNORE_FUNCTION}"\` ignore variable declarations for non-arrow and arrow functions.
* \`"${OPTION_MEMBER_VARIABLE_DECLARATION}"\` checks member variable declarations.
* \`"${OPTION_OBJECT_DESTRUCTURING}"\` checks object destructuring declarations.
* \`"${OPTION_ARRAY_DESTRUCTURING}"\` checks array destructuring declarations.`,
Expand All @@ -81,13 +84,14 @@ export class Rule extends Lint.Rules.AbstractRule {
OPTION_ARROW_PARAMETER,
OPTION_PROPERTY_DECLARATION,
OPTION_VARIABLE_DECLARATION,
OPTION_VARIABLE_DECLARATION_IGNORE_FUNCTION,
OPTION_MEMBER_VARIABLE_DECLARATION,
OPTION_OBJECT_DESTRUCTURING,
OPTION_ARRAY_DESTRUCTURING,
],
},
minLength: 0,
maxLength: 7,
maxLength: 10,
},
optionExamples: [
[true, OPTION_CALL_SIGNATURE, OPTION_PARAMETER, OPTION_MEMBER_VARIABLE_DECLARATION],
Expand Down Expand Up @@ -153,7 +157,8 @@ class TypedefWalker extends Lint.AbstractWalker<Options> {
}
}

private checkParameter({ parent, name, type }: ts.ParameterDeclaration): void {
private checkParameter(node: ts.Node): void {
const { parent, name, type } = node as ts.ParameterDeclaration;
const isArrowFunction = parent.kind === ts.SyntaxKind.ArrowFunction;

const option = (() => {
Expand All @@ -177,11 +182,20 @@ class TypedefWalker extends Lint.AbstractWalker<Options> {
// If this is an arrow function, it doesn't need to have a typedef on the property declaration
// as the typedefs can be on the function's parameters instead
if (initializer === undefined || initializer.kind !== ts.SyntaxKind.ArrowFunction) {
if (
this.options[OPTION_VARIABLE_DECLARATION_IGNORE_FUNCTION] === true &&
initializer !== undefined &&
initializer.kind === ts.SyntaxKind.FunctionExpression
) {
return;
}
this.checkTypeAnnotation("member-variable-declaration", name, type, name);
}
}

private checkVariableDeclaration({ parent, name, type }: ts.VariableDeclaration): void {
private checkVariableDeclaration(node: ts.Node): void {
const { parent, name, type } = node as ts.VariableDeclaration;

// variable declarations should always have a grandparent, but check that to be on the safe side.
// catch statements will be the parent of the variable declaration
// for-in/for-of loops will be the gradparent of the variable declaration
Expand All @@ -193,20 +207,39 @@ class TypedefWalker extends Lint.AbstractWalker<Options> {
return;
}

const option = (() => {
switch (name.kind) {
case ts.SyntaxKind.ObjectBindingPattern:
return "object-destructuring";
case ts.SyntaxKind.ArrayBindingPattern:
return "array-destructuring";
default:
return "variable-declaration";
}
})();
let option: Option;

switch (name.kind) {
case ts.SyntaxKind.ObjectBindingPattern:
option = OPTION_OBJECT_DESTRUCTURING;
break;

case ts.SyntaxKind.ArrayBindingPattern:
option = OPTION_ARRAY_DESTRUCTURING;
break;

default:
option = OPTION_VARIABLE_DECLARATION;
}

if (this.shouldIgnoreVariableDeclaration(node)) {
return;
}

this.checkTypeAnnotation(option, name, type, name);
}

private shouldIgnoreVariableDeclaration(node: ts.Node): boolean {
const ignoreFunctions: boolean =
this.options[OPTION_VARIABLE_DECLARATION_IGNORE_FUNCTION] === true;

return (
ignoreFunctions &&
(utils.getChildOfKind(node, ts.SyntaxKind.ArrowFunction) !== undefined ||
utils.getChildOfKind(node, ts.SyntaxKind.FunctionExpression) !== undefined)
);
}

private checkTypeAnnotation(
option: Option,
location: ts.Node | ts.NodeArray<ts.Node>,
Expand Down
@@ -0,0 +1,23 @@
var foo = function(): void {};
michaelw85 marked this conversation as resolved.
Show resolved Hide resolved
let foo = function(): void {};
const foo = function(): void {};

var foo = (): void => {};
let foo = (): void => {};
const foo = (): void => {};

class Foo {
foo = (): void => {};
foo = function(): void {};
}

const foo: () => void = (): void => {};
const foo: () => void = function(): void {};

var noTypeDef = 'Should still fail';
~~~~~~~~~ [expected variable-declaration: 'noTypeDef' to have a typedef]

class NoTypeDef {
public noTypeDef = 'Should still fail';
~~~~~~~~~ [expected member-variable-declaration: 'noTypeDef' to have a typedef]
}
@@ -0,0 +1,10 @@
{
"rules": {
"typedef": [
true,
"variable-declaration",
"member-variable-declaration",
"variable-declaration-ignore-function"
]
}
}