.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / tslint / lib / rules / preferConstRule.js
1 "use strict";
2 /**
3  * @license
4  * Copyright 2013 Palantir Technologies, Inc.
5  *
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
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18 Object.defineProperty(exports, "__esModule", { value: true });
19 var tslib_1 = require("tslib");
20 var utils = require("tsutils");
21 var ts = require("typescript");
22 var Lint = require("../index");
23 var OPTION_DESTRUCTURING_ALL = "all";
24 var OPTION_DESTRUCTURING_ANY = "any";
25 var Rule = /** @class */ (function (_super) {
26     tslib_1.__extends(Rule, _super);
27     function Rule() {
28         return _super !== null && _super.apply(this, arguments) || this;
29     }
30     /* tslint:enable:object-literal-sort-keys */
31     Rule.FAILURE_STRING_FACTORY = function (identifier, blockScoped) {
32         return "Identifier '" + identifier + "' is never reassigned; use 'const' instead of '" + (blockScoped ? "let" : "var") + "'.";
33     };
34     Rule.prototype.apply = function (sourceFile) {
35         var options = {
36             destructuringAll: this.ruleArguments.length !== 0 &&
37                 this.ruleArguments[0].destructuring ===
38                     OPTION_DESTRUCTURING_ALL,
39         };
40         var preferConstWalker = new PreferConstWalker(sourceFile, this.ruleName, options);
41         return this.applyWithWalker(preferConstWalker);
42     };
43     /* tslint:disable:object-literal-sort-keys */
44     Rule.metadata = {
45         ruleName: "prefer-const",
46         description: "Requires that variable declarations use `const` instead of `let` and `var` if possible.",
47         descriptionDetails: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n            If a variable is only assigned to once when it is declared, it should be declared using 'const'"], ["\n            If a variable is only assigned to once when it is declared, it should be declared using 'const'"]))),
48         hasFix: true,
49         optionsDescription: Lint.Utils.dedent(templateObject_2 || (templateObject_2 = tslib_1.__makeTemplateObject(["\n            An optional object containing the property \"destructuring\" with two possible values:\n\n            * \"", "\" (default) - If any variable in destructuring can be const, this rule warns for those variables.\n            * \"", "\" - Only warns if all variables in destructuring can be const."], ["\n            An optional object containing the property \"destructuring\" with two possible values:\n\n            * \"", "\" (default) - If any variable in destructuring can be const, this rule warns for those variables.\n            * \"", "\" - Only warns if all variables in destructuring can be const."])), OPTION_DESTRUCTURING_ANY, OPTION_DESTRUCTURING_ALL),
50         options: {
51             type: "object",
52             properties: {
53                 destructuring: {
54                     type: "string",
55                     enum: [OPTION_DESTRUCTURING_ALL, OPTION_DESTRUCTURING_ANY],
56                 },
57             },
58         },
59         optionExamples: [true, [true, { destructuring: OPTION_DESTRUCTURING_ALL }]],
60         type: "maintainability",
61         typescriptOnly: false,
62     };
63     return Rule;
64 }(Lint.Rules.AbstractRule));
65 exports.Rule = Rule;
66 var Scope = /** @class */ (function () {
67     function Scope(functionScope) {
68         this.variables = new Map();
69         this.reassigned = new Set();
70         // if no functionScope is provided we are in the process of creating a new function scope, which for consistency links to itself
71         this.functionScope = functionScope === undefined ? this : functionScope;
72     }
73     Scope.prototype.addVariable = function (identifier, declarationInfo, destructuringInfo) {
74         // block scoped variables go to the block scope, function scoped variables to the containing function scope
75         var scope = declarationInfo.isBlockScoped ? this : this.functionScope;
76         scope.variables.set(identifier.text, {
77             declarationInfo: declarationInfo,
78             destructuringInfo: destructuringInfo,
79             identifier: identifier,
80             reassigned: false,
81         });
82     };
83     return Scope;
84 }());
85 var PreferConstWalker = /** @class */ (function (_super) {
86     tslib_1.__extends(PreferConstWalker, _super);
87     function PreferConstWalker() {
88         var _this = _super !== null && _super.apply(this, arguments) || this;
89         _this.scope = new Scope();
90         return _this;
91     }
92     PreferConstWalker.prototype.walk = function (sourceFile) {
93         var _this = this;
94         // don't check anything on declaration files
95         if (sourceFile.isDeclarationFile) {
96             return;
97         }
98         this.scope = new Scope();
99         var cb = function (node) {
100             var savedScope = _this.scope;
101             var boundary = utils.isScopeBoundary(node);
102             if (boundary !== 0 /* None */) {
103                 if (boundary === 1 /* Function */) {
104                     if (node.kind === ts.SyntaxKind.ModuleDeclaration &&
105                         utils.hasModifier(node.modifiers, ts.SyntaxKind.DeclareKeyword)) {
106                         // don't check ambient namespaces
107                         return;
108                     }
109                     _this.scope = new Scope();
110                     if (utils.isFunctionDeclaration(node) ||
111                         utils.isMethodDeclaration(node) ||
112                         utils.isFunctionExpression(node) ||
113                         utils.isArrowFunction(node) ||
114                         utils.isConstructorDeclaration(node)) {
115                         // special handling for function parameters
116                         // each parameter initializer can only reassign preceding parameters of variables of the containing scope
117                         if (node.body !== undefined) {
118                             for (var _i = 0, _a = node.parameters; _i < _a.length; _i++) {
119                                 var param = _a[_i];
120                                 cb(param);
121                                 _this.settle(savedScope);
122                             }
123                             cb(node.body);
124                             _this.onScopeEnd(savedScope);
125                         }
126                         _this.scope = savedScope;
127                         return;
128                     }
129                 }
130                 else {
131                     _this.scope = new Scope(_this.scope.functionScope);
132                     if ((utils.isForInStatement(node) || utils.isForOfStatement(node)) &&
133                         node.initializer.kind !== ts.SyntaxKind.VariableDeclarationList) {
134                         _this.handleExpression(node.initializer);
135                     }
136                 }
137             }
138             if (node.kind === ts.SyntaxKind.VariableDeclarationList) {
139                 _this.handleVariableDeclaration(node);
140             }
141             else if (node.kind === ts.SyntaxKind.CatchClause) {
142                 if (node.variableDeclaration !== undefined) {
143                     _this.handleBindingName(node.variableDeclaration.name, {
144                         canBeConst: false,
145                         isBlockScoped: true,
146                     });
147                 }
148             }
149             else if (node.kind === ts.SyntaxKind.Parameter) {
150                 if (node.parent.kind !== ts.SyntaxKind.IndexSignature) {
151                     _this.handleBindingName(node.name, {
152                         canBeConst: false,
153                         isBlockScoped: true,
154                     });
155                 }
156             }
157             else if (utils.isPostfixUnaryExpression(node) ||
158                 (utils.isPrefixUnaryExpression(node) &&
159                     (node.operator === ts.SyntaxKind.PlusPlusToken ||
160                         node.operator === ts.SyntaxKind.MinusMinusToken))) {
161                 if (utils.isIdentifier(node.operand)) {
162                     _this.scope.reassigned.add(node.operand.text);
163                 }
164             }
165             else if (utils.isBinaryExpression(node) &&
166                 utils.isAssignmentKind(node.operatorToken.kind)) {
167                 _this.handleExpression(node.left);
168             }
169             if (boundary !== 0 /* None */) {
170                 ts.forEachChild(node, cb);
171                 _this.onScopeEnd(savedScope);
172                 _this.scope = savedScope;
173             }
174             else {
175                 return ts.forEachChild(node, cb);
176             }
177         };
178         if (ts.isExternalModule(sourceFile)) {
179             ts.forEachChild(sourceFile, cb);
180             this.onScopeEnd();
181         }
182         else {
183             return ts.forEachChild(sourceFile, cb);
184         }
185     };
186     PreferConstWalker.prototype.handleExpression = function (node) {
187         switch (node.kind) {
188             case ts.SyntaxKind.Identifier:
189                 this.scope.reassigned.add(node.text);
190                 break;
191             case ts.SyntaxKind.ParenthesizedExpression:
192                 this.handleExpression(node.expression);
193                 break;
194             case ts.SyntaxKind.ArrayLiteralExpression:
195                 for (var _i = 0, _a = node.elements; _i < _a.length; _i++) {
196                     var element = _a[_i];
197                     if (element.kind === ts.SyntaxKind.SpreadElement) {
198                         this.handleExpression(element.expression);
199                     }
200                     else {
201                         this.handleExpression(element);
202                     }
203                 }
204                 break;
205             case ts.SyntaxKind.ObjectLiteralExpression:
206                 for (var _b = 0, _c = node.properties; _b < _c.length; _b++) {
207                     var property = _c[_b];
208                     switch (property.kind) {
209                         case ts.SyntaxKind.ShorthandPropertyAssignment:
210                             this.scope.reassigned.add(property.name.text);
211                             break;
212                         case ts.SyntaxKind.SpreadAssignment:
213                             if (property.name !== undefined) {
214                                 this.scope.reassigned.add(property.name.text);
215                             }
216                             else {
217                                 // handle `...(variable)`
218                                 this.handleExpression(property.expression);
219                             }
220                             break;
221                         default:
222                             this.handleExpression(property.initializer);
223                     }
224                 }
225         }
226     };
227     PreferConstWalker.prototype.handleBindingName = function (name, declarationInfo) {
228         var _this = this;
229         if (name.kind === ts.SyntaxKind.Identifier) {
230             this.scope.addVariable(name, declarationInfo);
231         }
232         else {
233             var destructuringInfo_1 = {
234                 reassignedSiblings: false,
235             };
236             utils.forEachDestructuringIdentifier(name, function (declaration) {
237                 return _this.scope.addVariable(declaration.name, declarationInfo, destructuringInfo_1);
238             });
239         }
240     };
241     PreferConstWalker.prototype.handleVariableDeclaration = function (declarationList) {
242         var declarationInfo;
243         var kind = utils.getVariableDeclarationKind(declarationList);
244         if (kind === 2 /* Const */ ||
245             utils.hasModifier(declarationList.parent.modifiers, ts.SyntaxKind.ExportKeyword, ts.SyntaxKind.DeclareKeyword)) {
246             declarationInfo = {
247                 canBeConst: false,
248                 isBlockScoped: kind !== 0 /* Var */,
249             };
250         }
251         else {
252             declarationInfo = {
253                 allInitialized: declarationList.parent.kind === ts.SyntaxKind.ForOfStatement ||
254                     declarationList.parent.kind === ts.SyntaxKind.ForInStatement ||
255                     declarationList.declarations.every(function (declaration) { return declaration.initializer !== undefined; }),
256                 canBeConst: true,
257                 declarationList: declarationList,
258                 isBlockScoped: kind === 1 /* Let */,
259                 isForLoop: declarationList.parent.kind === ts.SyntaxKind.ForStatement ||
260                     declarationList.parent.kind === ts.SyntaxKind.ForOfStatement,
261                 reassignedSiblings: false,
262             };
263         }
264         for (var _i = 0, _a = declarationList.declarations; _i < _a.length; _i++) {
265             var declaration = _a[_i];
266             this.handleBindingName(declaration.name, declarationInfo);
267         }
268     };
269     PreferConstWalker.prototype.settle = function (parent) {
270         var _a = this.scope, variables = _a.variables, reassigned = _a.reassigned;
271         reassigned.forEach(function (name) {
272             var variableInfo = variables.get(name);
273             if (variableInfo !== undefined) {
274                 if (variableInfo.declarationInfo.canBeConst) {
275                     variableInfo.reassigned = true;
276                     variableInfo.declarationInfo.reassignedSiblings = true;
277                     if (variableInfo.destructuringInfo !== undefined) {
278                         variableInfo.destructuringInfo.reassignedSiblings = true;
279                     }
280                 }
281             }
282             else if (parent !== undefined) {
283                 // if the reassigned variable was not declared in this scope we defer to the parent scope
284                 parent.reassigned.add(name);
285             }
286         });
287         reassigned.clear();
288     };
289     PreferConstWalker.prototype.onScopeEnd = function (parent) {
290         var _this = this;
291         this.settle(parent);
292         var appliedFixes = new Set();
293         this.scope.variables.forEach(function (info, name) {
294             if (info.declarationInfo.canBeConst &&
295                 !info.reassigned &&
296                 // don't add failures for reassigned variables in for loop initializer
297                 !(info.declarationInfo.reassignedSiblings && info.declarationInfo.isForLoop) &&
298                 // if {destructuring: "all"} is set, only add a failure if all variables in a destructuring assignment can be const
299                 (!_this.options.destructuringAll ||
300                     info.destructuringInfo === undefined ||
301                     !info.destructuringInfo.reassignedSiblings)) {
302                 var fix = void 0;
303                 // only apply fixes if the VariableDeclarationList has no reassigned variables
304                 // and the variable is block scoped aka `let` and initialized
305                 if (info.declarationInfo.allInitialized &&
306                     !info.declarationInfo.reassignedSiblings &&
307                     info.declarationInfo.isBlockScoped &&
308                     !appliedFixes.has(info.declarationInfo.declarationList)) {
309                     fix = new Lint.Replacement(info.declarationInfo.declarationList.getStart(_this.sourceFile), 3, "const");
310                     // add only one fixer per VariableDeclarationList
311                     appliedFixes.add(info.declarationInfo.declarationList);
312                 }
313                 _this.addFailureAtNode(info.identifier, Rule.FAILURE_STRING_FACTORY(name, info.declarationInfo.isBlockScoped), fix);
314             }
315         });
316     };
317     return PreferConstWalker;
318 }(Lint.AbstractWalker));
319 var templateObject_1, templateObject_2;