eslint-plugin-typescript
Advanced tools
Comparing version 0.6.0 to 0.7.0
@@ -32,6 +32,12 @@ /** | ||
function getMemberName(member) { | ||
if (!member) return null; | ||
switch (member.type) { | ||
case "ExportDefaultDeclaration": | ||
case "ExportNamedDeclaration": { | ||
return getMemberName(member.declaration); | ||
// export statements (e.g. export { a };) | ||
// have no declarations, so ignore them | ||
return member.declaration | ||
? getMemberName(member.declaration) | ||
: null; | ||
} | ||
@@ -88,3 +94,3 @@ case "DeclareFunction": | ||
}); | ||
} else if (index === -1) { | ||
} else if (name && index === -1) { | ||
seen.push(name); | ||
@@ -91,0 +97,0 @@ } |
@@ -53,3 +53,3 @@ /** | ||
function isTypeScriptModuleDeclaration(node) { | ||
return node.name && node.name.type === "Literal"; | ||
return node.id && node.id.type === "Literal"; | ||
} | ||
@@ -64,7 +64,5 @@ | ||
function isDeclaration(node) { | ||
const hasDeclareModifier = | ||
(node.modifiers || []) | ||
.filter(m => m.type === "TSDeclareKeyword").length > 0; | ||
return hasDeclareModifier && !isTypeScriptModuleDeclaration(node); | ||
return ( | ||
node.declare === true && !isTypeScriptModuleDeclaration(node) | ||
); | ||
} | ||
@@ -71,0 +69,0 @@ |
@@ -63,3 +63,45 @@ /** | ||
/** | ||
* Checks if the given node has any decorators and marks them as used. | ||
* Checks the given node type annotation and marks it as used. | ||
* @param {ASTNode} node the relevant AST node. | ||
* @returns {void} | ||
* @private | ||
*/ | ||
function markTypeAnnotationAsUsed(node) { | ||
const annotation = node.typeAnnotation || node; | ||
switch (annotation.type) { | ||
case "TSTypeReference": { | ||
if (annotation.typeName.type === "TSArrayType") { | ||
markTypeAnnotationAsUsed( | ||
annotation.typeName.elementType | ||
); | ||
} else { | ||
markVariableAsUsed(context, annotation.typeName.name); | ||
if ( | ||
annotation.typeParameters && | ||
annotation.typeParameters.params | ||
) { | ||
annotation.typeParameters.params.forEach(param => { | ||
markTypeAnnotationAsUsed(param); | ||
}); | ||
} | ||
} | ||
break; | ||
} | ||
case "TSUnionType": | ||
case "TSIntersectionType": | ||
annotation.types.forEach(type => { | ||
markTypeAnnotationAsUsed(type); | ||
}); | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
/** | ||
* Checks the given decorator and marks it as used. | ||
* @param {ASTNode} node The relevant AST node. | ||
@@ -69,42 +111,35 @@ * @returns {void} | ||
*/ | ||
function markDecoratorsAsUsed(node) { | ||
if (!node.decorators || !node.decorators.length) { | ||
function markDecoratorAsUsed(node) { | ||
/** | ||
* Decorator | ||
*/ | ||
if (node.name) { | ||
markVariableAsUsed(context, node.name); | ||
return; | ||
} | ||
node.decorators.forEach(decorator => { | ||
/** | ||
* Decorator | ||
*/ | ||
if (decorator.name) { | ||
markVariableAsUsed(context, decorator.name); | ||
return; | ||
} | ||
if (decorator.expression && decorator.expression.name) { | ||
markVariableAsUsed(context, decorator.expression.name); | ||
return; | ||
} | ||
if (node.expression && node.expression.name) { | ||
markVariableAsUsed(context, node.expression.name); | ||
return; | ||
} | ||
/** | ||
* Decorator Factory | ||
*/ | ||
if (decorator.callee && decorator.callee.name) { | ||
markVariableAsUsed(context, decorator.callee.name); | ||
} | ||
/** | ||
* Decorator Factory | ||
*/ | ||
if (node.callee && node.callee.name) { | ||
markVariableAsUsed(context, node.callee.name); | ||
} | ||
if ( | ||
decorator.expression && | ||
decorator.expression.callee && | ||
decorator.expression.callee.name | ||
) { | ||
markVariableAsUsed( | ||
context, | ||
decorator.expression.callee.name | ||
); | ||
} | ||
}); | ||
if ( | ||
node.expression && | ||
node.expression.callee && | ||
node.expression.callee.name | ||
) { | ||
markVariableAsUsed(context, node.expression.callee.name); | ||
} | ||
} | ||
/** | ||
* Checks if the given node has any implemented interfaces and marks them as used. | ||
* Checks the given interface and marks it as used. | ||
* Generic arguments are also included in the check. | ||
* @param {ASTNode} node The relevant AST node. | ||
@@ -114,18 +149,81 @@ * @returns {void} | ||
*/ | ||
function markImplementedInterfacesAsUsed(node) { | ||
if (!node.implements || !node.implements.length) { | ||
function markImplementedInterfaceAsUsed(node) { | ||
if (!node || !node.id || !node.id.name) { | ||
return; | ||
} | ||
node.implements.forEach(implementedInterface => { | ||
if ( | ||
!implementedInterface || | ||
!implementedInterface.id || | ||
!implementedInterface.id.name | ||
) { | ||
return; | ||
} | ||
markVariableAsUsed(context, implementedInterface.id.name); | ||
}); | ||
markVariableAsUsed(context, node.id.name); | ||
if (!node.typeParameters || !node.typeParameters.params) { | ||
return; | ||
} | ||
node.typeParameters.params.forEach(markTypeAnnotationAsUsed); | ||
} | ||
/** | ||
* Checks the given class has a super class and marks it as used. | ||
* Generic arguments are also included in the check. | ||
* @param {ASTNode} node The relevant AST node. | ||
* @returns {void} | ||
* @private | ||
*/ | ||
function markSuperClassAsUsed(node) { | ||
if (!node.superClass) { | ||
return; | ||
} | ||
markVariableAsUsed(context, node.superClass.name); | ||
if (!node.superTypeParameters || !node.superTypeParameters.params) { | ||
return; | ||
} | ||
node.superTypeParameters.params.forEach(markTypeAnnotationAsUsed); | ||
} | ||
/** | ||
* Checks the given interface and marks it as used. | ||
* Generic arguments are also included in the check. | ||
* This is used when interfaces are extending other interfaces. | ||
* @param {ASTNode} node the relevant AST node. | ||
* @returns {void} | ||
* @private | ||
*/ | ||
function markExtendedInterfaceAsUsed(node) { | ||
if (!node || !node.id || !node.id.name) { | ||
return; | ||
} | ||
markVariableAsUsed(context, node.id.name); | ||
if (!node.typeParameters || !node.typeParameters.params) { | ||
return; | ||
} | ||
node.typeParameters.params.forEach(markTypeAnnotationAsUsed); | ||
} | ||
/** | ||
* Checks the given function return type and marks it as used. | ||
* @param {ASTNode} node the relevant AST node. | ||
* @returns {void} | ||
* @private | ||
*/ | ||
function markFunctionReturnTypeAsUsed(node) { | ||
if (node.returnType) { | ||
markTypeAnnotationAsUsed(node.returnType); | ||
} | ||
} | ||
/** | ||
* Checks the given class and marks super classes, interfaces and decoratores as used. | ||
* @param {ASTNode} node the relevant AST node. | ||
* @returns {void} | ||
* @private | ||
*/ | ||
function markClassOptionsAsUsed(node) { | ||
markSuperClassAsUsed(node); | ||
if (node.implements) { | ||
node.implements.forEach(markImplementedInterfaceAsUsed); | ||
} | ||
if (node.decorators) { | ||
node.decorators.forEach(markDecoratorAsUsed); | ||
} | ||
} | ||
//---------------------------------------------------------------------- | ||
@@ -135,39 +233,32 @@ // Public | ||
return { | ||
ClassProperty: markDecoratorsAsUsed, | ||
ClassDeclaration(node) { | ||
markDecoratorsAsUsed(node); | ||
markImplementedInterfacesAsUsed(node); | ||
Identifier(node) { | ||
if (node.typeAnnotation) { | ||
markTypeAnnotationAsUsed(node.typeAnnotation); | ||
} | ||
if (node.decorators) { | ||
node.decorators.forEach(markDecoratorAsUsed); | ||
} | ||
}, | ||
MethodDefinition(node) { | ||
/** | ||
* Decorators are only supported on class methods, so exit early | ||
* if the parent is not a ClassBody | ||
*/ | ||
const anc = context.getAncestors(); | ||
const tAnc = anc.length; | ||
if ( | ||
!tAnc || | ||
!anc[tAnc - 1] || | ||
anc[tAnc - 1].type !== "ClassBody" | ||
) { | ||
return; | ||
TypeAnnotation(node) { | ||
if (node.typeAnnotation) { | ||
markTypeAnnotationAsUsed(node.typeAnnotation); | ||
} | ||
}, | ||
/** | ||
* Mark any of the method's own decorators as used | ||
*/ | ||
markDecoratorsAsUsed(node); | ||
FunctionDeclaration: markFunctionReturnTypeAsUsed, | ||
FunctionExpression: markFunctionReturnTypeAsUsed, | ||
ArrowFunctionExpression: markFunctionReturnTypeAsUsed, | ||
/** | ||
* Mark any parameter decorators as used | ||
*/ | ||
if ( | ||
!node.value || | ||
!node.value.params || | ||
!node.value.params.length | ||
) { | ||
return; | ||
Decorator: markDecoratorAsUsed, | ||
TSInterfaceHeritage: markExtendedInterfaceAsUsed, | ||
ClassDeclaration: markClassOptionsAsUsed, | ||
ClassExpression: markClassOptionsAsUsed, | ||
MethodDefinition(node) { | ||
if (node.decorators) { | ||
node.decorators.forEach(markDecoratorAsUsed); | ||
} | ||
node.value.params.forEach(markDecoratorsAsUsed); | ||
} | ||
@@ -174,0 +265,0 @@ }; |
@@ -36,3 +36,3 @@ /** | ||
function isTypeScriptModuleDeclaration(node) { | ||
return node.name && node.name.type === "Literal"; | ||
return node.id && node.id.type === "Literal"; | ||
} | ||
@@ -39,0 +39,0 @@ |
{ | ||
"name": "eslint-plugin-typescript", | ||
"version": "0.6.0", | ||
"version": "0.7.0", | ||
"description": "TypeScript plugin for ESLint", | ||
@@ -34,7 +34,7 @@ "keywords": [ | ||
"typescript": "~2.4.2", | ||
"typescript-eslint-parser": "^6.0.1" | ||
"typescript-eslint-parser": "^7.0.0" | ||
}, | ||
"lint-staged": { | ||
"*.js": [ | ||
"prettier --write", | ||
"prettier --write --tab-width 4", | ||
"git add" | ||
@@ -41,0 +41,0 @@ ] |
@@ -24,2 +24,23 @@ /** | ||
code: ` | ||
function error(a: string); | ||
function error(b: number); | ||
function error(ab: string|number){ } | ||
export { error }; | ||
`, | ||
parserOptions: { sourceType: "module" }, | ||
parser: "typescript-eslint-parser" | ||
}, | ||
{ | ||
code: ` | ||
import { connect } from 'react-redux'; | ||
export interface ErrorMessageModel { message: string; } | ||
function mapStateToProps() { } | ||
function mapDispatchToProps() { } | ||
export default connect(mapStateToProps, mapDispatchToProps)(ErrorMessage); | ||
`, | ||
parserOptions: { sourceType: "module" }, | ||
parser: "typescript-eslint-parser" | ||
}, | ||
{ | ||
code: ` | ||
export const foo = "a", bar = "b"; | ||
@@ -26,0 +47,0 @@ export interface Foo {} |
@@ -178,2 +178,237 @@ /** | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"interface Base {}", | ||
"const a: Base = {}", | ||
"console.log(a);" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"const a: Nullable<string> = 'hello'", | ||
"console.log(a)" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { SomeOther } from 'other'", | ||
"const a: Nullable<SomeOther> = 'hello'", | ||
"console.log(a)" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"const a: Nullable | undefined = 'hello'", | ||
"console.log(a)" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"const a: Nullable & undefined = 'hello'", | ||
"console.log(a)" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { SomeOther } from 'other'", | ||
"const a: Nullable<SomeOther[]> = 'hello'", | ||
"console.log(a)" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { SomeOther } from 'other'", | ||
"const a: Nullable<Array<SomeOther>> = 'hello'", | ||
"console.log(a)" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"const a: Array<Nullable> = 'hello'", | ||
"console.log(a)" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"const a: Array<Nullable[]> = 'hello'", | ||
"console.log(a)" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"const a: Array<Array<Nullable>> = 'hello'", | ||
"console.log(a)" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { SomeOther } from 'other'", | ||
"const a: Array<Nullable<SomeOther>> = 'hello'", | ||
"console.log(a)" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { Component } from 'react'", | ||
"class Foo implements Component<Nullable>{}", | ||
"new Foo()" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { Component } from 'react'", | ||
"class Foo extends Component<Nullable, {}>{}", | ||
"new Foo()" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { SomeOther } from 'some'", | ||
"import { Component } from 'react'", | ||
"class Foo extends Component<Nullable<SomeOther>, {}>{}", | ||
"new Foo()" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { Another } from 'some'", | ||
"class A {", | ||
" do = (a: Nullable<Another>) => { console.log(a); }", | ||
"}", | ||
"new A();" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { Another } from 'some'", | ||
"class A {", | ||
" do(a: Nullable<Another>) { console.log(a); }", | ||
"}", | ||
"new A();" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { Another } from 'some'", | ||
"class A {", | ||
" do(): Nullable<Another> { return null; }", | ||
"}", | ||
"new A();" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { Another } from 'some'", | ||
"interface A {", | ||
" do(a: Nullable<Another>);", | ||
"}" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { Another } from 'some'", | ||
"interface A {", | ||
" other: Nullable<Another>;", | ||
"}" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"function foo(a: Nullable) { console.log(a); }", | ||
"foo()" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"function foo(): Nullable { return null; }", | ||
"foo()" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { SomeOther } from 'some'", | ||
"import { Another } from 'some'", | ||
"class A extends Nullable<SomeOther> {", | ||
" other: Nullable<Another>;", | ||
"}", | ||
"new A();" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { SomeOther } from 'some'", | ||
"import { Another } from 'some'", | ||
"class A extends Nullable<SomeOther> {", | ||
" do(a: Nullable<Another>){ console.log(a); }", | ||
"}", | ||
"new A();" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { SomeOther } from 'some'", | ||
"import { Another } from 'some'", | ||
"interface A extends Nullable<SomeOther> {", | ||
" other: Nullable<Another>;", | ||
"}" | ||
].join("\n"), | ||
parser | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { SomeOther } from 'some'", | ||
"import { Another } from 'some'", | ||
"interface A extends Nullable<SomeOther> {", | ||
" do(a: Nullable<Another>);", | ||
"}" | ||
].join("\n"), | ||
parser | ||
} | ||
@@ -197,4 +432,173 @@ ], | ||
] | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable';", | ||
"const a: string = 'hello';", | ||
"console.log(a);" | ||
].join("\n"), | ||
parser, | ||
errors: [ | ||
{ | ||
message: "'Nullable' is defined but never used.", | ||
line: 1, | ||
column: 10 | ||
} | ||
] | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable';", | ||
"import { SomeOther } from 'other';", | ||
"const a: Nullable<string> = 'hello';", | ||
"console.log(a);" | ||
].join("\n"), | ||
parser, | ||
errors: [ | ||
{ | ||
message: "'SomeOther' is defined but never used.", | ||
line: 2, | ||
column: 10 | ||
} | ||
] | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { Another } from 'some'", | ||
"class A {", | ||
" do = (a: Nullable) => { console.log(a); }", | ||
"}", | ||
"new A();" | ||
].join("\n"), | ||
parser, | ||
errors: [ | ||
{ | ||
message: "'Another' is defined but never used.", | ||
line: 2, | ||
column: 10 | ||
} | ||
] | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { Another } from 'some'", | ||
"class A {", | ||
" do(a: Nullable) { console.log(a); }", | ||
"}", | ||
"new A();" | ||
].join("\n"), | ||
parser, | ||
errors: [ | ||
{ | ||
message: "'Another' is defined but never used.", | ||
line: 2, | ||
column: 10 | ||
} | ||
] | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { Another } from 'some'", | ||
"class A {", | ||
" do(): Nullable { return null; }", | ||
"}", | ||
"new A();" | ||
].join("\n"), | ||
parser, | ||
errors: [ | ||
{ | ||
message: "'Another' is defined but never used.", | ||
line: 2, | ||
column: 10 | ||
} | ||
] | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { Another } from 'some'", | ||
"interface A {", | ||
" do(a: Nullable);", | ||
"}" | ||
].join("\n"), | ||
parser, | ||
errors: [ | ||
{ | ||
message: "'Another' is defined but never used.", | ||
line: 2, | ||
column: 10 | ||
} | ||
] | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { Another } from 'some'", | ||
"interface A {", | ||
" other: Nullable;", | ||
"}" | ||
].join("\n"), | ||
parser, | ||
errors: [ | ||
{ | ||
message: "'Another' is defined but never used.", | ||
line: 2, | ||
column: 10 | ||
} | ||
] | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"function foo(a: string) { console.log(a); }", | ||
"foo()" | ||
].join("\n"), | ||
parser, | ||
errors: [ | ||
{ | ||
message: "'Nullable' is defined but never used.", | ||
line: 1, | ||
column: 10 | ||
} | ||
] | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"function foo(): string | null { return null; }", | ||
"foo()" | ||
].join("\n"), | ||
parser, | ||
errors: [ | ||
{ | ||
message: "'Nullable' is defined but never used.", | ||
line: 1, | ||
column: 10 | ||
} | ||
] | ||
}, | ||
{ | ||
code: [ | ||
"import { Nullable } from 'nullable'", | ||
"import { SomeOther } from 'some'", | ||
"import { Another } from 'some'", | ||
"class A extends Nullable {", | ||
" other: Nullable<Another>;", | ||
"}", | ||
"new A();" | ||
].join("\n"), | ||
parser, | ||
errors: [ | ||
{ | ||
message: "'SomeOther' is defined but never used.", | ||
line: 2, | ||
column: 10 | ||
} | ||
] | ||
} | ||
] | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
595560
18669