@fimbul/mimir
Advanced tools
Comparing version
{ | ||
"name": "@fimbul/mimir", | ||
"version": "0.17.0-dev.20181220", | ||
"version": "0.17.0-dev.20181221", | ||
"description": "Core rules of the Fimbullinter project", | ||
@@ -28,3 +28,3 @@ "main": "recommended.yaml", | ||
"dependencies": { | ||
"@fimbul/ymir": "0.17.0-dev.20181218", | ||
"@fimbul/ymir": "0.17.0-dev.20181221", | ||
"chalk": "^2.3.2", | ||
@@ -31,0 +31,0 @@ "debug": "^4.0.0", |
@@ -10,5 +10,5 @@ "use strict"; | ||
format(fileName, summary) { | ||
if (summary.failures.length === 0) | ||
if (summary.findings.length === 0) | ||
return; | ||
return summary.failures.map((f) => JSON.stringify(Object.assign({}, f, { fileName }))).join(); | ||
return summary.findings.map((f) => JSON.stringify(Object.assign({}, f, { fileName }))).join(); | ||
} | ||
@@ -15,0 +15,0 @@ flush() { |
@@ -6,2 +6,12 @@ "use strict"; | ||
const path = require("path"); | ||
const COLORS = { | ||
error: chalk_1.default.red, | ||
warning: chalk_1.default.yellow, | ||
suggestion: chalk_1.default.cyan, | ||
}; | ||
const SYMBOLS = { | ||
error: '✖', | ||
warning: '⚠', | ||
suggestion: '💡', | ||
}; | ||
class Formatter extends ymir_1.AbstractFormatter { | ||
@@ -19,13 +29,13 @@ constructor() { | ||
this.fixed += summary.fixes; | ||
if (summary.failures.length === 0) | ||
if (summary.findings.length === 0) | ||
return; | ||
const mapped = []; | ||
for (const failure of summary.failures.slice().sort(ymir_1.Failure.compare)) { | ||
if (failure.fix !== undefined) | ||
for (const finding of summary.findings.slice().sort(ymir_1.Finding.compare)) { | ||
if (finding.fix !== undefined) | ||
++this.fixable; | ||
if (failure.severity.length > this.maxSeverityWidth) | ||
this.maxSeverityWidth = failure.severity.length; | ||
if (failure.ruleName.length > this.maxNameWidth) | ||
this.maxNameWidth = failure.ruleName.length; | ||
let { character, line } = failure.start; | ||
if (finding.severity.length > this.maxSeverityWidth) | ||
this.maxSeverityWidth = finding.severity.length; | ||
if (finding.ruleName.length > this.maxNameWidth) | ||
this.maxNameWidth = finding.ruleName.length; | ||
let { character, line } = finding.start; | ||
if (line !== 0 || character === 0 || !summary.content.startsWith('\uFEFF')) | ||
@@ -38,5 +48,5 @@ character += 1; | ||
position, | ||
severity: failure.severity, | ||
ruleName: failure.ruleName, | ||
message: failure.message, | ||
severity: finding.severity, | ||
ruleName: finding.ruleName, | ||
message: finding.message, | ||
}); | ||
@@ -48,31 +58,28 @@ } | ||
flush() { | ||
let errors = 0; | ||
let warnings = 0; | ||
const counts = { | ||
error: 0, | ||
warning: 0, | ||
suggestion: 0, | ||
}; | ||
const lines = []; | ||
for (const [fileName, failures] of this.files) { | ||
lines.push('', `${chalk_1.default.underline(path.normalize(fileName))}${chalk_1.default.hidden(':' + failures[0].position)}`); | ||
for (const failure of failures) { | ||
let positionColor; | ||
if (failure.severity === 'error') { | ||
positionColor = chalk_1.default.red; | ||
++errors; | ||
} | ||
else { | ||
positionColor = chalk_1.default.yellow; | ||
++warnings; | ||
} | ||
lines.push(positionColor(pad(failure.severity.toUpperCase(), this.maxSeverityWidth) + ' ' + pad(failure.position, this.maxPositionWidth)) + ` ${chalk_1.default.grey(pad(failure.ruleName, this.maxNameWidth))} ${chalk_1.default.blueBright(failure.message)}`); | ||
for (const [fileName, findings] of this.files) { | ||
lines.push('', `${chalk_1.default.underline(path.normalize(fileName))}${chalk_1.default.hidden(':' + findings[0].position)}`); | ||
for (const finding of findings) { | ||
const positionColor = COLORS[finding.severity]; | ||
++counts[finding.severity]; | ||
lines.push(positionColor(pad(finding.severity.toUpperCase(), this.maxSeverityWidth) + ' ' + pad(finding.position, this.maxPositionWidth)) + ` ${chalk_1.default.grey(pad(finding.ruleName, this.maxNameWidth))} ${chalk_1.default.blueBright(finding.message)}`); | ||
} | ||
} | ||
if (this.fixed !== 0) | ||
lines.push('', chalk_1.default.green(`Automatically fixed ${addCount(this.fixed, 'failure')}.`)); | ||
lines.push('', chalk_1.default.green(`Automatically fixed ${addCount(this.fixed, 'finding')}.`)); | ||
if (this.files.size !== 0) { | ||
const summaryLine = []; | ||
if (errors !== 0) | ||
summaryLine.push(chalk_1.default.red.bold(`✖ ${addCount(errors, 'error')}`)); | ||
if (warnings !== 0) | ||
summaryLine.push(chalk_1.default.yellow.bold(`⚠ ${addCount(warnings, 'warning')}`)); | ||
for (const severity of Object.keys(counts)) { | ||
const count = counts[severity]; | ||
if (count !== 0) | ||
summaryLine.push(COLORS[severity].bold(`${SYMBOLS[severity]} ${addCount(count, severity)}`)); | ||
} | ||
lines.push('', summaryLine.join(' ')); | ||
if (this.fixable !== 0) | ||
lines.push(chalk_1.default.grey(addCount(this.fixable, 'failure') + ' ' + | ||
lines.push(chalk_1.default.grey(addCount(this.fixable, 'finding') + ' ' + | ||
(this.fixable === 1 ? 'is' : 'are') + " potentially fixable with the '--fix' option.")); | ||
@@ -79,0 +86,0 @@ } |
@@ -45,3 +45,3 @@ "use strict"; | ||
} | ||
this.addFailureAtNode(errorNode, "A 'Promise'-returning function should not be assigned to a 'void'-returning function type."); | ||
this.addFindingAtNode(errorNode, "A 'Promise'-returning function should not be assigned to a 'void'-returning function type."); | ||
} | ||
@@ -69,3 +69,3 @@ } | ||
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.`); | ||
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.`); | ||
} | ||
@@ -94,3 +94,3 @@ getTypeOfProperty(classType, name, 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.`); | ||
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.`); | ||
} | ||
@@ -97,0 +97,0 @@ } |
@@ -24,3 +24,3 @@ "use strict"; | ||
if (tsutils_1.isCallExpression(node.expression) && tsutils_1.isThenableType(this.checker, node.expression)) | ||
this.addFailureAtNode(node, "Return value of async function call was discarded. Did you mean to 'await' its result?"); | ||
this.addFindingAtNode(node, "Return value of async function call was discarded. Did you mean to 'await' its result?"); | ||
return; | ||
@@ -27,0 +27,0 @@ } |
@@ -21,3 +21,3 @@ "use strict"; | ||
fix.push(ymir_1.Replacement.append(match.index, '('), ymir_1.Replacement.append(node.expression.end, ')')); | ||
this.addFailure(match.index, node.end, "Unnecessary 'await' of a non-Promise value.", fix); | ||
this.addFinding(match.index, node.end, "Unnecessary 'await' of a non-Promise value.", fix); | ||
} | ||
@@ -28,3 +28,3 @@ else if (node.kind === ts.SyntaxKind.AwaitKeyword && node.end === re.lastIndex) { | ||
const start = node.pos - 'for'.length; | ||
this.addFailure(start, parent.statement.pos, "Unnecessary 'for await' of a non-AsyncIterable value.", ymir_1.Replacement.delete(start + 'for'.length, re.lastIndex)); | ||
this.addFinding(start, parent.statement.pos, "Unnecessary 'for await' of a non-AsyncIterable value.", ymir_1.Replacement.delete(start + 'for'.length, re.lastIndex)); | ||
} | ||
@@ -31,0 +31,0 @@ } |
@@ -25,3 +25,3 @@ "use strict"; | ||
this.isDomGlobal(symbol.valueDeclaration, text)) | ||
this.addFailureAtNode(node, `Referencing global '${text}' is not allowed. Did you mean to use a local variable or parameter with a similar name?`); | ||
this.addFindingAtNode(node, `Referencing global '${text}' is not allowed. Did you mean to use a local variable or parameter with a similar name?`); | ||
} | ||
@@ -28,0 +28,0 @@ } |
@@ -29,3 +29,3 @@ "use strict"; | ||
return; | ||
this.addFailureAtNode(errorNode, `Only 'delete' optional properties. Property '${name || symbol.name}' is required.`); | ||
this.addFindingAtNode(errorNode, `Only 'delete' optional properties. Property '${name || symbol.name}' is required.`); | ||
} | ||
@@ -32,0 +32,0 @@ }; |
@@ -48,3 +48,3 @@ "use strict"; | ||
fail({ asteriskToken, name }) { | ||
this.addFailure(asteriskToken.end - 1, asteriskToken.end, `Generator ${name === undefined ? '' : `'${name.getText(this.sourceFile).replace(/'/g, "\\'")}' `}contains no 'yield'.`); | ||
this.addFinding(asteriskToken.end - 1, asteriskToken.end, `Generator ${name === undefined ? '' : `'${name.getText(this.sourceFile).replace(/'/g, "\\'")}' `}contains no 'yield'.`); | ||
} | ||
@@ -51,0 +51,0 @@ }; |
@@ -17,3 +17,3 @@ "use strict"; | ||
re.lastIndex === node.expression.pos) | ||
this.addFailure(node.end, node.end, 'Expected parentheses on constructor call.', ymir_1.Replacement.append(node.end, '()')); | ||
this.addFinding(node.end, node.end, 'Expected parentheses on constructor call.', ymir_1.Replacement.append(node.end, '()')); | ||
} | ||
@@ -20,0 +20,0 @@ } |
@@ -14,3 +14,3 @@ "use strict"; | ||
if (isForbiddenDeclaration(statement)) | ||
this.addFailureAtNode(statement, 'Unexpected lexical declaration in case block.'); | ||
this.addFindingAtNode(statement, 'Unexpected lexical declaration in case block.'); | ||
} | ||
@@ -17,0 +17,0 @@ }; |
@@ -17,3 +17,3 @@ "use strict"; | ||
if (start === match.index) | ||
this.addFailure(start, node.end, "'debugger' statements are forbidden.", canSafelyRemoveStatement(node) | ||
this.addFinding(start, node.end, "'debugger' statements are forbidden.", canSafelyRemoveStatement(node) | ||
? ymir_1.Replacement.delete(node.pos, node.end) | ||
@@ -20,0 +20,0 @@ : { start, end: node.end, text: ';' }); |
@@ -19,3 +19,3 @@ "use strict"; | ||
if (expressionsSeen.has(text)) { | ||
this.addFailureAtNode(clause.expression, `Duplicate 'case ${text}'.`); | ||
this.addFindingAtNode(clause.expression, `Duplicate 'case ${text}'.`); | ||
continue; | ||
@@ -30,3 +30,3 @@ } | ||
if (valuesSeen.has(literals[0])) { | ||
this.addFailureAtNode(clause.expression, `Duplicate 'case ${literals[0]}'.`); | ||
this.addFindingAtNode(clause.expression, `Duplicate 'case ${literals[0]}'.`); | ||
} | ||
@@ -39,3 +39,3 @@ else { | ||
if (literals.every((v) => valuesSeen.has(v))) | ||
this.addFailureAtNode(clause.expression, `Duplicate 'case ${literals.sort().join(' | ')}'.`); | ||
this.addFindingAtNode(clause.expression, `Duplicate 'case ${literals.sort().join(' | ')}'.`); | ||
} | ||
@@ -42,0 +42,0 @@ } |
@@ -33,6 +33,6 @@ "use strict"; | ||
if (property.kind === ts.SyntaxKind.SpreadAssignment) { | ||
this.addFailureAtNode(property, 'All properties of this object are overridden later.'); | ||
this.addFindingAtNode(property, 'All properties of this object are overridden later.'); | ||
} | ||
else { | ||
this.addFailureAtNode(property.name, `Property '${property.name.getText(this.sourceFile)}' is overridden later.`); | ||
this.addFindingAtNode(property.name, `Property '${property.name.getText(this.sourceFile)}' is overridden later.`); | ||
if (isAccessor) | ||
@@ -39,0 +39,0 @@ continue; |
@@ -17,3 +17,3 @@ "use strict"; | ||
const start = clauses[i].getStart(this.sourceFile); | ||
this.addFailure(start, start + kind.length, `Missing 'break' before '${kind}'.`); | ||
this.addFinding(start, start + kind.length, `Missing 'break' before '${kind}'.`); | ||
} | ||
@@ -20,0 +20,0 @@ } |
@@ -66,3 +66,3 @@ "use strict"; | ||
if (typeParameter.default === undefined) | ||
this.addFailureAtNode(node, `TypeParameter '${typeParameter.name.text}' is inferred as '{}'. Consider adding type arguments to the call.`); | ||
this.addFindingAtNode(node, `TypeParameter '${typeParameter.name.text}' is inferred as '{}'. Consider adding type arguments to the call.`); | ||
} | ||
@@ -69,0 +69,0 @@ }; |
@@ -29,3 +29,3 @@ "use strict"; | ||
if (!isEmpty(assertedLiterals)) | ||
this.addFailureAtNode(node, `Type '${format(originalTypeParts)}' cannot be converted to type '${format(assertedLiterals)}'.`); | ||
this.addFindingAtNode(node, `Type '${format(originalTypeParts)}' cannot be converted to type '${format(assertedLiterals)}'.`); | ||
} | ||
@@ -32,0 +32,0 @@ }; |
@@ -29,6 +29,6 @@ "use strict"; | ||
if (!usedInParameters) { | ||
this.addFailureAtNode(typeParameter, `TypeParameter '${typeParameter.name.text}' cannot be inferred from any parameter.`); | ||
this.addFindingAtNode(typeParameter, `TypeParameter '${typeParameter.name.text}' cannot be inferred from any parameter.`); | ||
} | ||
else if (!usedInReturnOrExtends && !this.isConstrainedByOtherTypeParameter(typeParameter, typeParameters)) { | ||
this.addFailureAtNode(typeParameter, `TypeParameter '${typeParameter.name.text}' is not used to enforce a constraint between types and can be replaced with \ | ||
this.addFindingAtNode(typeParameter, `TypeParameter '${typeParameter.name.text}' is not used to enforce a constraint between types and can be replaced with \ | ||
'${typeParameter.constraint ? typeParameter.constraint.getText(this.sourceFile) : 'any'}'.`); | ||
@@ -35,0 +35,0 @@ } |
@@ -22,3 +22,3 @@ "use strict"; | ||
if (parent.kind === ts.SyntaxKind.CaseClause || tsutils_1.isBinaryExpression(parent) && isEqualityCheck(parent.operatorToken.kind)) | ||
this.addFailureAtNode(parent, "Comparing with 'NaN' always yields 'false'. Consider using 'isNaN' instead."); | ||
this.addFindingAtNode(parent, "Comparing with 'NaN' always yields 'false'. Consider using 'isNaN' instead."); | ||
} | ||
@@ -25,0 +25,0 @@ } |
@@ -22,3 +22,3 @@ "use strict"; | ||
if (match.index >= node.getStart(this.sourceFile)) | ||
this.addFailure(match.index + match[1].length, re.lastIndex, 'Octal escape sequences are deprecated and not allowed in strict mode.', ymir_1.Replacement.replace(match.index + match[1].length + 1, re.lastIndex, `x${toHexSequence(parseInt(match[0].substr(match[1].length + 1), 8))}`)); | ||
this.addFinding(match.index + match[1].length, re.lastIndex, 'Octal escape sequences are deprecated and not allowed in strict mode.', ymir_1.Replacement.replace(match.index + match[1].length + 1, re.lastIndex, `x${toHexSequence(parseInt(match[0].substr(match[1].length + 1), 8))}`)); | ||
} | ||
@@ -25,0 +25,0 @@ } |
@@ -25,3 +25,3 @@ "use strict"; | ||
if (hasConflictingAccessModifiers(flags, symbol)) | ||
return this.addFailureAtNode(errorNode, `Property '${name}' has conflicting declarations and is inaccessible in type '${this.checker.typeToString(lhsType)}'.`); | ||
return this.addFindingAtNode(errorNode, `Property '${name}' has conflicting declarations and is inaccessible in type '${this.checker.typeToString(lhsType)}'.`); | ||
if (lhs !== undefined && lhs.kind === ts.SyntaxKind.ThisKeyword && | ||
@@ -31,10 +31,10 @@ flags & ts.ModifierFlags.Abstract && hasNonMethodDeclaration(symbol)) { | ||
if (enclosingClass !== undefined) | ||
return this.addFailureAtNode(errorNode, `Abstract property '${name}' in class '${this.printClass(enclosingClass)}' cannot be accessed during class initialization.`); | ||
return this.addFindingAtNode(errorNode, `Abstract property '${name}' in class '${this.printClass(enclosingClass)}' cannot be accessed during class initialization.`); | ||
} | ||
if (lhs !== undefined && lhs.kind === ts.SyntaxKind.SuperKeyword) { | ||
if (hasNonMethodDeclaration(symbol)) | ||
return this.addFailureAtNode(errorNode, "Only public and protected methods of the base class are accessible via the 'super' keyword."); | ||
return this.addFindingAtNode(errorNode, "Only public and protected methods of the base class are accessible via the 'super' keyword."); | ||
if (flags & ts.ModifierFlags.Abstract && | ||
symbol.declarations.every((d) => tsutils_1.hasModifier(d.modifiers, ts.SyntaxKind.AbstractKeyword))) | ||
return this.addFailureAtNode(errorNode, `Abstract method '${name}' in class '${this.printClass(symbol.declarations[0].parent)}' cannot be accessed via the 'super' keyword.`); | ||
return this.addFindingAtNode(errorNode, `Abstract method '${name}' in class '${this.printClass(symbol.declarations[0].parent)}' cannot be accessed via the 'super' keyword.`); | ||
} | ||
@@ -58,3 +58,3 @@ if ((flags & ts.ModifierFlags.NonPublicAccessibilityModifier) === 0) | ||
if ((flags & ts.ModifierFlags.Static) === 0 && !hasBase(lhsType, enclosingClass, isIdentical)) | ||
return this.addFailureAtNode(errorNode, `Property '${name}' is protected and only accessible through an instance of class '${this.checker.typeToString(enclosingClass)}'.`); | ||
return this.addFindingAtNode(errorNode, `Property '${name}' is protected and only accessible through an instance of class '${this.checker.typeToString(enclosingClass)}'.`); | ||
} | ||
@@ -78,3 +78,3 @@ } | ||
failVisibility(node, property, typeString, isPrivate) { | ||
this.addFailureAtNode(node, `Property '${property}' is ${isPrivate ? 'private' : 'protected'} and only accessible within class '${typeString}'${isPrivate ? '' : ' and its subclasses'}.`); | ||
this.addFindingAtNode(node, `Property '${property}' is ${isPrivate ? 'private' : 'protected'} and only accessible within class '${typeString}'${isPrivate ? '' : ' and its subclasses'}.`); | ||
} | ||
@@ -81,0 +81,0 @@ findEnclosingClass(node, baseClasses) { |
@@ -20,3 +20,3 @@ "use strict"; | ||
replacements.push(ymir_1.Replacement.append(keywordStart, '('), ymir_1.Replacement.append(node.expression.end, ')')); | ||
this.addFailure(keywordStart, node.expression.pos, FAIL_MESSAGE, replacements); | ||
this.addFinding(keywordStart, node.expression.pos, FAIL_MESSAGE, replacements); | ||
} | ||
@@ -23,0 +23,0 @@ } |
@@ -30,3 +30,3 @@ "use strict"; | ||
if (!variableInfo.inGlobalScope && !variableInfo.exported && !variableInfo.uses.some(utils_1.isVariableReassignment)) | ||
this.addFailureAtNode(node, `Variable '${node.text}' is never assigned.`); | ||
this.addFindingAtNode(node, `Variable '${node.text}' is never assigned.`); | ||
} | ||
@@ -33,0 +33,0 @@ }; |
@@ -61,3 +61,3 @@ "use strict"; | ||
} | ||
this.addFailureAtNode(node.getFirstToken(this.sourceFile), 'Unreachable code detected.'); | ||
this.addFindingAtNode(node.getFirstToken(this.sourceFile), 'Unreachable code detected.'); | ||
} | ||
@@ -64,0 +64,0 @@ }; |
@@ -14,3 +14,3 @@ "use strict"; | ||
for (const statement of tsutils_1.getControlFlowEnd(node.finallyBlock).statements) | ||
this.addFailureAtNode(statement.getChildAt(0, this.sourceFile), "Unsafe use of control flow statement inside 'finally'."); | ||
this.addFindingAtNode(statement.getChildAt(0, this.sourceFile), "Unsafe use of control flow statement inside 'finally'."); | ||
} | ||
@@ -17,0 +17,0 @@ } |
@@ -91,3 +91,3 @@ "use strict"; | ||
if (tag.name === 'deprecated' || tag.name === 'experimental') | ||
this.addFailureAtNode(node, `${descr(s, this.checker, hint, node)} is ${tag.name}${tag.text ? ': ' + tag.text : '.'}`); | ||
this.addFindingAtNode(node, `${descr(s, this.checker, hint, node)} is ${tag.name}${tag.text ? ': ' + tag.text : '.'}`); | ||
} | ||
@@ -94,0 +94,0 @@ } |
@@ -36,3 +36,3 @@ "use strict"; | ||
if (!this.isUsed(expr)) | ||
this.addFailureAtNode(errorNode === undefined ? expr : errorNode, FAIL_MESSAGE); | ||
this.addFindingAtNode(errorNode === undefined ? expr : errorNode, FAIL_MESSAGE); | ||
} | ||
@@ -76,3 +76,3 @@ isUsed(node) { | ||
return whenTrueUsed; | ||
this.addFailureAtNode(whenFalseUsed ? whenTrue : whenFalse, FAIL_MESSAGE); | ||
this.addFindingAtNode(whenFalseUsed ? whenTrue : whenFalse, FAIL_MESSAGE); | ||
return true; | ||
@@ -79,0 +79,0 @@ } |
@@ -15,3 +15,3 @@ "use strict"; | ||
const start = label.getStart(this.sourceFile); | ||
this.addFailure(start, label.end, `Unused label '${label.text}'.`, ymir_1.Replacement.delete(start, statement.getStart(this.sourceFile))); | ||
this.addFinding(start, label.end, `Unused label '${label.text}'.`, ymir_1.Replacement.delete(start, statement.getStart(this.sourceFile))); | ||
} | ||
@@ -18,0 +18,0 @@ } |
@@ -39,3 +39,3 @@ "use strict"; | ||
getNullableFlags(this.checker.getTypeAtLocation(node.name), true) & ts.TypeFlags.Undefined)) | ||
this.addFailure(node.exclamationToken.end - 1, node.exclamationToken.end, FAIL_DEFINITE_ASSIGNMENT, ymir_1.Replacement.delete(node.exclamationToken.pos, node.exclamationToken.end)); | ||
this.addFinding(node.exclamationToken.end - 1, node.exclamationToken.end, FAIL_DEFINITE_ASSIGNMENT, ymir_1.Replacement.delete(node.exclamationToken.pos, node.exclamationToken.end)); | ||
} | ||
@@ -48,3 +48,3 @@ checkDefiniteAssignmentAssertionProperty(node) { | ||
getNullableFlags(this.checker.getTypeAtLocation(node), true) & ts.TypeFlags.Undefined)) | ||
this.addFailure(node.exclamationToken.end - 1, node.exclamationToken.end, FAIL_DEFINITE_ASSIGNMENT, ymir_1.Replacement.delete(node.exclamationToken.pos, node.exclamationToken.end)); | ||
this.addFinding(node.exclamationToken.end - 1, node.exclamationToken.end, FAIL_DEFINITE_ASSIGNMENT, ymir_1.Replacement.delete(node.exclamationToken.pos, node.exclamationToken.end)); | ||
} | ||
@@ -67,3 +67,3 @@ checkNonNullAssertion(node) { | ||
} | ||
this.addFailure(node.end - 1, node.end, message, ymir_1.Replacement.delete(node.expression.end, node.end)); | ||
this.addFinding(node.end - 1, node.end, message, ymir_1.Replacement.delete(node.expression.end, node.end)); | ||
} | ||
@@ -92,3 +92,3 @@ checkTypeAssertion(node) { | ||
if (node.kind === ts.SyntaxKind.AsExpression) { | ||
this.addFailure(node.type.pos - 'as'.length, node.end, message, ymir_1.Replacement.delete(node.expression.end, node.end)); | ||
this.addFinding(node.type.pos - 'as'.length, node.end, message, ymir_1.Replacement.delete(node.expression.end, node.end)); | ||
} | ||
@@ -100,3 +100,3 @@ else { | ||
fix.push(ymir_1.Replacement.append(start, '('), ymir_1.Replacement.append(node.end, ')')); | ||
this.addFailure(start, node.expression.pos, message, fix); | ||
this.addFinding(start, node.expression.pos, message, fix); | ||
} | ||
@@ -103,0 +103,0 @@ } |
@@ -17,3 +17,3 @@ "use strict"; | ||
const start = declareKeyword.end - 'declare'.length; | ||
this.addFailure(start, declareKeyword.end, "Using the 'declare' keyword here is redundant as the statement has no runtime value.", ymir_1.Replacement.delete(start, tsutils_1.getNextToken(declareKeyword).getStart(this.sourceFile))); | ||
this.addFinding(start, declareKeyword.end, "Using the 'declare' keyword here is redundant as the statement has no runtime value.", ymir_1.Replacement.delete(start, tsutils_1.getNextToken(declareKeyword).getStart(this.sourceFile))); | ||
} | ||
@@ -20,0 +20,0 @@ } |
@@ -60,3 +60,3 @@ "use strict"; | ||
if (symbol !== undefined && !symbolMaybeUndefined(checker, symbol, name)) | ||
this.addFailureAtNode(errorNode, "Unnecessary default value as this property is never 'undefined'.", ymir_1.Replacement.delete(tsutils_1.getChildOfKind(errorNode.parent, ts.SyntaxKind.EqualsToken, this.sourceFile).pos, errorNode.end)); | ||
this.addFindingAtNode(errorNode, "Unnecessary default value as this property is never 'undefined'.", ymir_1.Replacement.delete(tsutils_1.getChildOfKind(errorNode.parent, ts.SyntaxKind.EqualsToken, this.sourceFile).pos, errorNode.end)); | ||
} | ||
@@ -76,3 +76,3 @@ } | ||
continue; | ||
this.addFailureAtNode(element.initializer, "Unnecessary default value as this property is never 'undefined'."); | ||
this.addFindingAtNode(element.initializer, "Unnecessary default value as this property is never 'undefined'."); | ||
} | ||
@@ -107,3 +107,3 @@ function maybeUndefined({ symbolName }) { | ||
} | ||
this.addFailure(node.end - 'undefined'.length, node.end, message, fix); | ||
this.addFinding(node.end - 'undefined'.length, node.end, message, fix); | ||
} | ||
@@ -110,0 +110,0 @@ removeUndefinedFromType(type) { |
@@ -18,3 +18,3 @@ "use strict"; | ||
!isLabelNecessary(node.label)) | ||
this.addFailureAtNode(node.label, `Jump label '${node.label.text}' is unnecessary.`, ymir_1.Replacement.delete(node.label.pos, node.label.end)); | ||
this.addFindingAtNode(node.label, `Jump label '${node.label.text}' is unnecessary.`, ymir_1.Replacement.delete(node.label.pos, node.label.end)); | ||
} | ||
@@ -21,0 +21,0 @@ } |
@@ -113,3 +113,3 @@ "use strict"; | ||
if (result !== undefined) | ||
return this.addFailureAtNode(node, result ? 'Expression is always truthy.' : 'Expression is always falsy.'); | ||
return this.addFindingAtNode(node, result ? 'Expression is always truthy.' : 'Expression is always falsy.'); | ||
} | ||
@@ -116,0 +116,0 @@ isTruthyFalsy(node) { |
@@ -7,3 +7,3 @@ "use strict"; | ||
const tsutils_1 = require("tsutils"); | ||
const FAILURE_STRING = 'Using the spread operator here is not necessary.'; | ||
const MESSAGE = 'Using the spread operator here is not necessary.'; | ||
let Rule = class Rule extends ymir_1.AbstractRule { | ||
@@ -33,3 +33,3 @@ apply() { | ||
return; | ||
this.addFailureAtNode(node, FAILURE_STRING, removeUselessSpread(node, node.expression.elements)); | ||
this.addFindingAtNode(node, MESSAGE, removeUselessSpread(node, node.expression.elements)); | ||
} | ||
@@ -39,3 +39,3 @@ checkSpreadAssignment(node) { | ||
return; | ||
this.addFailureAtNode(node, FAILURE_STRING, removeUselessSpread(node, node.expression.properties)); | ||
this.addFindingAtNode(node, MESSAGE, removeUselessSpread(node, node.expression.properties)); | ||
} | ||
@@ -45,3 +45,3 @@ checkJsxSpreadAttribute(node) { | ||
return; | ||
this.addFailureAtNode(node, FAILURE_STRING, removeUselessJsxSpreadAttribute(node, node.expression.properties)); | ||
this.addFindingAtNode(node, MESSAGE, removeUselessJsxSpreadAttribute(node, node.expression.properties)); | ||
} | ||
@@ -48,0 +48,0 @@ }; |
@@ -40,3 +40,3 @@ "use strict"; | ||
if (reason !== undefined) | ||
this.addFailureAtNode(directive, `Redundant 'use strict': ${reason}.`, ymir_1.Replacement.delete(directive.pos, directive.end)); | ||
this.addFindingAtNode(directive, `Redundant 'use strict': ${reason}.`, ymir_1.Replacement.delete(directive.pos, directive.end)); | ||
return; | ||
@@ -43,0 +43,0 @@ } |
@@ -13,3 +13,3 @@ "use strict"; | ||
})(Mode = exports.Mode || (exports.Mode = {})); | ||
const FAILURE_STRINGS = { | ||
const MESSAGES = { | ||
[Mode.Never]: 'Parameter properties have been disallowed.', | ||
@@ -47,3 +47,3 @@ [Mode.WhenPossible]: 'Use parameter properties when possible.', | ||
for (const param of construct.parameters.filter(tsutils_1.isParameterProperty)) | ||
this.addFailureAtNode(param, FAILURE_STRINGS[Mode.Never], getFixerForDisallowedParameterProp(construct, param, tsutils_1.getLineBreakStyle(this.context.sourceFile))); | ||
this.addFindingAtNode(param, MESSAGES[Mode.Never], getFixerForDisallowedParameterProp(construct, param, tsutils_1.getLineBreakStyle(this.context.sourceFile))); | ||
break; | ||
@@ -58,7 +58,7 @@ case Mode.Consistent: | ||
for (const param of construct.parameters.filter(tsutils_1.isParameterProperty)) | ||
this.addFailure(param.pos, param.end, FAILURE_STRINGS[Mode.Consistent].cannotBeParamPropsOnly, getFixerForDisallowedParameterProp(construct, param, tsutils_1.getLineBreakStyle(this.context.sourceFile))); | ||
this.addFinding(param.pos, param.end, MESSAGES[Mode.Consistent].cannotBeParamPropsOnly, getFixerForDisallowedParameterProp(construct, param, tsutils_1.getLineBreakStyle(this.context.sourceFile))); | ||
} | ||
else if (allPropsCanBeParamProps && !construct.parameters.every(tsutils_1.isParameterProperty)) { | ||
for (const param of construct.parameters.filter((p) => !tsutils_1.isParameterProperty(p))) | ||
this.addFailure(param.pos, param.end, FAILURE_STRINGS[Mode.Consistent].canBeParamPropsOnly, getFixerForLonghandProp(param, construct)); | ||
this.addFinding(param.pos, param.end, MESSAGES[Mode.Consistent].canBeParamPropsOnly, getFixerForLonghandProp(param, construct)); | ||
} | ||
@@ -69,3 +69,3 @@ break; | ||
if (!tsutils_1.isParameterProperty(param) && canBeParameterProperty(param, construct)) | ||
this.addFailureAtNode(param, FAILURE_STRINGS[Mode.WhenPossible], getFixerForLonghandProp(param, construct)); | ||
this.addFindingAtNode(param, MESSAGES[Mode.WhenPossible], getFixerForLonghandProp(param, construct)); | ||
} | ||
@@ -72,0 +72,0 @@ } |
@@ -78,3 +78,3 @@ "use strict"; | ||
for (const name of declaration.identifiers) | ||
this.addFailureAtNode(name, `Variable '${name.text}' is never reassigned. Prefer 'const' instead of '${keyword}'.`, fix); | ||
this.addFindingAtNode(name, `Variable '${name.text}' is never reassigned. Prefer 'const' instead of '${keyword}'.`, fix); | ||
} | ||
@@ -81,0 +81,0 @@ } |
@@ -19,3 +19,3 @@ "use strict"; | ||
return; | ||
this.addFailureAtNode(node.argumentExpression, `Prefer 'obj.${text}' over 'obj[${node.argumentExpression.getText(this.sourceFile)}]'.`, node.expression.kind === ts.SyntaxKind.NumericLiteral | ||
this.addFindingAtNode(node.argumentExpression, `Prefer 'obj.${text}' over 'obj[${node.argumentExpression.getText(this.sourceFile)}]'.`, node.expression.kind === ts.SyntaxKind.NumericLiteral | ||
? [ | ||
@@ -22,0 +22,0 @@ ymir_1.Replacement.append(node.expression.getStart(this.sourceFile), '('), |
@@ -35,3 +35,3 @@ "use strict"; | ||
if (this.isIterationPossible(arrayVariable)) | ||
this.addFailure(node.getStart(this.sourceFile), node.statement.pos, `Prefer a 'for-of' loop over a 'for' loop for this simple iteration.`); | ||
this.addFinding(node.getStart(this.sourceFile), node.statement.pos, `Prefer a 'for-of' loop over a 'for' loop for this simple iteration.`); | ||
} | ||
@@ -38,0 +38,0 @@ isIterationPossible(node) { |
@@ -18,3 +18,3 @@ "use strict"; | ||
const start = end - 'module'.length; | ||
this.addFailure(start, end, "Prefer 'namespace' over 'module'.", ymir_1.Replacement.replace(start, end, 'namespace')); | ||
this.addFinding(start, end, "Prefer 'namespace' over 'module'.", ymir_1.Replacement.replace(start, end, 'namespace')); | ||
} | ||
@@ -21,0 +21,0 @@ this.checkModule(statement); |
@@ -18,3 +18,3 @@ "use strict"; | ||
this.isCorrectArgumentType(parent.arguments[0])) | ||
this.addFailure(match.index, node.end, `Prefer 'Number.${node.text}' over '${node.text}'.`, ymir_1.Replacement.append(match.index, 'Number.')); | ||
this.addFinding(match.index, node.end, `Prefer 'Number.${node.text}' over '${node.text}'.`, ymir_1.Replacement.append(match.index, 'Number.')); | ||
} | ||
@@ -21,0 +21,0 @@ } |
@@ -25,6 +25,6 @@ "use strict"; | ||
if (grandParent.arguments.length === 1) { | ||
this.addFailureAtNode(grandParent, "No need for 'Object.assign', use the object directly.", createFix(grandParent, this.sourceFile)); | ||
this.addFindingAtNode(grandParent, "No need for 'Object.assign', use the object directly.", createFix(grandParent, this.sourceFile)); | ||
} | ||
else if (grandParent.arguments.every(this.isSpreadableObject, this)) { | ||
this.addFailureAtNode(grandParent, "Prefer object spread over 'Object.assign'.", createFix(grandParent, this.sourceFile)); | ||
this.addFindingAtNode(grandParent, "Prefer object spread over 'Object.assign'.", createFix(grandParent, this.sourceFile)); | ||
} | ||
@@ -31,0 +31,0 @@ } |
@@ -11,3 +11,3 @@ "use strict"; | ||
if (tsutils_1.isExpressionStatement(node) && tsutils_1.isCallExpression(node.expression) && this.returnsNever(node.expression)) | ||
this.addFailureAtNode(node, `This call never returns. Consider ${isReturnAllowed(node) ? 'return' : 'throw'}ing the result for better control flow analysis and type inference.`); | ||
this.addFindingAtNode(node, `This call never returns. Consider ${isReturnAllowed(node) ? 'return' : 'throw'}ing the result for better control flow analysis and type inference.`); | ||
} | ||
@@ -14,0 +14,0 @@ returnsNever(node) { |
@@ -9,3 +9,3 @@ "use strict"; | ||
const start = diagnostic.start; | ||
this.addFailure(start, start + diagnostic.length, ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')); | ||
this.addFinding(start, start + diagnostic.length, ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')); | ||
} | ||
@@ -12,0 +12,0 @@ } |
@@ -11,3 +11,3 @@ "use strict"; | ||
const lines = sourceFile.getLineStarts(); | ||
this.addFailure(end, end, 'File must end with a newline.', ymir_1.Replacement.append(end, lines.length === 0 || sourceFile.text[lines[1] - 2] !== '\r' ? '\n' : '\r\n')); | ||
this.addFinding(end, end, 'File must end with a newline.', ymir_1.Replacement.append(end, lines.length === 0 || sourceFile.text[lines[1] - 2] !== '\r' ? '\n' : '\r\n')); | ||
} | ||
@@ -14,0 +14,0 @@ } |
@@ -46,3 +46,3 @@ "use strict"; | ||
if (tsutils_1.isThenableType(this.checker, node)) | ||
this.addFailure(pos - 'return'.length, pos, "Missing 'await' of Promise returned inside try-catch.", needsParens(node) | ||
this.addFinding(pos - 'return'.length, pos, "Missing 'await' of Promise returned inside try-catch.", needsParens(node) | ||
? [ | ||
@@ -49,0 +49,0 @@ ymir_1.Replacement.append(pos, ' await'), |
@@ -36,3 +36,3 @@ "use strict"; | ||
const needsParens = tsutils_1.isBinaryExpression(parent) && parent.operatorToken.kind === ts.SyntaxKind.AsteriskAsteriskToken; | ||
context.addFailure(match.index, node.end, "Use the classic type assertion style '<T>obj' instead.", [ | ||
context.addFinding(match.index, node.end, "Use the classic type assertion style '<T>obj' instead.", [ | ||
ymir_1.Replacement.append(node.getStart(context.sourceFile), `${charIf(needsParens, '(')}<${node.type.getText(context.sourceFile)}>${charIf(expressionNeedsParens, '(')}`), | ||
@@ -50,3 +50,3 @@ ymir_1.Replacement.replace(node.expression.end, node.end, charIf(expressionNeedsParens, ')') + charIf(needsParens, ')')), | ||
const start = node.getStart(context.sourceFile); | ||
context.addFailure(start, node.expression.pos, "Use 'obj as T' instead.", [ | ||
context.addFinding(start, node.expression.pos, "Use 'obj as T' instead.", [ | ||
ymir_1.Replacement.replace(start, node.expression.getStart(context.sourceFile), charIf(expressionParens, '(') + charIf(assertionParens, '(')), | ||
@@ -53,0 +53,0 @@ ymir_1.Replacement.append(node.end, `${charIf(expressionParens, ')')} as ${node.type.getText(context.sourceFile)}${charIf(assertionParens, ')')}`), |
@@ -14,3 +14,3 @@ "use strict"; | ||
const start = diagnostic.start; | ||
this.addFailure(start, start + diagnostic.length, ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')); | ||
this.addFinding(start, start + diagnostic.length, ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n')); | ||
} | ||
@@ -17,0 +17,0 @@ } |
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
374563
0.04%4434
0.16%+ Added
- Removed