80 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			80 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import * as Lint from 'tslint';
 | 
						|
import { isPrefixUnaryExpression } from 'tsutils';
 | 
						|
import * as ts from 'typescript';
 | 
						|
 | 
						|
// tslint:disable:no-unnecessary-type-assertion
 | 
						|
/**
 | 
						|
 * 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(
 | 
						|
            // tslint:disable-next-line:no-inferred-empty-object-type
 | 
						|
            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
 | 
						|
}
 | 
						|
// tslint:enable:no-unnecessary-type-assertion
 |