4 * Copyright 2013 Palantir Technologies, Inc.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 Object.defineProperty(exports, "__esModule", { value: true });
19 var tslib_1 = require("tslib");
20 var tsutils_1 = require("tsutils");
21 var ts = require("typescript");
22 var Lint = require("../index");
23 var OPTION_STATEMENTS = "statements";
24 var OPTION_MEMBERS = "members";
25 var OPTION_ELEMENTS = "elements";
26 var OPTION_PARAMETERS = "parameters";
27 var OPTION_ARGUMENTS = "arguments";
28 var Rule = /** @class */ (function (_super) {
29 tslib_1.__extends(Rule, _super);
31 return _super !== null && _super.apply(this, arguments) || this;
33 Rule.prototype.apply = function (sourceFile) {
34 return this.applyWithWalker(new AlignWalker(sourceFile, this.ruleName, {
35 arguments: this.ruleArguments.indexOf(OPTION_ARGUMENTS) !== -1,
36 elements: this.ruleArguments.indexOf(OPTION_ELEMENTS) !== -1,
37 members: this.ruleArguments.indexOf(OPTION_MEMBERS) !== -1,
38 parameters: this.ruleArguments.indexOf(OPTION_PARAMETERS) !== -1,
39 statements: this.ruleArguments.indexOf(OPTION_STATEMENTS) !== -1,
42 /* tslint:disable:object-literal-sort-keys */
45 description: "Enforces vertical alignment.",
47 rationale: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n Helps maintain a readable, consistent style in your codebase.\n\n Consistent alignment for code statements helps keep code readable and clear.\n Statements misaligned from the standard can be harder to read and understand."], ["\n Helps maintain a readable, consistent style in your codebase.\n\n Consistent alignment for code statements helps keep code readable and clear.\n Statements misaligned from the standard can be harder to read and understand."]))),
48 optionsDescription: Lint.Utils.dedent(templateObject_2 || (templateObject_2 = tslib_1.__makeTemplateObject(["\n Five arguments may be optionally provided:\n\n * `\"", "\"` checks alignment of function parameters.\n * `\"", "\"` checks alignment of function call arguments.\n * `\"", "\"` checks alignment of statements.\n * `\"", "\"` checks alignment of members of classes, interfaces, type literal, object literals and\n object destructuring.\n * `\"", "\"` checks alignment of elements of array literals, array destructuring and tuple types."], ["\n Five arguments may be optionally provided:\n\n * \\`\"", "\"\\` checks alignment of function parameters.\n * \\`\"", "\"\\` checks alignment of function call arguments.\n * \\`\"", "\"\\` checks alignment of statements.\n * \\`\"", "\"\\` checks alignment of members of classes, interfaces, type literal, object literals and\n object destructuring.\n * \\`\"", "\"\\` checks alignment of elements of array literals, array destructuring and tuple types."])), OPTION_PARAMETERS, OPTION_ARGUMENTS, OPTION_STATEMENTS, OPTION_MEMBERS, OPTION_ELEMENTS),
64 optionExamples: [[true, "parameters", "statements"]],
66 typescriptOnly: false,
68 /* tslint:enable:object-literal-sort-keys */
69 Rule.FAILURE_STRING_SUFFIX = " are not aligned";
71 }(Lint.Rules.AbstractRule));
73 var AlignWalker = /** @class */ (function (_super) {
74 tslib_1.__extends(AlignWalker, _super);
75 function AlignWalker() {
76 return _super !== null && _super.apply(this, arguments) || this;
78 AlignWalker.prototype.walk = function (sourceFile) {
80 var cb = function (node) {
81 if (_this.options.statements && tsutils_1.isBlockLike(node)) {
82 _this.checkAlignment(node.statements.filter(function (s) { return s.kind !== ts.SyntaxKind.EmptyStatement; }), OPTION_STATEMENTS);
86 case ts.SyntaxKind.NewExpression:
87 if (node.arguments === undefined) {
91 case ts.SyntaxKind.CallExpression:
92 if (_this.options.arguments) {
93 _this.checkAlignment(node.arguments, OPTION_ARGUMENTS);
96 case ts.SyntaxKind.FunctionDeclaration:
97 case ts.SyntaxKind.FunctionExpression:
98 case ts.SyntaxKind.Constructor:
99 case ts.SyntaxKind.MethodDeclaration:
100 case ts.SyntaxKind.ArrowFunction:
101 case ts.SyntaxKind.CallSignature:
102 case ts.SyntaxKind.ConstructSignature:
103 case ts.SyntaxKind.MethodSignature:
104 case ts.SyntaxKind.FunctionType:
105 case ts.SyntaxKind.ConstructorType:
106 if (_this.options.parameters) {
107 _this.checkAlignment(node.parameters, OPTION_PARAMETERS);
110 case ts.SyntaxKind.ArrayLiteralExpression:
111 case ts.SyntaxKind.ArrayBindingPattern:
112 if (_this.options.elements) {
113 _this.checkAlignment(node.elements, OPTION_ELEMENTS);
116 case ts.SyntaxKind.TupleType:
117 if (_this.options.elements) {
118 _this.checkAlignment(node.elementTypes, OPTION_ELEMENTS);
121 case ts.SyntaxKind.ObjectLiteralExpression:
122 if (_this.options.members) {
123 _this.checkAlignment(node.properties, OPTION_MEMBERS);
126 case ts.SyntaxKind.ObjectBindingPattern:
127 if (_this.options.members) {
128 _this.checkAlignment(node.elements, OPTION_MEMBERS);
131 case ts.SyntaxKind.ClassDeclaration:
132 case ts.SyntaxKind.ClassExpression:
133 if (_this.options.members) {
134 _this.checkAlignment(node.members.filter(function (m) { return m.kind !== ts.SyntaxKind.SemicolonClassElement; }), OPTION_MEMBERS);
137 case ts.SyntaxKind.InterfaceDeclaration:
138 case ts.SyntaxKind.TypeLiteral:
139 if (_this.options.members) {
140 _this.checkAlignment(node.members, OPTION_MEMBERS);
144 return ts.forEachChild(node, cb);
146 return cb(sourceFile);
148 AlignWalker.prototype.checkAlignment = function (nodes, kind) {
149 if (nodes.length <= 1) {
152 var sourceFile = this.sourceFile;
153 var pos = getLineAndCharacterWithoutBom(sourceFile, this.getStart(nodes[0]));
154 var alignToColumn = pos.character;
156 // skip first node in list
157 for (var i = 1; i < nodes.length; ++i) {
159 var start = this.getStart(node);
160 pos = ts.getLineAndCharacterOfPosition(sourceFile, start);
161 if (line !== pos.line && pos.character !== alignToColumn) {
162 var diff = alignToColumn - pos.character;
165 fix = Lint.Replacement.appendText(start, " ".repeat(diff));
167 else if (node.pos <= start + diff &&
168 /^\s+$/.test(sourceFile.text.substring(start + diff, start))) {
169 // only delete text if there is only whitespace
170 fix = Lint.Replacement.deleteText(start + diff, -diff);
172 this.addFailure(start, Math.max(node.end, start), kind + Rule.FAILURE_STRING_SUFFIX, fix);
177 AlignWalker.prototype.getStart = function (node) {
178 return node.kind !== ts.SyntaxKind.OmittedExpression
179 ? node.getStart(this.sourceFile)
180 : // find the comma token following the OmmitedExpression
181 tsutils_1.getNextToken(node, this.sourceFile).getStart(this.sourceFile);
184 }(Lint.AbstractWalker));
185 function getLineAndCharacterWithoutBom(sourceFile, pos) {
186 var result = ts.getLineAndCharacterOfPosition(sourceFile, pos);
187 if (result.line === 0 && sourceFile.text[0] === "\uFEFF") {
188 result.character -= 1;
192 var templateObject_1, templateObject_2;