Implement custom no-magic-numbers rule that doesn't include magic numbers passed into BigNumber instantiations (e.g const amount = new BigNumber(5); )
This commit is contained in:
76
packages/tslint-config/rules/customNoMagicNumbersRule.ts
Normal file
76
packages/tslint-config/rules/customNoMagicNumbersRule.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import * as Lint from 'tslint';
|
||||
import { isPrefixUnaryExpression } from 'tsutils';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
/**
|
||||
* A modified version of the no-magic-numbers rule that allows for magic numbers
|
||||
* when instantiating a BigNumber instance.
|
||||
* E.g We want to be able to write:
|
||||
* const amount = new BigNumber(5);
|
||||
* Original source: https://github.com/palantir/tslint/blob/42b058a6baa688f8be8558b277eb056c3ff79818/src/rules/noMagicNumbersRule.ts
|
||||
*/
|
||||
export class Rule extends Lint.Rules.AbstractRule {
|
||||
public static ALLOWED_NODES = new Set<ts.SyntaxKind>([
|
||||
ts.SyntaxKind.ExportAssignment,
|
||||
ts.SyntaxKind.FirstAssignment,
|
||||
ts.SyntaxKind.LastAssignment,
|
||||
ts.SyntaxKind.PropertyAssignment,
|
||||
ts.SyntaxKind.ShorthandPropertyAssignment,
|
||||
ts.SyntaxKind.VariableDeclaration,
|
||||
ts.SyntaxKind.VariableDeclarationList,
|
||||
ts.SyntaxKind.EnumMember,
|
||||
ts.SyntaxKind.PropertyDeclaration,
|
||||
ts.SyntaxKind.Parameter,
|
||||
]);
|
||||
|
||||
public static DEFAULT_ALLOWED = [-1, 0, 1];
|
||||
|
||||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
|
||||
const allowedNumbers = this.ruleArguments.length > 0 ? this.ruleArguments : Rule.DEFAULT_ALLOWED;
|
||||
return this.applyWithWalker(
|
||||
new CustomNoMagicNumbersWalker(sourceFile, this.ruleName, new Set(allowedNumbers.map(String))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:max-classes-per-file
|
||||
class CustomNoMagicNumbersWalker extends Lint.AbstractWalker<Set<string>> {
|
||||
public static FAILURE_STRING = "'magic numbers' are not allowed";
|
||||
private static _isNegativeNumberLiteral(
|
||||
node: ts.Node,
|
||||
): node is ts.PrefixUnaryExpression & { operand: ts.NumericLiteral } {
|
||||
return (
|
||||
isPrefixUnaryExpression(node) &&
|
||||
node.operator === ts.SyntaxKind.MinusToken &&
|
||||
node.operand.kind === ts.SyntaxKind.NumericLiteral
|
||||
);
|
||||
}
|
||||
public walk(sourceFile: ts.SourceFile): void {
|
||||
const cb = (node: ts.Node): void => {
|
||||
if (node.kind === ts.SyntaxKind.NumericLiteral) {
|
||||
return this.checkNumericLiteral(node, (node as ts.NumericLiteral).text);
|
||||
}
|
||||
if (CustomNoMagicNumbersWalker._isNegativeNumberLiteral(node)) {
|
||||
return this.checkNumericLiteral(node, `-${(node.operand as ts.NumericLiteral).text}`);
|
||||
}
|
||||
return ts.forEachChild(node, cb);
|
||||
};
|
||||
return ts.forEachChild(sourceFile, cb);
|
||||
}
|
||||
|
||||
// tslint:disable:no-non-null-assertion
|
||||
// tslint:disable-next-line:underscore-private-and-protected
|
||||
private checkNumericLiteral(node: ts.Node, num: string): void {
|
||||
if (!Rule.ALLOWED_NODES.has(node.parent!.kind) && !this.options.has(num)) {
|
||||
if (node.parent!.kind === ts.SyntaxKind.NewExpression) {
|
||||
const className = (node.parent! as any).expression.escapedText;
|
||||
const BIG_NUMBER_NEW_EXPRESSION = 'BigNumber';
|
||||
if (className === BIG_NUMBER_NEW_EXPRESSION) {
|
||||
return; // noop
|
||||
}
|
||||
}
|
||||
this.addFailureAtNode(node, CustomNoMagicNumbersWalker.FAILURE_STRING);
|
||||
}
|
||||
}
|
||||
// tslint:enable:no-non-null-assertion
|
||||
}
|
||||
Reference in New Issue
Block a user