function cb(node) {
     switch (node.kind) {
         case ts.SyntaxKind.ClassDeclaration:
             checkNode(node, exports.ARGUMENT_CLASSES);
             break;
         case ts.SyntaxKind.EnumDeclaration:
             checkNode(node, exports.ARGUMENT_ENUMS);
             for (var _i = 0, _a = node.members; _i < _a.length; _i++) {
                 var member = _a[_i];
                 // Enum members don't have modifiers, so use the parent
                 // enum declaration when checking the requirements.
                 checkNode(member, exports.ARGUMENT_ENUM_MEMBERS, node);
             }
             break;
         case ts.SyntaxKind.FunctionDeclaration:
             checkNode(node, exports.ARGUMENT_FUNCTIONS);
             break;
         case ts.SyntaxKind.InterfaceDeclaration:
             checkNode(node, exports.ARGUMENT_INTERFACES);
             break;
         case ts.SyntaxKind.MethodDeclaration:
             if (node.parent.kind !== ts.SyntaxKind.ObjectLiteralExpression) {
                 checkNode(node, exports.ARGUMENT_METHODS);
             }
             break;
         case ts.SyntaxKind.ModuleDeclaration:
             checkNode(node, exports.ARGUMENT_NAMESPACES);
             break;
         case ts.SyntaxKind.PropertyDeclaration:
             checkNode(node, exports.ARGUMENT_PROPERTIES);
             break;
         case ts.SyntaxKind.TypeAliasDeclaration:
             checkNode(node, exports.ARGUMENT_TYPES);
             break;
         case ts.SyntaxKind.VariableStatement:
             // Only check variables at the namespace/module-level or file-level
             // and not variables declared inside functions and other things.
             switch (node.parent.kind) {
                 case ts.SyntaxKind.SourceFile:
                 case ts.SyntaxKind.ModuleBlock:
                     for (var _b = 0, _c = node.declarationList.declarations; _b < _c.length; _b++) {
                         var declaration = _c[_b];
                         checkNode(declaration, exports.ARGUMENT_VARIABLES, node);
                     }
             }
             break;
         case ts.SyntaxKind.GetAccessor:
         case ts.SyntaxKind.SetAccessor:
             if (node.parent.kind !== ts.SyntaxKind.ObjectLiteralExpression) {
                 checkNode(node, exports.ARGUMENT_PROPERTIES);
             }
     }
     return ts.forEachChild(node, cb);
 }
 var cb = function (node) {
     if (shouldCheck(node, _this.options)) {
         var name = node.name, type = node.type, initializer = node.initializer;
         if (type !== undefined && initializer !== undefined
             && typeIsInferrable(type.kind, initializer)) {
             var fix = Lint.Replacement.deleteFromTo(name.end, type.end);
             _this.addFailureAtNode(type, Rule.FAILURE_STRING_FACTORY(ts.tokenToString(type.kind)), fix);
         }
     }
     return ts.forEachChild(node, cb);
 };
 function handleConstructor(node) {
     scope.enterConstructor();
     for (var _i = 0, _a = node.parameters; _i < _a.length; _i++) {
         var parameter = _a[_i];
         if (utils.isModifierFlagSet(parameter, ts.ModifierFlags.Private)) {
             scope.addDeclaredVariable(parameter);
         }
     }
     ts.forEachChild(node, visitNode);
     scope.exitConstructor();
 }
Example #4
0
 return ts.forEachChild(ctx.sourceFile, function cb(node) {
     if (tsutils_1.isNewExpression(node) && node.expression.kind === ts.SyntaxKind.Identifier) {
         switch (node.expression.text) {
             case "Boolean":
             case "String":
             case "Number":
                 ctx.addFailure(node.getStart(ctx.sourceFile), node.expression.end, Rule.FAILURE_STRING);
         }
     }
     return ts.forEachChild(node, cb);
 });
function walk(ctx, allowSingleConcat) {
    return ts.forEachChild(ctx.sourceFile, function cb(node) {
        var failure = getError(node, allowSingleConcat);
        if (failure !== undefined) {
            ctx.addFailureAtNode(node, failure);
        }
        else {
            return ts.forEachChild(node, cb);
        }
    });
}
Example #6
0
function walk(ctx) {
    var sourceFile = ctx.sourceFile;
    return ts.forEachChild(sourceFile, function cb(node) {
        if (tsutils_1.isNumericLiteral(node)) {
            return check(node);
        }
        return ts.forEachChild(node, cb);
    });
    function check(node) {
        // Apparently the number literal '0.0' has a '.text' of '0', so use '.getText()' instead.
        var text = node.getText(sourceFile);
        if (text.length <= 1) {
            return;
        }
        if (text.startsWith("0")) {
            // Hex/octal/binary number can't have decimal point or exponent, so no other errors possible.
            switch (text[1]) {
                case "x":
                    if (!utils_1.isUpperCase(text.slice(2))) {
                        ctx.addFailureAtNode(node, Rule.FAILURE_STRING_NOT_UPPERCASE);
                    }
                    return;
                case "o":
                case "b":
                    return;
                case ".":
                    break;
                default:
                    ctx.addFailureAtNode(node, Rule.FAILURE_STRING_LEADING_0);
                    return;
            }
        }
        var _a = text.split(/e/i), num = _a[0], exp = _a[1];
        if (exp !== undefined && (exp.startsWith("-0") || exp.startsWith("0"))) {
            ctx.addFailureAt(node.getEnd() - exp.length, exp.length, Rule.FAILURE_STRING_LEADING_0);
        }
        if (!num.includes(".")) {
            return;
        }
        if (num.startsWith(".")) {
            fail(Rule.FAILURE_STRING_LEADING_DECIMAL);
        }
        if (num.endsWith(".")) {
            fail(Rule.FAILURE_STRING_TRAILING_DECIMAL);
        }
        // Allow '10', but not '1.0'
        if (num.endsWith("0")) {
            fail(Rule.FAILURE_STRING_TRAILING_0);
        }
        function fail(message) {
            ctx.addFailureAt(node.getStart(sourceFile), num.length, message);
        }
    }
}
Example #7
0
// Find all nodes from the AST in the subtree of node of SyntaxKind kind.
function collectDeepNodes(node, kind) {
    const nodes = [];
    const helper = (child) => {
        if (child.kind === kind) {
            nodes.push(child);
        }
        ts.forEachChild(child, helper);
    };
    ts.forEachChild(node, helper);
    return nodes;
}
Example #8
0
 return ts.forEachChild(ctx.sourceFile, function recur(node) {
     if (tsutils_1.isClassLikeDeclaration(node)) {
         for (var _i = 0, _a = node.members; _i < _a.length; _i++) {
             var child = _a[_i];
             if (shouldCheck(child)) {
                 check(child);
             }
         }
     }
     return ts.forEachChild(node, recur);
 });
 TypedefWhitespaceWalker.prototype.walk = function (sourceFile) {
     var _this = this;
     var cb = function (node) {
         var optionType = getOptionType(node);
         if (optionType !== undefined) {
             _this.checkSpace(node, optionType);
         }
         return ts.forEachChild(node, cb);
     };
     return ts.forEachChild(sourceFile, cb);
 };
 function handleNode(node) {
     switch (node.kind) {
         case ts.SyntaxKind.ImportDeclaration:
             imports.push(node.moduleSpecifier.text);
             break;
         case ts.SyntaxKind.ImportEqualsDeclaration:
             imports.push(node.moduleReference.expression.text);
             break;
     }
     ts.forEachChild(node, handleNode);
 }
 return ts.forEachChild(ctx.sourceFile, function cb(node) {
     if (tsutils_1.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.PlusToken) {
         var tc = program.getTypeChecker();
         var leftType = getBaseTypeOfLiteralType(tc.getTypeAtLocation(node.left));
         var rightType = getBaseTypeOfLiteralType(tc.getTypeAtLocation(node.right));
         if (leftType === "invalid" || rightType === "invalid" || leftType !== rightType) {
             return ctx.addFailureAtNode(node, Rule.INVALID_TYPES_ERROR);
         }
     }
     return ts.forEachChild(node, cb);
 });
Example #12
0
 function visit(node) {
     readThrough(node);
     var replacement = replacer(node);
     if (replacement != null) {
         code += replacement;
         skip(node);
     }
     else {
         ts.forEachChild(node, visit);
     }
 }
Example #13
0
function findNode(node, kind, text) {
    if (node.kind === kind && node.getText() === text) {
        // throw new Error(node.getText());
        return node;
    }
    let foundNode = null;
    ts.forEachChild(node, childNode => {
        foundNode = foundNode || findNode(childNode, kind, text);
    });
    return foundNode;
}
 return ts.forEachChild(ctx.sourceFile, function cb(node) {
     if (node.kind === ts.SyntaxKind.ForInStatement) {
         var type = program.getTypeChecker().getTypeAtLocation(node.expression);
         if (type.symbol !== undefined && type.symbol.name === "Array" ||
             // tslint:disable-next-line:no-bitwise
             (type.flags & ts.TypeFlags.StringLike) !== 0) {
             ctx.addFailureAtNode(node, Rule.FAILURE_STRING);
         }
     }
     return ts.forEachChild(node, cb);
 });
Example #15
0
 return ts.forEachChild(sourceFile, function cb(node) {
     switch (node.kind) {
         case ts.SyntaxKind.ArrayType:
             checkArrayType(node);
             break;
         case ts.SyntaxKind.TypeReference:
             checkTypeReference(node);
             break;
     }
     return ts.forEachChild(node, cb);
 });
 return ts.forEachChild(ctx.sourceFile, function cb(node) {
     if (node.kind === ts.SyntaxKind.Constructor) {
         for (var _i = 0, _a = node.parameters; _i < _a.length; _i++) {
             var parameter = _a[_i];
             if (tsutils_1.isParameterProperty(parameter)) {
                 ctx.addFailure(parameter.getStart(ctx.sourceFile), parameter.name.pos, Rule.FAILURE_STRING_FACTORY(parameter.name.getText(ctx.sourceFile)));
             }
         }
     }
     return ts.forEachChild(node, cb);
 });
 return ts.forEachChild(sourceFile, function cb(node) {
     if (utils.isArrowFunction(node) && utils.isBlock(node.body)) {
         var expr = getSimpleReturnExpression(node.body);
         if (expr !== undefined &&
             (multiline ||
                 utils.isSameLine(sourceFile, node.body.getStart(sourceFile), node.body.end))) {
             var isObjectLiteral = expr.kind === ts.SyntaxKind.ObjectLiteralExpression;
             ctx.addFailureAtNode(node.body, Rule.FAILURE_STRING(isObjectLiteral), createFix(node, node.body, expr, sourceFile.text));
         }
     }
     return ts.forEachChild(node, cb);
 });
 var cb = function (node) {
     if (node.kind >= ts.SyntaxKind.FirstTemplateToken &&
         node.kind <= ts.SyntaxKind.LastTemplateToken) {
         intervals.push({
             end: node.end,
             pos: node.getStart(sourceFile),
         });
     }
     else {
         return ts.forEachChild(node, cb);
     }
 };
 var cb = function (node) {
     if (tsutils_1.isCallExpression(node) && tsutils_1.isIdentifier(node.expression) && node.expression.text === "parseInt") {
         return node.arguments.length === 0 ? undefined : cb(node.arguments[0]);
     }
     if (node.kind === ts.SyntaxKind.NumericLiteral) {
         return _this.checkNumericLiteral(node, node.text);
     }
     if (utils_1.isNegativeNumberLiteral(node)) {
         return _this.checkNumericLiteral(node, "-" + node.operand.text);
     }
     return ts.forEachChild(node, cb);
 };
function findTopLevelFunctions(parentNode) {
    const topLevelFunctions = new Set();
    function cb(node) {
        // Stop recursing into this branch if it's a definition construct.
        // These are function expression, function declaration, class, or arrow function (lambda).
        // The body of these constructs will not execute when loading the module, so we don't
        // need to mark function calls inside them as pure.
        // Class static initializers in ES2015 are an exception we don't cover. They would need similar
        // processing as enums to prevent property setting from causing the class to be retained.
        if (ts.isFunctionDeclaration(node)
            || ts.isFunctionExpression(node)
            || ts.isClassDeclaration(node)
            || ts.isArrowFunction(node)
            || ts.isMethodDeclaration(node)) {
            return;
        }
        let noPureComment = !hasPureComment(node);
        let innerNode = node;
        while (innerNode && ts.isParenthesizedExpression(innerNode)) {
            innerNode = innerNode.expression;
            noPureComment = noPureComment && !hasPureComment(innerNode);
        }
        if (!innerNode) {
            return;
        }
        if (noPureComment) {
            if (ts.isNewExpression(innerNode)) {
                topLevelFunctions.add(node);
            }
            else if (ts.isCallExpression(innerNode)) {
                let expression = innerNode.expression;
                while (expression && ts.isParenthesizedExpression(expression)) {
                    expression = expression.expression;
                }
                if (expression) {
                    if (ts.isFunctionExpression(expression)) {
                        // Skip IIFE's with arguments
                        // This could be improved to check if there are any references to variables
                        if (innerNode.arguments.length === 0) {
                            topLevelFunctions.add(node);
                        }
                    }
                    else {
                        topLevelFunctions.add(node);
                    }
                }
            }
        }
        ts.forEachChild(innerNode, cb);
    }
    ts.forEachChild(parentNode, cb);
    return topLevelFunctions;
}
Example #21
0
function findClassDeclarations(node) {
    const classes = [];
    // Find all class declarations, build a ClassData for each.
    ts.forEachChild(node, (child) => {
        if (child.kind !== ts.SyntaxKind.VariableStatement) {
            return;
        }
        const varStmt = child;
        if (varStmt.declarationList.declarations.length > 1) {
            return;
        }
        const varDecl = varStmt.declarationList.declarations[0];
        if (varDecl.name.kind !== ts.SyntaxKind.Identifier) {
            return;
        }
        const name = varDecl.name.text;
        const expr = varDecl.initializer;
        if (!expr || expr.kind !== ts.SyntaxKind.ParenthesizedExpression) {
            return;
        }
        if (expr.expression.kind !== ts.SyntaxKind.CallExpression) {
            return;
        }
        const callExpr = expr.expression;
        if (callExpr.expression.kind !== ts.SyntaxKind.FunctionExpression) {
            return;
        }
        const fn = callExpr.expression;
        if (fn.body.statements.length < 2) {
            return;
        }
        if (fn.body.statements[0].kind !== ts.SyntaxKind.FunctionDeclaration) {
            return;
        }
        const innerFn = fn.body.statements[0];
        if (fn.body.statements[fn.body.statements.length - 1].kind !== ts.SyntaxKind.ReturnStatement) {
            return;
        }
        if (!innerFn.name || innerFn.name.kind !== ts.SyntaxKind.Identifier) {
            return;
        }
        if (innerFn.name.text !== name) {
            return;
        }
        classes.push({
            name,
            class: varDecl,
            classFunction: fn,
            statements: [],
        });
    });
    return classes;
}
 return ts.forEachChild(ctx.sourceFile, function cb(node) {
     if (tsutils_1.isPropertySignature(node)) {
         var type = node.type;
         if (type !== undefined && tsutils_1.isFunctionTypeNode(type)) {
             ctx.addFailureAtNode(node.name, Rule.FAILURE_STRING, type.type === undefined ? undefined : [
                 Lint.Replacement.deleteFromTo(Lint.childOfKind(node, ts.SyntaxKind.ColonToken).getStart(), type.getStart()),
                 Lint.Replacement.replaceFromTo(Lint.childOfKind(type, ts.SyntaxKind.EqualsGreaterThanToken).pos, type.type.pos, ":"),
             ]);
         }
     }
     return ts.forEachChild(node, cb);
 });
 var cb = function (node) {
     if (tsutils_1.isIterationStatement(node)) {
         _this.checkStatement(node.statement, node, 0, node.end);
     }
     else if (tsutils_1.isIfStatement(node)) {
         _this.checkStatement(node.thenStatement, node, 0);
         if (node.elseStatement !== undefined && node.elseStatement.kind !== ts.SyntaxKind.IfStatement) {
             _this.checkStatement(node.elseStatement, node, 5);
         }
     }
     return ts.forEachChild(node, cb);
 };
Example #24
0
// 1) If TS sees an empty decorator array, it will still emit a `__decorate` call.
//    This seems to be a TS bug.
// 2) Also ensure nodes with modified decorators have parents
//    built in TS transformers assume certain nodes have parents (fixed in TS 2.7+)
function cleanupDecorators(node) {
    if (node.decorators) {
        if (node.decorators.length == 0) {
            node.decorators = undefined;
        }
        else if (node.parent == undefined) {
            const originalNode = ts.getParseTreeNode(node);
            node.parent = originalNode.parent;
        }
    }
    ts.forEachChild(node, node => cleanupDecorators(node));
}
 function cb(node) {
     if (node.kind === ts.SyntaxKind.ImportDeclaration
         && node.importClause) {
         // Save the path of the import transformed into snake case and remove relative paths.
         const moduleSpecifier = node.moduleSpecifier;
         const pureImport = moduleSpecifier.text
             .replace(/[\/@\-]/g, '_')
             .replace(/^\.+/, '');
         pureImports.push(pureImport);
     }
     ts.forEachChild(node, cb);
 }
Example #26
0
function fixupParentReferences(sourceFile) {
    "use strict";
    var parent = sourceFile;
    function walk(n) {
        n.parent = parent;
        var saveParent = parent;
        parent = n;
        ts.forEachChild(n, walk);
        parent = saveParent;
    }
    ts.forEachChild(sourceFile, walk);
}
function walk(ctx, tc) {
    return ts.forEachChild(ctx.sourceFile, function cb(node) {
        if (tsutils_1.isPropertyAccessExpression(node) && !isSafeUse(node)) {
            var symbol = tc.getSymbolAtLocation(node);
            var declaration = symbol === undefined ? undefined : symbol.valueDeclaration;
            if (declaration !== undefined && isMethod(declaration, ctx.options.ignoreStatic)) {
                ctx.addFailureAtNode(node, Rule.FAILURE_STRING);
            }
        }
        return ts.forEachChild(node, cb);
    });
}
 return ts.forEachChild(ctx.sourceFile, function cb(node) {
     if (tsutils_1.isThrowStatement(node)) {
         var expression = node.expression;
         if (isString(expression)) {
             ctx.addFailureAtNode(node, Rule.FAILURE_STRING, [
                 Lint.Replacement.appendText(expression.getStart(sourceFile), "new Error("),
                 Lint.Replacement.appendText(expression.getEnd(), ")"),
             ]);
         }
     }
     return ts.forEachChild(node, cb);
 });
Example #29
0
 return ts.forEachChild(ctx.sourceFile, function cb(node) {
     if (tsutils_1.isBinaryExpression(node)) {
         if ((node.operatorToken.kind === ts.SyntaxKind.EqualsEqualsToken ||
             node.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsToken) &&
             !(isExpressionAllowed(node.right, ctx.options) || isExpressionAllowed(node.left, ctx.options))) {
             ctx.addFailureAtNode(node.operatorToken, node.operatorToken.kind === ts.SyntaxKind.EqualsEqualsToken
                 ? Rule.EQ_FAILURE_STRING
                 : Rule.NEQ_FAILURE_STRING);
         }
     }
     return ts.forEachChild(node, cb);
 });
 TrailingCommaWalker.prototype.walk = function (sourceFile) {
     var _this = this;
     var cb = function (node) {
         switch (node.kind) {
             case ts.SyntaxKind.ArrayLiteralExpression:
             case ts.SyntaxKind.ArrayBindingPattern:
                 _this.checkList(node.elements, node.end, "arrays");
                 break;
             case ts.SyntaxKind.ObjectBindingPattern:
                 _this.checkList(node.elements, node.end, "objects");
                 break;
             case ts.SyntaxKind.NamedImports:
                 _this.checkList(node.elements, node.end, "imports");
                 break;
             case ts.SyntaxKind.NamedExports:
                 _this.checkList(node.elements, node.end, "exports");
                 break;
             case ts.SyntaxKind.ObjectLiteralExpression:
                 _this.checkList(node.properties, node.end, "objects");
                 break;
             case ts.SyntaxKind.EnumDeclaration:
                 _this.checkList(node.members, node.end, "objects");
                 break;
             case ts.SyntaxKind.NewExpression:
                 if (node.arguments === undefined) {
                     break;
                 }
             // falls through
             case ts.SyntaxKind.CallExpression:
                 _this.checkList(node.arguments, node.end, "functions");
                 break;
             case ts.SyntaxKind.ArrowFunction:
             case ts.SyntaxKind.Constructor:
             case ts.SyntaxKind.FunctionDeclaration:
             case ts.SyntaxKind.FunctionExpression:
             case ts.SyntaxKind.MethodDeclaration:
             case ts.SyntaxKind.SetAccessor:
             case ts.SyntaxKind.MethodSignature:
             case ts.SyntaxKind.ConstructSignature:
             case ts.SyntaxKind.ConstructorType:
             case ts.SyntaxKind.FunctionType:
             case ts.SyntaxKind.CallSignature:
                 _this.checkListWithEndToken(node, node.parameters, ts.SyntaxKind.CloseParenToken, "functions");
                 break;
             case ts.SyntaxKind.TypeLiteral:
                 _this.checkTypeLiteral(node);
                 break;
             default:
         }
         return ts.forEachChild(node, cb);
     };
     return ts.forEachChild(sourceFile, cb);
 };