@fimbul/mimir
Advanced tools
Comparing version 0.16.0 to 0.17.0-dev.20181130
{ | ||
"name": "@fimbul/mimir", | ||
"version": "0.16.0", | ||
"version": "0.17.0-dev.20181130", | ||
"description": "Core rules of the Fimbullinter project", | ||
@@ -28,3 +28,3 @@ "main": "recommended.yaml", | ||
"dependencies": { | ||
"@fimbul/ymir": "^0.16.0", | ||
"@fimbul/ymir": "0.16.0", | ||
"chalk": "^2.3.2", | ||
@@ -31,0 +31,0 @@ "debug": "^4.0.0", |
@@ -34,4 +34,4 @@ "use strict"; | ||
checkAssignment(node) { | ||
if (returnTypeMatches(this.checker.getContextualType(node), isVoidType) && | ||
returnTypeMatches(this.checker.getTypeAtLocation(node), typeContainsThenable, this.checker, node)) { | ||
if (returnTypeMatches(this.checker.getContextualType(node), this.checker, isVoidType) && | ||
returnTypeMatches(this.checker.getTypeAtLocation(node), this.checker, typeContainsThenable, node)) { | ||
let errorNode = node; | ||
@@ -50,20 +50,25 @@ if (tsutils_1.isArrowFunction(node)) { | ||
checkClassProperty(node, clazz) { | ||
const { heritageClauses } = clazz; | ||
if (heritageClauses === undefined) | ||
if (clazz.heritageClauses === undefined) | ||
return; | ||
const checker = this.checker; | ||
if (node.kind === ts.SyntaxKind.MethodDeclaration) { | ||
const signature = checker.getSignatureFromDeclaration(node); | ||
if (signature === undefined || !typeContainsThenable(signature.getReturnType(), checker, clazz)) | ||
return; | ||
} | ||
else if (!returnTypeMatches(checker.getTypeAtLocation(node), checker, typeContainsThenable, clazz)) { | ||
return; | ||
} | ||
const staticName = tsutils_1.getPropertyName(node.name); | ||
if (staticName === undefined) | ||
return; | ||
let classType = this.checker.getTypeAtLocation(clazz); | ||
if (clazz.kind === ts.SyntaxKind.ClassExpression) | ||
classType = this.checker.getTypeOfSymbolAtLocation(classType.getProperty('prototype'), clazz); | ||
if (!returnTypeMatches(this.getTypeOfProperty(classType, staticName, clazz), typeContainsThenable, this.checker, clazz)) | ||
return; | ||
for (const heritageClause of heritageClauses) | ||
for (const base of heritageClause.types) | ||
if (returnTypeMatches(this.getTypeOfProperty(this.checker.getTypeAtLocation(base), staticName, base), isVoidType)) | ||
return this.addFailureAtNode(tsutils_1.getModifier(node, ts.SyntaxKind.AsyncKeyword) || node.name, `Overriding 'void'-returning method in base type with a 'Promise'-returning method is unsafe.`); | ||
const properties = staticName !== undefined | ||
? [{ name: staticName, symbolName: ts.escapeLeadingUnderscores(staticName) }] | ||
: utils_1.lateBoundPropertyNames(node.name.expression, checker).properties; | ||
for (const { name, symbolName } of properties) | ||
for (const heritageClause of clazz.heritageClauses) | ||
for (const base of heritageClause.types) | ||
if (returnTypeMatches(this.getTypeOfProperty(checker.getTypeAtLocation(base), symbolName, base), checker, isVoidType)) | ||
return this.addFailureAtNode(tsutils_1.getModifier(node, ts.SyntaxKind.AsyncKeyword) || node.name, `Overriding 'void'-returning method '${name}' of base type with a 'Promise'-returning method is unsafe.`); | ||
} | ||
getTypeOfProperty(classType, name, node) { | ||
const propertySymbol = utils_1.getPropertyOfType(classType, ts.escapeLeadingUnderscores(name)); | ||
const propertySymbol = utils_1.getPropertyOfType(classType, name); | ||
return propertySymbol && this.checker.getTypeOfSymbolAtLocation(propertySymbol, node); | ||
@@ -73,17 +78,20 @@ } | ||
const staticName = tsutils_1.getPropertyName(node.name); | ||
if (staticName === undefined) | ||
return; | ||
const contextualType = this.checker.getContextualType(parent); | ||
if (contextualType === undefined) | ||
return; | ||
const property = utils_1.getPropertyOfType(contextualType, ts.escapeLeadingUnderscores(staticName)); | ||
const propertyType = property | ||
? this.checker.getTypeOfSymbolAtLocation(property, parent) | ||
: tsutils_1.isValidNumericLiteral(staticName) && String(+staticName) === staticName && contextualType.getNumberIndexType() || | ||
contextualType.getStringIndexType(); | ||
if (!returnTypeMatches(propertyType && tsutils_1.removeOptionalityFromType(this.checker, propertyType), isVoidType)) | ||
return; | ||
const signature = this.checker.getSignatureFromDeclaration(node); | ||
if (signature !== undefined && typeContainsThenable(signature.getReturnType(), this.checker, node)) | ||
this.addFailureAtNode(tsutils_1.getModifier(node, ts.SyntaxKind.AsyncKeyword) || node.name, "A 'Promise'-returning function should not be assigned to a 'void'-returning function type."); | ||
const properties = staticName !== undefined | ||
? [{ name: staticName, symbolName: ts.escapeLeadingUnderscores(staticName) }] | ||
: utils_1.lateBoundPropertyNames(node.name.expression, this.checker).properties; | ||
for (const { name, symbolName } of properties) { | ||
const property = utils_1.getPropertyOfType(contextualType, symbolName); | ||
const propertyType = property | ||
? this.checker.getTypeOfSymbolAtLocation(property, parent) | ||
: tsutils_1.isValidNumericLiteral(name) && String(+name) === name && contextualType.getNumberIndexType() || | ||
contextualType.getStringIndexType(); | ||
if (!returnTypeMatches(propertyType, this.checker, isVoidType)) | ||
continue; | ||
const signature = this.checker.getSignatureFromDeclaration(node); | ||
if (signature !== undefined && typeContainsThenable(signature.getReturnType(), this.checker, node)) | ||
return this.addFailureAtNode(tsutils_1.getModifier(node, ts.SyntaxKind.AsyncKeyword) || node.name, `'Promise'-returning method '${name}' should not be assigned to a 'void'-returning function type.`); | ||
} | ||
} | ||
@@ -95,7 +103,7 @@ }; | ||
exports.Rule = Rule; | ||
function returnTypeMatches(type, predicate, ...args) { | ||
function returnTypeMatches(type, checker, predicate, param) { | ||
if (type === undefined) | ||
return false; | ||
const callSignatures = type.getCallSignatures(); | ||
return callSignatures.length !== 0 && callSignatures.every((signature) => predicate(signature.getReturnType(), ...args)); | ||
const callSignatures = tsutils_1.removeOptionalityFromType(checker, type).getCallSignatures(); | ||
return callSignatures.length !== 0 && callSignatures.every((signature) => predicate(signature.getReturnType(), checker, param)); | ||
} | ||
@@ -102,0 +110,0 @@ function typeContainsThenable(type, checker, node) { |
Sorry, the diff of this file is not supported yet
441600
4434
Updated@fimbul/ymir@0.16.0