@fimbul/mimir
Advanced tools
Comparing version 0.21.0-dev.20190518 to 0.21.0-dev.20190529
{ | ||
"name": "@fimbul/mimir", | ||
"version": "0.21.0-dev.20190518", | ||
"version": "0.21.0-dev.20190529", | ||
"description": "Core rules of the Fimbullinter project", | ||
@@ -33,3 +33,3 @@ "main": "recommended.yaml", | ||
"tslib": "^1.8.1", | ||
"tsutils": "^3.8.0" | ||
"tsutils": "^3.11.0" | ||
}, | ||
@@ -36,0 +36,0 @@ "peerDependencies": { |
@@ -7,3 +7,2 @@ "use strict"; | ||
const tsutils_1 = require("tsutils"); | ||
const utils_1 = require("../utils"); | ||
let Rule = class Rule extends ymir_1.TypedRule { | ||
@@ -63,12 +62,12 @@ apply() { | ||
const properties = staticName !== undefined | ||
? [{ name: staticName, symbolName: ts.escapeLeadingUnderscores(staticName) }] | ||
: utils_1.lateBoundPropertyNames(node.name.expression, checker).properties; | ||
for (const { name, symbolName } of properties) | ||
? [{ displayName: staticName, symbolName: ts.escapeLeadingUnderscores(staticName) }] | ||
: tsutils_1.getLateBoundPropertyNames(node.name.expression, checker).names; | ||
for (const { displayName, 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.addFindingAtNode(tsutils_1.getModifier(node, ts.SyntaxKind.AsyncKeyword) || node.name, `Overriding 'void'-returning method '${name}' of base type with a 'Promise'-returning method is unsafe.`); | ||
return this.addFindingAtNode(tsutils_1.getModifier(node, ts.SyntaxKind.AsyncKeyword) || node.name, `Overriding 'void'-returning method '${displayName}' of base type with a 'Promise'-returning method is unsafe.`); | ||
} | ||
getTypeOfProperty(classType, name, node) { | ||
const propertySymbol = utils_1.getPropertyOfType(classType, name); | ||
const propertySymbol = tsutils_1.getPropertyOfType(classType, name); | ||
return propertySymbol && this.checker.getTypeOfSymbolAtLocation(propertySymbol, node); | ||
@@ -82,10 +81,9 @@ } | ||
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); | ||
? [{ displayName: staticName, symbolName: ts.escapeLeadingUnderscores(staticName) }] | ||
: tsutils_1.getLateBoundPropertyNames(node.name.expression, this.checker).names; | ||
for (const { displayName, symbolName } of properties) { | ||
const property = tsutils_1.getPropertyOfType(contextualType, symbolName); | ||
const propertyType = property | ||
? this.checker.getTypeOfSymbolAtLocation(property, parent) | ||
: tsutils_1.isValidNumericLiteral(name) && String(+name) === name && contextualType.getNumberIndexType() || | ||
contextualType.getStringIndexType(); | ||
: tsutils_1.isNumericPropertyName(displayName) && contextualType.getNumberIndexType() || contextualType.getStringIndexType(); | ||
if (!returnTypeMatches(propertyType, this.checker, isVoidType)) | ||
@@ -95,3 +93,3 @@ continue; | ||
if (signature !== undefined && typeContainsThenable(signature.getReturnType(), this.checker, node)) | ||
return this.addFindingAtNode(tsutils_1.getModifier(node, ts.SyntaxKind.AsyncKeyword) || node.name, `'Promise'-returning method '${name}' should not be assigned to a 'void'-returning function type.`); | ||
return this.addFindingAtNode(tsutils_1.getModifier(node, ts.SyntaxKind.AsyncKeyword) || node.name, `'Promise'-returning method '${displayName}' should not be assigned to a 'void'-returning function type.`); | ||
} | ||
@@ -98,0 +96,0 @@ } |
@@ -7,3 +7,2 @@ "use strict"; | ||
const tsutils_1 = require("tsutils"); | ||
const utils_1 = require("../utils"); | ||
const emptyPropertyInfo = { | ||
@@ -67,6 +66,6 @@ known: false, | ||
} | ||
const lateBound = utils_1.lateBoundPropertyNames(property.name.expression, this.checker); | ||
const lateBound = tsutils_1.getLateBoundPropertyNames(property.name.expression, this.checker); | ||
if (!lateBound.known) | ||
return emptyPropertyInfo; | ||
const names = lateBound.properties.map((p) => p.symbolName); | ||
const names = lateBound.names.map((p) => p.symbolName); | ||
return { | ||
@@ -73,0 +72,0 @@ names, |
@@ -15,7 +15,7 @@ "use strict"; | ||
checkElementAccess(node) { | ||
const { properties } = utils_1.lateBoundPropertyNames(node.argumentExpression, this.checker); | ||
if (properties.length === 0) | ||
const { names } = tsutils_1.getLateBoundPropertyNames(node.argumentExpression, this.checker); | ||
if (names.length === 0) | ||
return; | ||
const type = this.checker.getApparentType(this.checker.getTypeAtLocation(node.expression)); | ||
for (const { symbol, name } of utils_1.propertiesOfType(type, properties)) | ||
for (const { symbol, name } of utils_1.propertiesOfType(type, names)) | ||
this.checkSymbol(symbol, name, node, node.expression, type); | ||
@@ -22,0 +22,0 @@ } |
@@ -70,3 +70,3 @@ "use strict"; | ||
else { | ||
for (const { symbol, name } of utils_1.propertiesOfType(type, utils_1.lateBoundPropertyNames(element.propertyName.expression, this.checker).properties)) | ||
for (const { symbol, name } of utils_1.propertiesOfType(type, tsutils_1.getLateBoundPropertyNames(element.propertyName.expression, this.checker).names)) | ||
this.checkStability(symbol, element.propertyName, name, describeWithName); | ||
@@ -73,0 +73,0 @@ } |
@@ -79,3 +79,3 @@ "use strict"; | ||
if ((targetType.flags & ts.TypeFlags.Literal) !== 0 && !tsutils_1.isInConstContext(node) || // allow "foo" as "foo" to avoid widening | ||
tsutils_1.isObjectType(targetType) && (targetType.objectFlags & ts.ObjectFlags.Tuple || couldBeTupleType(targetType))) | ||
tsutils_1.isTupleType(tsutils_1.isTypeReference(targetType) ? targetType.target : targetType)) | ||
return; | ||
@@ -204,25 +204,2 @@ let sourceType = this.checker.getTypeAtLocation(node.expression); | ||
} | ||
/** | ||
* Sometimes tuple types don't have ObjectFlags.Tuple set, like when they're being matched against an inferred type. | ||
* So, in addition, check if there are integer properties 0..n and no other numeric keys | ||
*/ | ||
function couldBeTupleType(type) { | ||
const properties = type.getProperties(); | ||
if (properties.length === 0) | ||
return false; | ||
let i = 0; | ||
for (; i < properties.length; ++i) { | ||
const name = properties[i].escapedName; | ||
if (String(i) !== name) { | ||
if (i === 0) | ||
// if there are no integer properties, this is not a tuple | ||
return false; | ||
break; | ||
} | ||
} | ||
for (; i < properties.length; ++i) | ||
if (String(+properties[i].escapedName) === properties[i].escapedName) | ||
return false; | ||
return true; | ||
} | ||
//# sourceMappingURL=no-useless-assertion.js.map |
@@ -7,3 +7,2 @@ "use strict"; | ||
const tsutils_1 = require("tsutils"); | ||
const utils_1 = require("../utils"); | ||
let Rule = class Rule extends ymir_1.AbstractRule { | ||
@@ -74,3 +73,3 @@ apply() { | ||
const lateBoundNames = propNames(element, i, checker); | ||
if (!lateBoundNames.known || lateBoundNames.properties.some(maybeUndefined)) | ||
if (!lateBoundNames.known || lateBoundNames.names.some(maybeUndefined)) | ||
continue; | ||
@@ -83,3 +82,3 @@ // TODO we currently cannot autofix this case: it's possible to use a default value that's not assignable to the | ||
function maybeUndefined({ symbolName }) { | ||
const symbol = utils_1.getPropertyOfType(type || (type = checker.getApparentType(checker.getTypeAtLocation(node))), symbolName); | ||
const symbol = tsutils_1.getPropertyOfType(type || (type = checker.getApparentType(checker.getTypeAtLocation(node))), symbolName); | ||
return symbol === undefined || symbolMaybeUndefined(checker, symbol, node); | ||
@@ -133,8 +132,8 @@ } | ||
return staticName !== undefined | ||
? { known: true, properties: [{ name: staticName, symbolName: ts.escapeLeadingUnderscores(staticName) }] } | ||
: utils_1.lateBoundPropertyNames(property.propertyName.expression, checker); | ||
? { known: true, names: [{ displayName: staticName, symbolName: ts.escapeLeadingUnderscores(staticName) }] } | ||
: tsutils_1.getLateBoundPropertyNames(property.propertyName.expression, checker); | ||
} | ||
function getArrayPropertyName(_, i) { | ||
const name = String(i); | ||
return { known: true, properties: [{ name, symbolName: name }] }; | ||
return { known: true, names: [{ displayName: name, symbolName: name }] }; | ||
} | ||
@@ -141,0 +140,0 @@ function symbolMaybeUndefined(checker, symbol, node) { |
@@ -130,4 +130,4 @@ "use strict"; | ||
isConstantComparison(left, right, operator) { | ||
left = utils_1.unwrapParens(left); | ||
right = utils_1.unwrapParens(right); | ||
left = tsutils_1.unwrapParentheses(left); | ||
right = tsutils_1.unwrapParentheses(right); | ||
const equals = { | ||
@@ -145,3 +145,3 @@ negated: operator === ts.SyntaxKind.ExclamationEqualsEqualsToken || operator === ts.SyntaxKind.ExclamationEqualsToken, | ||
if (tsutils_1.isTypeOfExpression(left)) { | ||
left = utils_1.unwrapParens(left.expression); | ||
left = tsutils_1.unwrapParentheses(left.expression); | ||
if (right.kind === ts.SyntaxKind.NullKeyword || isUndefined(right)) | ||
@@ -193,3 +193,3 @@ return equals.negated; | ||
type = this.checker.getBaseConstraintOfType(type) || type; | ||
for (const t of tsutils_1.isIntersectionType(type) ? type.types : [type]) { | ||
for (const t of tsutils_1.intersectionTypeParts(type)) { | ||
if (tsutils_1.isLiteralType(t)) | ||
@@ -278,4 +278,4 @@ return typeof t.value === 'object' ? utils_1.formatPseudoBigInt(t.value) : String(t.value); | ||
else { | ||
const names = utils_1.lateBoundPropertyNames(node.argumentExpression, this.checker); | ||
if (names.known && names.properties.every(({ symbolName }) => utils_1.getPropertyOfType(objectType, symbolName) !== undefined)) | ||
const names = tsutils_1.getLateBoundPropertyNames(node.argumentExpression, this.checker); | ||
if (names.known && names.names.every(({ symbolName }) => tsutils_1.getPropertyOfType(objectType, symbolName) !== undefined)) | ||
return type; | ||
@@ -288,10 +288,10 @@ } | ||
return; | ||
const names = utils_1.lateBoundPropertyNames(name, this.checker); // TODO lateBoundPropertyNames should also be aware of index signatures | ||
const names = tsutils_1.getLateBoundPropertyNames(name, this.checker); // TODO lateBoundPropertyNames should also be aware of index signatures | ||
if (!names.known) | ||
return; | ||
const types = tsutils_1.unionTypeParts(this.checker.getApparentType(this.getTypeOfExpression(utils_1.unwrapParens(node)))); | ||
for (const { symbolName } of names.properties) { | ||
const types = tsutils_1.unionTypeParts(this.checker.getApparentType(this.getTypeOfExpression(tsutils_1.unwrapParentheses(node)))); | ||
for (const { symbolName } of names.names) { | ||
// we check every union type member separately because symbols lose optionality when accessed through union types | ||
for (const type of types) { | ||
const symbol = utils_1.getPropertyOfType(type, symbolName); | ||
const symbol = tsutils_1.getPropertyOfType(type, symbolName); | ||
if (symbol === undefined || symbol.flags & ts.SymbolFlags.Optional) | ||
@@ -298,0 +298,0 @@ return; // it might be present at runtime, so we don't return false |
@@ -72,5 +72,5 @@ "use strict"; | ||
return false; | ||
const expression = utils_1.unwrapParens(statement.expression); | ||
const expression = tsutils_1.unwrapParentheses(statement.expression); | ||
return tsutils_1.isIdentifier(expression) && expression.escapedText === name.escapedText; | ||
} | ||
//# sourceMappingURL=no-useless-try-catch.js.map |
@@ -156,49 +156,16 @@ "use strict"; | ||
return; | ||
const { properties } = lateBoundPropertyNames(argumentExpression, checker); | ||
if (properties.length === 0) | ||
const { names } = tsutils_1.getLateBoundPropertyNames(argumentExpression, checker); | ||
if (names.length === 0) | ||
return; | ||
yield* propertiesOfType(checker.getApparentType(checker.getTypeAtLocation(node.expression)), properties); | ||
yield* propertiesOfType(checker.getApparentType(checker.getTypeAtLocation(node.expression)), names); | ||
} | ||
exports.elementAccessSymbols = elementAccessSymbols; | ||
function* propertiesOfType(type, names) { | ||
for (const { symbolName, name } of names) { | ||
const symbol = getPropertyOfType(type, symbolName); | ||
for (const { symbolName, displayName } of names) { | ||
const symbol = tsutils_1.getPropertyOfType(type, symbolName); | ||
if (symbol !== undefined) | ||
yield { symbol, name }; | ||
yield { symbol, name: displayName }; | ||
} | ||
} | ||
exports.propertiesOfType = propertiesOfType; | ||
function getPropertyOfType(type, name) { | ||
return type.getProperties().find((s) => s.escapedName === name); | ||
} | ||
exports.getPropertyOfType = getPropertyOfType; | ||
function lateBoundPropertyNames(node, checker) { | ||
let known = true; | ||
const properties = []; | ||
if (tsutils_1.isPropertyAccessExpression(node) && | ||
tsutils_1.isIdentifier(node.expression) && | ||
node.expression.text === 'Symbol') { | ||
properties.push({ | ||
name: `Symbol.${node.name.text}`, | ||
symbolName: `__@${node.name.text}`, | ||
}); | ||
} | ||
else { | ||
const type = checker.getTypeAtLocation(node); | ||
for (const key of tsutils_1.unionTypeParts(checker.getBaseConstraintOfType(type) || type)) { | ||
if (tsutils_1.isLiteralType(key)) { | ||
const name = String(key.value); | ||
properties.push({ | ||
name, | ||
symbolName: ts.escapeLeadingUnderscores(name), | ||
}); | ||
} | ||
else { | ||
known = false; | ||
} | ||
} | ||
} | ||
return { known, properties }; | ||
} | ||
exports.lateBoundPropertyNames = lateBoundPropertyNames; | ||
function hasDirectivePrologue(node) { | ||
@@ -231,8 +198,2 @@ switch (node.kind) { | ||
exports.formatPseudoBigInt = formatPseudoBigInt; | ||
function unwrapParens(node) { | ||
while (node.kind === ts.SyntaxKind.ParenthesizedExpression) | ||
node = node.expression; | ||
return node; | ||
} | ||
exports.unwrapParens = unwrapParens; | ||
//# sourceMappingURL=utils.js.map |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
415786
4878
Updatedtsutils@^3.11.0