tslint-eslint-rules
Version:
Improve your TSLint with the missing ESLint Rules
915 lines (914 loc) • 90.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var ts = require("typescript");
var Lint = require("tslint");
var RULE_NAME = 'ter-indent';
var DEFAULT_VARIABLE_INDENT = 1;
var DEFAULT_PARAMETER_INDENT = null;
var DEFAULT_FUNCTION_BODY_INDENT = 1;
var indentType = 'space';
var indentSize = 4;
var OPTIONS;
function assign(target) {
var sources = [];
for (var _i = 1; _i < arguments.length; _i++) {
sources[_i - 1] = arguments[_i];
}
sources.forEach(function (source) {
if (source !== undefined && source !== null) {
for (var nextKey in source) {
if (source.hasOwnProperty(nextKey)) {
target[nextKey] = source[nextKey];
}
}
}
});
return target;
}
function isKind(node, kind) {
return node.kind === ts.SyntaxKind[kind];
}
function isOneOf(node, kinds) {
return kinds.some(function (kind) { return node.kind === ts.SyntaxKind[kind]; });
}
var Rule = (function (_super) {
tslib_1.__extends(Rule, _super);
function Rule() {
return _super !== null && _super.apply(this, arguments) || this;
}
Rule.prototype.apply = function (sourceFile) {
var walker = new IndentWalker(sourceFile, this.getOptions());
return this.applyWithWalker(walker);
};
Rule.metadata = {
ruleName: RULE_NAME,
hasFix: true,
description: 'enforce consistent indentation',
rationale: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n Using only one of tabs or spaces for indentation leads to more consistent editor behavior,\n cleaner diffs in version control, and easier programmatic manipulation.\n "], ["\n Using only one of tabs or spaces for indentation leads to more consistent editor behavior,\n cleaner diffs in version control, and easier programmatic manipulation.\n "]))),
optionsDescription: Lint.Utils.dedent(templateObject_2 || (templateObject_2 = tslib_1.__makeTemplateObject(["\n The string 'tab' or an integer indicating the number of spaces to use per tab.\n\n An object may be provided to fine tune the indentation rules:\n\n * `\"SwitchCase\"` (default: 0) enforces indentation level for `case` clauses in\n `switch` statements\n * `\"VariableDeclarator\"` (default: 1) enforces indentation level for `var` declarators;\n can also take an object to define separate rules for `var`,\n `let` and `const` declarations.\n * `\"outerIIFEBody\"` (default: 1) enforces indentation level for file-level IIFEs.\n * `\"MemberExpression\"` (off by default) enforces indentation level for multi-line\n property chains (except in variable declarations and assignments)\n * `\"FunctionDeclaration\"` takes an object to define rules for function declarations.\n * `\"parameters\"` (off by default) enforces indentation level for parameters in a\n function declaration. This can either be a number indicating\n indentation level, or the string `\"first\"` indicating that all\n parameters of the declaration must be aligned with the first parameter.\n * `\"body\"` (default: 1) enforces indentation level for the body of a function expression.\n * `\"FunctionExpression\"` takes an object to define rules for function declarations.\n * `\"parameters\"` (off by default) enforces indentation level for parameters in a\n function declaration. This can either be a number indicating\n indentation level, or the string `\"first\"` indicating that all\n parameters of the declaration must be aligned with the first parameter.\n * `\"body\"` (default: 1) enforces indentation level for the body of a function expression.\n * `\"CallExpression\"` takes an object to define rules for function call expressions.\n * `\"arguments\"` (off by default) enforces indentation level for arguments in a call\n expression. This can either be a number indicating indentation level,\n or the string `\"first\"` indicating that all arguments of the\n expression must be aligned with the first argument.\n "], ["\n The string 'tab' or an integer indicating the number of spaces to use per tab.\n\n An object may be provided to fine tune the indentation rules:\n\n * \\`\"SwitchCase\"\\` (default: 0) enforces indentation level for \\`case\\` clauses in\n \\`switch\\` statements\n * \\`\"VariableDeclarator\"\\` (default: 1) enforces indentation level for \\`var\\` declarators;\n can also take an object to define separate rules for \\`var\\`,\n \\`let\\` and \\`const\\` declarations.\n * \\`\"outerIIFEBody\"\\` (default: 1) enforces indentation level for file-level IIFEs.\n * \\`\"MemberExpression\"\\` (off by default) enforces indentation level for multi-line\n property chains (except in variable declarations and assignments)\n * \\`\"FunctionDeclaration\"\\` takes an object to define rules for function declarations.\n * \\`\"parameters\"\\` (off by default) enforces indentation level for parameters in a\n function declaration. This can either be a number indicating\n indentation level, or the string \\`\"first\"\\` indicating that all\n parameters of the declaration must be aligned with the first parameter.\n * \\`\"body\"\\` (default: 1) enforces indentation level for the body of a function expression.\n * \\`\"FunctionExpression\"\\` takes an object to define rules for function declarations.\n * \\`\"parameters\"\\` (off by default) enforces indentation level for parameters in a\n function declaration. This can either be a number indicating\n indentation level, or the string \\`\"first\"\\` indicating that all\n parameters of the declaration must be aligned with the first parameter.\n * \\`\"body\"\\` (default: 1) enforces indentation level for the body of a function expression.\n * \\`\"CallExpression\"\\` takes an object to define rules for function call expressions.\n * \\`\"arguments\"\\` (off by default) enforces indentation level for arguments in a call\n expression. This can either be a number indicating indentation level,\n or the string \\`\"first\"\\` indicating that all arguments of the\n expression must be aligned with the first argument.\n "]))),
options: {
type: 'array',
items: [{
type: 'number',
minimum: '0'
}, {
type: 'string',
enum: ['tab']
}, {
type: 'object',
properties: {
SwitchCase: {
type: 'number',
minimum: 0
},
VariableDeclarator: {
type: 'object',
properties: {
var: {
type: 'number',
minimum: 0
},
let: {
type: 'number',
minimum: 0
},
const: {
type: 'number',
minimum: 0
}
}
},
outerIIFEBody: {
type: 'number'
},
FunctionDeclaration: {
type: 'object',
properties: {
parameters: {
type: 'number',
minimum: 0
},
body: {
type: 'number',
minimum: 0
}
}
},
FunctionExpression: {
type: 'object',
properties: {
parameters: {
type: 'number',
minimum: 0
},
body: {
type: 'number',
minimum: 0
}
}
},
MemberExpression: {
type: 'number'
},
CallExpression: {
type: 'object',
properties: {
arguments: {
type: 'number',
minimum: 0
}
}
}
},
additionalProperties: false
}],
minLength: 1,
maxLength: 2
},
optionExamples: [
Lint.Utils.dedent(templateObject_3 || (templateObject_3 = tslib_1.__makeTemplateObject(["\n \"", "\": [true, \"tab\"]\n "], ["\n \"", "\": [true, \"tab\"]\n "])), RULE_NAME),
Lint.Utils.dedent(templateObject_4 || (templateObject_4 = tslib_1.__makeTemplateObject(["\n \"", "\": [true, 2]\n "], ["\n \"", "\": [true, 2]\n "])), RULE_NAME),
Lint.Utils.dedent(templateObject_5 || (templateObject_5 = tslib_1.__makeTemplateObject(["\n \"", "\": [\n true,\n 2,\n {\n \"FunctionExpression\": {\n \"parameters\": 1,\n \"body\": 1\n }\n }\n ]\n "], ["\n \"", "\": [\n true,\n 2,\n {\n \"FunctionExpression\": {\n \"parameters\": 1,\n \"body\": 1\n }\n }\n ]\n "])), RULE_NAME)
],
typescriptOnly: false,
type: 'maintainability'
};
return Rule;
}(Lint.Rules.AbstractRule));
exports.Rule = Rule;
var IndentWalker = (function (_super) {
tslib_1.__extends(IndentWalker, _super);
function IndentWalker(sourceFile, options) {
var _this = _super.call(this, sourceFile, options) || this;
_this.caseIndentStore = {};
_this.varIndentStore = {};
OPTIONS = {
SwitchCase: 0,
VariableDeclarator: {
var: DEFAULT_VARIABLE_INDENT,
let: DEFAULT_VARIABLE_INDENT,
const: DEFAULT_VARIABLE_INDENT
},
outerIIFEBody: null,
FunctionDeclaration: {
parameters: DEFAULT_PARAMETER_INDENT,
body: DEFAULT_FUNCTION_BODY_INDENT
},
FunctionExpression: {
parameters: DEFAULT_PARAMETER_INDENT,
body: DEFAULT_FUNCTION_BODY_INDENT
},
CallExpression: {
arguments: DEFAULT_PARAMETER_INDENT
}
};
var firstParam = _this.getOptions()[0];
if (firstParam === 'tab') {
indentSize = 1;
indentType = 'tab';
}
else {
indentSize = firstParam || 4;
indentType = 'space';
}
var userOptions = _this.getOptions()[1];
if (userOptions) {
OPTIONS.SwitchCase = userOptions.SwitchCase || 0;
if (typeof userOptions.VariableDeclarator === 'number') {
OPTIONS.VariableDeclarator = {
var: userOptions.VariableDeclarator,
let: userOptions.VariableDeclarator,
const: userOptions.VariableDeclarator
};
}
else if (typeof userOptions.VariableDeclarator === 'object') {
assign(OPTIONS.VariableDeclarator, userOptions.VariableDeclarator);
}
if (typeof userOptions.outerIIFEBody === 'number') {
OPTIONS.outerIIFEBody = userOptions.outerIIFEBody;
}
if (typeof userOptions.MemberExpression === 'number') {
OPTIONS.MemberExpression = userOptions.MemberExpression;
}
if (typeof userOptions.FunctionDeclaration === 'object') {
assign(OPTIONS.FunctionDeclaration, userOptions.FunctionDeclaration);
}
if (typeof userOptions.FunctionExpression === 'object') {
assign(OPTIONS.FunctionExpression, userOptions.FunctionExpression);
}
if (typeof userOptions.CallExpression === 'object') {
assign(OPTIONS.CallExpression, userOptions.CallExpression);
}
}
_this.srcFile = sourceFile;
_this.srcText = sourceFile.getFullText();
return _this;
}
IndentWalker.prototype.getSourceSubstr = function (start, end) {
return this.srcText.substr(start, end - start);
};
IndentWalker.prototype.getLineAndCharacter = function (node, byEndLocation) {
if (byEndLocation === void 0) { byEndLocation = false; }
var index = byEndLocation ? node.getEnd() : node.getStart();
return this.srcFile.getLineAndCharacterOfPosition(index);
};
IndentWalker.prototype.getLine = function (node, byEndLocation) {
if (byEndLocation === void 0) { byEndLocation = false; }
return this.getLineAndCharacter(node, byEndLocation).line;
};
IndentWalker.prototype.createErrorMessage = function (expectedAmount, actualSpaces, actualTabs) {
var expectedStatement = expectedAmount + " " + indentType + (expectedAmount === 1 ? '' : 's');
var foundSpacesWord = "space" + (actualSpaces === 1 ? '' : 's');
var foundTabsWord = "tab" + (actualTabs === 1 ? '' : 's');
var foundStatement;
if (actualSpaces > 0 && actualTabs > 0) {
foundStatement = actualSpaces + " " + foundSpacesWord + " and " + actualTabs + " " + foundTabsWord;
}
else if (actualSpaces > 0) {
foundStatement = indentType === 'space' ? actualSpaces : actualSpaces + " " + foundSpacesWord;
}
else if (actualTabs > 0) {
foundStatement = indentType === 'tab' ? actualTabs : actualTabs + " " + foundTabsWord;
}
else {
foundStatement = '0';
}
return "Expected indentation of " + expectedStatement + " but found " + foundStatement + ".";
};
IndentWalker.prototype.report = function (node, needed, gottenSpaces, gottenTabs, loc) {
if (gottenSpaces && gottenTabs) {
return;
}
var msg = this.createErrorMessage(needed, gottenSpaces, gottenTabs);
var width = gottenSpaces + gottenTabs;
var start = (loc !== undefined ? loc : node.getStart()) - width;
var desiredIndent = (indentType === 'space' ? ' ' : '\t').repeat(needed);
var fix = this.createReplacement(start, width, desiredIndent);
this.addFailure(this.createFailure(start, width, msg, fix));
};
IndentWalker.prototype.isNodeFirstInLine = function (node, byEndLocation) {
if (byEndLocation === void 0) { byEndLocation = false; }
var token = byEndLocation ? node.getLastToken() : node.getFirstToken();
var pos = token.getStart() - 1;
while ([' ', '\t'].indexOf(this.srcText.charAt(pos)) !== -1) {
pos -= 1;
}
return this.srcText.charAt(pos) === '\n' || this._firstInLineCommentHelper(node);
};
IndentWalker.prototype._firstInLineCommentHelper = function (node) {
var pos;
var firstInLine = false;
var comments = ts.getLeadingCommentRanges(node.getFullText(), 0);
if (comments && comments.length) {
var offset = node.getFullStart();
var lastComment = comments[comments.length - 1];
var comment = this.getSourceSubstr(lastComment.pos + offset, lastComment.end + offset);
if (comment.indexOf('\n') !== -1) {
firstInLine = true;
}
else {
pos = lastComment.pos + offset;
while (pos > 0 && this.srcText.charAt(pos) !== '\n') {
pos -= 1;
}
var content = this.getSourceSubstr(pos + 1, lastComment.pos + offset);
if (content.trim() === '') {
firstInLine = true;
}
}
}
return firstInLine;
};
IndentWalker.prototype.getNodeIndent = function (node) {
if (node === this.getSourceFile()) {
return { contentStart: 0, firstInLine: true, space: 0, tab: 0, goodChar: 0, badChar: 0 };
}
if (node.kind === ts.SyntaxKind.SyntaxList && node.parent) {
return this.getNodeIndent(node.parent);
}
var endIndex = node.getStart(this.srcFile);
var pos = endIndex - 1;
while (pos > 0 && this.srcText.charAt(pos) !== '\n') {
pos -= 1;
}
var str = this.getSourceSubstr(pos + 1, endIndex);
var whiteSpace = (str.match(/^\s+/) || [''])[0];
var indentChars = whiteSpace.split('');
var spaces = indentChars.filter(function (char) { return char === ' '; }).length;
var tabs = indentChars.filter(function (char) { return char === '\t'; }).length;
return {
contentStart: pos + spaces + tabs + 1,
firstInLine: spaces + tabs === str.length || this._firstInLineCommentHelper(node),
space: spaces,
tab: tabs,
goodChar: indentType === 'space' ? spaces : tabs,
badChar: indentType === 'space' ? tabs : spaces
};
};
IndentWalker.prototype.checkNodeIndent = function (node, neededIndent) {
var actualIndent = this.getNodeIndent(node);
if (!isKind(node, 'ArrayLiteralExpression') &&
!isKind(node, 'ObjectLiteralExpression') &&
(actualIndent.goodChar !== neededIndent || actualIndent.badChar !== 0) &&
actualIndent.firstInLine) {
this.report(node, neededIndent, actualIndent.space, actualIndent.tab, actualIndent.contentStart);
}
if (isKind(node, 'IfStatement')) {
var elseStatement = node.elseStatement;
if (elseStatement) {
var elseKeyword = node.getChildren().filter(function (ch) { return isKind(ch, 'ElseKeyword'); }).shift();
this.checkNodeIndent(elseKeyword, neededIndent);
if (!this.isNodeFirstInLine(elseStatement)) {
this.checkNodeIndent(elseStatement, neededIndent);
}
}
}
else if (isKind(node, 'TryStatement')) {
var handler = node.catchClause;
if (handler) {
var catchKeyword = handler.getChildren().filter(function (ch) { return isKind(ch, 'CatchKeyword'); }).shift();
this.checkNodeIndent(catchKeyword, neededIndent);
if (!this.isNodeFirstInLine(handler)) {
this.checkNodeIndent(handler, neededIndent);
}
}
var finalizer = node.finallyBlock;
if (finalizer) {
var finallyKeyword = node.getChildren().filter(function (ch) { return isKind(ch, 'FinallyKeyword'); }).shift();
this.checkNodeIndent(finallyKeyword, neededIndent);
}
}
else if (isKind(node, 'DoStatement')) {
var whileKeyword = node.getChildren().filter(function (ch) { return isKind(ch, 'WhileKeyword'); }).shift();
this.checkNodeIndent(whileKeyword, neededIndent);
}
};
IndentWalker.prototype.isSingleLineNode = function (node) {
var text = node.kind === ts.SyntaxKind.SyntaxList ? node.getFullText() : node.getText();
return text.indexOf('\n') === -1;
};
IndentWalker.prototype.blockIndentationCheck = function (node) {
if (this.isSingleLineNode(node)) {
return;
}
var functionLike = [
'FunctionExpression',
'FunctionDeclaration',
'MethodDeclaration',
'Constructor',
'ArrowFunction'
];
if (node.parent && isOneOf(node.parent, functionLike)) {
this.checkIndentInFunctionBlock(node);
return;
}
var indent;
var nodesToCheck = [];
var statementsWithProperties = [
'IfStatement',
'WhileStatement',
'ForStatement',
'ForInStatement',
'ForOfStatement',
'DoStatement',
'ClassDeclaration',
'ClassExpression',
'InterfaceDeclaration',
'TypeLiteral',
'TryStatement',
'SourceFile'
];
if (node.parent && isOneOf(node.parent, statementsWithProperties) && this.isNodeBodyBlock(node)) {
indent = this.getNodeIndent(node.parent).goodChar;
}
else if (node.parent && isKind(node.parent, 'CatchClause')) {
indent = this.getNodeIndent(node.parent.parent).goodChar;
}
else {
indent = this.getNodeIndent(node).goodChar;
}
if (isKind(node, 'IfStatement') && !isKind(node.thenStatement, 'Block')) {
nodesToCheck = [node.thenStatement];
}
else {
if (isKind(node, 'Block')) {
nodesToCheck = node.getChildren()[1].getChildren();
}
else if (node.parent &&
isOneOf(node.parent, [
'ClassDeclaration',
'ClassExpression',
'InterfaceDeclaration',
'TypeLiteral'
])) {
nodesToCheck = node.getChildren();
}
else {
nodesToCheck = [node.statement];
}
}
this.checkNodeIndent(node, indent);
if (nodesToCheck.length > 0) {
this.checkNodesIndent(nodesToCheck, indent + indentSize);
}
if (isKind(node, 'Block')) {
this.checkLastNodeLineIndent(node, indent);
}
else if (node.parent && this.isNodeBodyBlock(node)) {
this.checkLastNodeLineIndent(node.parent, indent);
}
};
IndentWalker.prototype.isAssignment = function (node) {
if (!isKind(node, 'BinaryExpression')) {
return false;
}
return node.operatorToken.getText() === '=';
};
IndentWalker.prototype.isNodeBodyBlock = function (node) {
var hasBlock = [
'ClassDeclaration',
'ClassExpression',
'InterfaceDeclaration',
'TypeLiteral'
];
return isKind(node, 'Block') || (isKind(node, 'SyntaxList') &&
isOneOf(node.parent, hasBlock));
};
IndentWalker.prototype.checkFirstNodeLineIndent = function (node, firstLineIndent) {
var startIndent = this.getNodeIndent(node);
var firstInLine = startIndent.firstInLine;
if (firstInLine && (startIndent.goodChar !== firstLineIndent || startIndent.badChar !== 0)) {
this.report(node, firstLineIndent, startIndent.space, startIndent.tab, startIndent.contentStart);
}
};
IndentWalker.prototype.checkLastNodeLineIndent = function (node, lastLineIndent) {
var lastToken = node.getLastToken();
var endIndent = this.getNodeIndent(lastToken);
var firstInLine = endIndent.firstInLine;
if (firstInLine && (endIndent.goodChar !== lastLineIndent || endIndent.badChar !== 0)) {
this.report(lastToken, lastLineIndent, endIndent.space, endIndent.tab);
}
};
IndentWalker.prototype.isOuterIIFE = function (node) {
if (!node.parent)
return false;
var parent = node.parent;
var expressionIsNode = parent.expression !== node;
if (isKind(parent, 'ParenthesizedExpression')) {
parent = parent.parent;
}
if (!isKind(parent, 'CallExpression') || expressionIsNode) {
return false;
}
var stmt = parent;
var condition;
do {
stmt = stmt.parent;
condition = (isKind(stmt, 'PrefixUnaryExpression') && (stmt.operator === ts.SyntaxKind.ExclamationToken ||
stmt.operator === ts.SyntaxKind.TildeToken ||
stmt.operator === ts.SyntaxKind.PlusToken ||
stmt.operator === ts.SyntaxKind.MinusToken) ||
isKind(stmt, 'BinaryExpression') ||
isKind(stmt, 'SyntaxList') ||
isKind(stmt, 'VariableDeclaration') ||
isKind(stmt, 'VariableDeclarationList') ||
isKind(stmt, 'ParenthesizedExpression'));
} while (condition);
return ((isKind(stmt, 'ExpressionStatement') ||
isKind(stmt, 'VariableStatement')) &&
!!stmt.parent && isKind(stmt.parent, 'SourceFile'));
};
IndentWalker.prototype.isArgBeforeCalleeNodeMultiline = function (node) {
var parent = node.parent;
if (parent && parent['arguments'].length >= 2 && parent['arguments'][1] === node) {
var firstArg = parent['arguments'][0];
return this.getLine(firstArg, true) > this.getLine(firstArg);
}
return false;
};
IndentWalker.prototype.checkIndentInFunctionBlock = function (node) {
var calleeNode = node.parent;
var indent = this.getNodeIndent(calleeNode).goodChar;
if (calleeNode.parent && calleeNode.parent.kind === ts.SyntaxKind.CallExpression) {
var calleeParent = calleeNode.parent;
if (calleeNode.kind !== ts.SyntaxKind.FunctionExpression && calleeNode.kind !== ts.SyntaxKind.ArrowFunction) {
if (calleeParent && this.getLine(calleeParent) < this.getLine(node)) {
indent = this.getNodeIndent(calleeParent).goodChar;
}
}
else {
var callee = calleeParent.expression;
if (this.isArgBeforeCalleeNodeMultiline(calleeNode) &&
this.getLine(callee) === this.getLine(callee, true) &&
!this.isNodeFirstInLine(calleeNode)) {
indent = this.getNodeIndent(calleeParent).goodChar;
}
}
}
var functionOffset = indentSize;
if (OPTIONS.outerIIFEBody !== null && this.isOuterIIFE(calleeNode)) {
functionOffset = OPTIONS.outerIIFEBody * indentSize;
}
else if (calleeNode.kind === ts.SyntaxKind.FunctionExpression) {
functionOffset = OPTIONS.FunctionExpression.body * indentSize;
}
else if (calleeNode.kind === ts.SyntaxKind.FunctionDeclaration) {
functionOffset = OPTIONS.FunctionDeclaration.body * indentSize;
}
else if (isOneOf(calleeNode, ['MethodDeclaration', 'Constructor'])) {
functionOffset = OPTIONS.FunctionExpression.body * indentSize;
}
indent += functionOffset;
var parentVarNode = this.getVariableDeclaratorNode(node);
if (parentVarNode && this.isNodeInVarOnTop(node, parentVarNode) && parentVarNode.parent) {
var varKind = parentVarNode.parent.getFirstToken().getText();
indent += indentSize * OPTIONS.VariableDeclarator[varKind];
}
this.checkFirstNodeLineIndent(node, indent - functionOffset);
if (node.statements.length) {
this.checkNodesIndent(node.statements, indent);
}
this.checkLastNodeLineIndent(node, indent - functionOffset);
};
IndentWalker.prototype.checkNodesIndent = function (nodes, indent) {
var _this = this;
nodes.forEach(function (node) { return _this.checkNodeIndent(node, indent); });
};
IndentWalker.prototype.expectedCaseIndent = function (node, switchIndent) {
var switchNode = (node.kind === ts.SyntaxKind.SwitchStatement) ? node : node.parent;
var line = this.getLine(switchNode);
var caseIndent;
if (this.caseIndentStore[line]) {
return this.caseIndentStore[line];
}
else {
if (typeof switchIndent === 'undefined') {
switchIndent = this.getNodeIndent(switchNode).goodChar;
}
caseIndent = switchIndent + (indentSize * OPTIONS.SwitchCase);
this.caseIndentStore[line] = caseIndent;
return caseIndent;
}
};
IndentWalker.prototype.expectedVarIndent = function (node, varIndent) {
var varNode = node.parent;
var line = this.getLine(varNode);
var indent;
if (this.varIndentStore[line]) {
return this.varIndentStore[line];
}
else {
if (typeof varIndent === 'undefined') {
varIndent = this.getNodeIndent(varNode).goodChar;
}
var varKind = varNode.getFirstToken().getText();
indent = varIndent + (indentSize * OPTIONS.VariableDeclarator[varKind]);
this.varIndentStore[line] = indent;
return indent;
}
};
IndentWalker.prototype.getParentNodeByType = function (node, kind, stopAtList) {
if (stopAtList === void 0) { stopAtList = [ts.SyntaxKind.SourceFile]; }
var parent = node.parent;
while (parent
&& parent.kind !== kind
&& stopAtList.indexOf(parent.kind) === -1
&& parent.kind !== ts.SyntaxKind.SourceFile) {
parent = parent.parent;
}
return parent && parent.kind === kind ? parent : null;
};
IndentWalker.prototype.getVariableDeclaratorNode = function (node) {
return this.getParentNodeByType(node, ts.SyntaxKind.VariableDeclaration);
};
IndentWalker.prototype.getBinaryExpressionNode = function (node) {
return this.getParentNodeByType(node, ts.SyntaxKind.BinaryExpression);
};
IndentWalker.prototype.checkIndentInArrayOrObjectBlock = function (node) {
if (this.isSingleLineNode(node)) {
return;
}
var elements = isKind(node, 'ObjectLiteralExpression') ? node['properties'] : node['elements'];
elements = elements.filter(function (elem) { return elem.getText() !== ''; });
var nodeLine = this.getLine(node);
var nodeEndLine = this.getLine(node, true);
var nodeIndent;
var elementsIndent;
var varKind;
var parentVarNode = this.getVariableDeclaratorNode(node);
if (this.isNodeFirstInLine(node) && node.parent) {
var parent = node.parent;
nodeIndent = this.getNodeIndent(parent).goodChar;
if (parentVarNode && this.getLine(parentVarNode) !== nodeLine) {
if (!isKind(parent, 'VariableDeclaration') || parentVarNode === parentVarNode.parent.declarations[0]) {
var parentVarLine = this.getLine(parentVarNode);
var parentLine = this.getLine(parent);
if (isKind(parent, 'VariableDeclaration') && parentVarLine === parentLine && parentVarNode.parent) {
varKind = parentVarNode.parent.getFirstToken().getText();
nodeIndent = nodeIndent + (indentSize * OPTIONS.VariableDeclarator[varKind]);
}
else if (isOneOf(parent, [
'ObjectLiteralExpression',
'ArrayLiteralExpression',
'CallExpression',
'ArrowFunction',
'NewExpression',
'BinaryExpression'
])) {
nodeIndent = nodeIndent + indentSize;
}
}
}
else if (!parentVarNode &&
!this.isFirstArrayElementOnSameLine(parent) &&
parent.kind !== ts.SyntaxKind.PropertyAccessExpression &&
parent.kind !== ts.SyntaxKind.ExpressionStatement &&
parent.kind !== ts.SyntaxKind.PropertyAssignment &&
!(this.isAssignment(parent))) {
nodeIndent = nodeIndent + indentSize;
}
elementsIndent = nodeIndent + indentSize;
this.checkFirstNodeLineIndent(node, nodeIndent);
}
else {
nodeIndent = this.getNodeIndent(node).goodChar;
elementsIndent = nodeIndent + indentSize;
}
if (parentVarNode && this.isNodeInVarOnTop(node, parentVarNode) && parentVarNode.parent) {
varKind = parentVarNode.parent.getFirstToken().getText();
elementsIndent += indentSize * OPTIONS.VariableDeclarator[varKind];
}
this.checkNodesIndent(elements, elementsIndent);
if (elements.length > 0) {
var lastLine = this.getLine(elements[elements.length - 1], true);
if (lastLine === nodeEndLine) {
return;
}
}
this.checkLastNodeLineIndent(node, elementsIndent - indentSize);
};
IndentWalker.prototype.isFirstArrayElementOnSameLine = function (node) {
if (isKind(node, 'ArrayLiteralExpression')) {
var ele = node.elements[0];
if (ele) {
return isKind(ele, 'ObjectLiteralExpression') && this.getLine(ele) === this.getLine(node);
}
}
return false;
};
IndentWalker.prototype.isNodeInVarOnTop = function (node, varNode) {
var nodeLine = this.getLine(node);
var parentLine = this.getLine(varNode.parent);
return varNode &&
parentLine === nodeLine &&
varNode.parent.declarations.length > 1;
};
IndentWalker.prototype.blockLessNodes = function (node) {
if (!isKind(node.statement, 'Block')) {
this.blockIndentationCheck(node);
}
};
IndentWalker.prototype.checkIndentInVariableDeclarations = function (node) {
var indent = this.expectedVarIndent(node);
this.checkNodeIndent(node, indent);
};
IndentWalker.prototype.visitCase = function (node) {
if (this.isSingleLineNode(node)) {
return;
}
var caseIndent = this.expectedCaseIndent(node);
this.checkNodesIndent(node.statements, caseIndent + indentSize);
};
IndentWalker.prototype.checkLastReturnStatementLineIndent = function (node, firstLineIndent) {
if (!node.expression) {
return;
}
var lastToken = node.expression.getLastToken();
var endIndex = lastToken.getStart();
var pos = endIndex - 1;
while (pos > 0 && this.srcText.charAt(pos) !== '\n') {
pos -= 1;
}
var textBeforeClosingParenthesis = this.getSourceSubstr(pos + 1, endIndex);
if (textBeforeClosingParenthesis.trim()) {
return;
}
var endIndent = this.getNodeIndent(lastToken);
if (endIndent.goodChar !== firstLineIndent) {
this.report(node, firstLineIndent, endIndent.space, endIndent.tab, lastToken.getStart());
}
};
IndentWalker.prototype.visitClassDeclaration = function (node) {
var len = node.getChildCount();
this.blockIndentationCheck(node.getChildAt(len - 2));
_super.prototype.visitClassDeclaration.call(this, node);
};
IndentWalker.prototype.visitClassExpression = function (node) {
var len = node.getChildCount();
this.blockIndentationCheck(node.getChildAt(len - 2));
_super.prototype.visitClassExpression.call(this, node);
};
IndentWalker.prototype.visitInterfaceDeclaration = function (node) {
var len = node.getChildCount();
this.blockIndentationCheck(node.getChildAt(len - 2));
_super.prototype.visitInterfaceDeclaration.call(this, node);
};
IndentWalker.prototype.visitTypeLiteral = function (node) {
var len = node.getChildCount();
this.blockIndentationCheck(node.getChildAt(len - 2));
_super.prototype.visitTypeLiteral.call(this, node);
};
IndentWalker.prototype.visitBlock = function (node) {
this.blockIndentationCheck(node);
_super.prototype.visitBlock.call(this, node);
};
IndentWalker.prototype.visitIfStatement = function (node) {
var thenLine = this.getLine(node.thenStatement);
var line = this.getLine(node);
if (!isKind(node.thenStatement, 'Block') && thenLine > line) {
this.blockIndentationCheck(node);
}
_super.prototype.visitIfStatement.call(this, node);
};
IndentWalker.prototype.visitObjectLiteralExpression = function (node) {
this.checkIndentInArrayOrObjectBlock(node);
_super.prototype.visitObjectLiteralExpression.call(this, node);
};
IndentWalker.prototype.visitArrayLiteralExpression = function (node) {
this.checkIndentInArrayOrObjectBlock(node);
_super.prototype.visitArrayLiteralExpression.call(this, node);
};
IndentWalker.prototype.visitSwitchStatement = function (node) {
var switchIndent = this.getNodeIndent(node).goodChar;
var caseIndent = this.expectedCaseIndent(node, switchIndent);
this.checkNodesIndent(node.caseBlock.clauses, caseIndent);
this.checkLastNodeLineIndent(node, switchIndent);
_super.prototype.visitSwitchStatement.call(this, node);
};
IndentWalker.prototype.visitCaseClause = function (node) {
this.visitCase(node);
_super.prototype.visitCaseClause.call(this, node);
};
IndentWalker.prototype.visitDefaultClause = function (node) {
this.visitCase(node);
_super.prototype.visitDefaultClause.call(this, node);
};
IndentWalker.prototype.visitWhileStatement = function (node) {
this.blockLessNodes(node);
_super.prototype.visitWhileStatement.call(this, node);
};
IndentWalker.prototype.visitForStatement = function (node) {
this.blockLessNodes(node);
_super.prototype.visitForStatement.call(this, node);
};
IndentWalker.prototype.visitForInStatement = function (node) {
this.blockLessNodes(node);
_super.prototype.visitForInStatement.call(this, node);
};
IndentWalker.prototype.visitDoStatement = function (node) {
this.blockLessNodes(node);
_super.prototype.visitDoStatement.call(this, node);
};
IndentWalker.prototype.visitVariableDeclaration = function (node) {
this.checkIndentInVariableDeclarations(node);
_super.prototype.visitVariableDeclaration.call(this, node);
};
IndentWalker.prototype.visitVariableStatement = function (node) {
_super.prototype.visitVariableStatement.call(this, node);
var list = node.getChildAt(0).getChildAt(1);
if (!list) {
return;
}
var len = list.getChildCount();
if (len === 0) {
return;
}
var lastElement = list.getChildAt(len - 1);
var lastToken = node.getLastToken();
var lastTokenLine = this.getLine(lastToken, true);
var lastElementLine = this.getLine(lastElement, true);
if (lastTokenLine <= lastElementLine) {
return;
}
var tokenBeforeLastElement = list.getChildAt(len - 2);
if (tokenBeforeLastElement && isKind(tokenBeforeLastElement, 'CommaToken')) {
this.checkLastNodeLineIndent(node, this.getNodeIndent(tokenBeforeLastElement).goodChar);
}
else {
var nodeIndent = this.getNodeIndent(node).goodChar;
var varKind = node.getFirstToken().getText();
var declaratorIndent = typeof OPTIONS.VariableDeclarator[varKind] === 'number' ? OPTIONS.VariableDeclarator[varKind] : DEFAULT_VARIABLE_INDENT;
var elementsIndent = nodeIndent + indentSize * declaratorIndent;
this.checkLastNodeLineIndent(node, elementsIndent - indentSize);
}
};
IndentWalker.prototype.visitFunctionDeclaration = function (node) {
if (this.isSingleLineNode(node)) {
return;
}
if (OPTIONS.FunctionDeclaration.parameters === 'first' && node.parameters.length) {
var indent = this.getLineAndCharacter(node.parameters[0]).character;
this.checkNodesIndent(node.parameters.slice(1), indent);
}
else if (OPTIONS.FunctionDeclaration.parameters !== null) {
var nodeIndent = this.getNodeIndent(node).goodChar;
this.checkNodesIndent(node.parameters, nodeIndent + indentSize * OPTIONS.FunctionDeclaration.parameters);
var closingParen = node.getChildAt(node.getChildCount() - 2);
this.checkNodeIndent(closingParen, nodeIndent);
}
_super.prototype.visitFunctionDeclaration.call(this, node);
};
IndentWalker.prototype.checkFunctionMethodExpression = function (node) {
if (OPTIONS.FunctionExpression.parameters === 'first' && node.parameters.length) {
var indent = this.getLineAndCharacter(node.parameters[0]).character;
this.checkNodesIndent(node.parameters.slice(1), indent);
}
else if (OPTIONS.FunctionExpression.parameters !== null) {
var nodeIndent = this.getNodeIndent(node).goodChar;
this.checkNodesIndent(node.parameters, nodeIndent + indentSize * OPTIONS.FunctionExpression.parameters);
var closingParen = node.getChildAt(node.getChildCount() - 2);
this.checkNodeIndent(closingParen, nodeIndent);
}
};
IndentWalker.prototype.visitFunctionExpression = function (node) {
if (this.isSingleLineNode(node)) {
return;
}
this.checkFunctionMethodExpression(node);
_super.prototype.visitFunctionExpression.call(this, node);
};
IndentWalker.prototype.visitMethodDeclaration = function (node) {
if (this.isSingleLineNode(node)) {
return;
}
this.checkFunctionMethodExpression(node);
_super.prototype.visitMethodDeclaration.call(this, node);
};
IndentWalker.prototype.visitConstructorDeclaration = function (node) {
if (this.isSingleLineNode(node)) {
return;
}
this.checkFunctionMethodExpression(node);
_super.prototype.visitConstructorDeclaration.call(this, node);
};
IndentWalker.prototype.visitCallExpression = function (node) {
if (this.isSingleLineNode(node)) {
return;
}
if (OPTIONS.CallExpression.arguments === 'first' && node.arguments.length) {
var indent = this.getLineAndCharacter(node.arguments[0]).character;
this.checkNodesIndent(node.arguments.slice(1), indent);
}
else if (OPTIONS.CallExpression.arguments !== null) {
var openParen = node.getChildAt(node.getChildCount(this.srcFile) - 3, this.srcFile);
var openParenIndent = this.getNodeIndent(openParen);
this.checkNodesIndent(node.arguments, openParenIndent.goodChar + indentSize * OPTIONS.CallExpression.arguments);
}
_super.prototype.visitCallExpression.call(this, node);
};
IndentWalker.prototype.visitPropertyAccessExpression = function (node) {
if (this.isSingleLineNode(node)) {
return;
}
var varDec = ts.SyntaxKind.VariableDeclaration;
var funcKind = [ts.SyntaxKind.FunctionExpression, ts.SyntaxKind.ArrowFunction];
if (this.getParentNodeByType(node, varDec, funcKind)) {
return;
}
var binExp = ts.SyntaxKind.BinaryExpression;
var funcExp = ts.SyntaxKind.FunctionExpression;
var binaryNode = this.getParentNodeByType(node, binExp, [funcExp]);
if (binaryNode && this.isAssignment(binaryNode)) {
return;
}
_super.prototype.visitPropertyAccessExpression.call(this, node);
if (typeof OPTIONS.MemberExpression === 'undefined') {
return;
}
var propertyIndent = this.getNodeIndent(node).goodChar + indentSize * OPTIONS.MemberExpression;
var dotToken = node.getChildAt(1);
var checkNodes = [node.name, dotToken];
this.checkNodesIndent(checkNodes, propertyIndent);
};
IndentWalker.prototype.visitReturnStatement = function (node) {
if (this.isSingleLineNode(node) || !node.expression) {
return;
}
var firstLineIndent = this.getNodeIndent(node).goodChar;
if (isKind(node.expression, 'ParenthesizedExpression')) {
this.checkLastReturnStatementLineIndent(node, firstLineIndent);
}
else {
this.checkNodeIndent(node, firstLineIndent);
}
_super.prototype.visitReturnStatement.call(this, node);
};
IndentWalker.prototype.visitSourceFile = function (node) {
this.checkNodesIndent(node.statements, 0);
_super.prototype.visitSourceFile.call(this, node);
};
return IndentWalker;
}(Lint.RuleWalker));
var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5;
//# sourceMappingURL=data:application/json;charset=utf8;base64,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