.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / tslint / lib / rules / noShadowedVariableRule.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 tsutils_1 = require("tsutils");
21 var ts = require("typescript");
22 var Lint = require("../index");
23 var Rule = /** @class */ (function (_super) {
24     tslib_1.__extends(Rule, _super);
25     function Rule() {
26         return _super !== null && _super.apply(this, arguments) || this;
27     }
28     /* tslint:enable:object-literal-sort-keys */
29     Rule.FAILURE_STRING_FACTORY = function (name) {
30         return "Shadowed name: '" + name + "'";
31     };
32     Rule.prototype.apply = function (sourceFile) {
33         return this.applyWithWalker(new NoShadowedVariableWalker(sourceFile, this.ruleName, parseOptions(this.ruleArguments[0])));
34     };
35     /* tslint:disable:object-literal-sort-keys */
36     Rule.metadata = {
37         ruleName: "no-shadowed-variable",
38         description: "Disallows shadowing variable declarations.",
39         rationale: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["\n            When a variable in a local scope and a variable in the containing scope have the same name, shadowing occurs.\n            Shadowing makes it impossible to access the variable in the containing scope and\n            obscures to what value an identifier actually refers. Compare the following snippets:\n\n            ```\n            const a = 'no shadow';\n            function print() {\n                console.log(a);\n            }\n            print(); // logs 'no shadow'.\n            ```\n\n            ```\n            const a = 'no shadow';\n            function print() {\n                const a = 'shadow'; // TSLint will complain here.\n                console.log(a);\n            }\n            print(); // logs 'shadow'.\n            ```\n\n            ESLint has [an equivalent rule](https://eslint.org/docs/rules/no-shadow).\n            For more background information, refer to\n            [this MDN closure doc](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#Lexical_scoping).\n        "], ["\n            When a variable in a local scope and a variable in the containing scope have the same name, shadowing occurs.\n            Shadowing makes it impossible to access the variable in the containing scope and\n            obscures to what value an identifier actually refers. Compare the following snippets:\n\n            \\`\\`\\`\n            const a = 'no shadow';\n            function print() {\n                console.log(a);\n            }\n            print(); // logs 'no shadow'.\n            \\`\\`\\`\n\n            \\`\\`\\`\n            const a = 'no shadow';\n            function print() {\n                const a = 'shadow'; // TSLint will complain here.\n                console.log(a);\n            }\n            print(); // logs 'shadow'.\n            \\`\\`\\`\n\n            ESLint has [an equivalent rule](https://eslint.org/docs/rules/no-shadow).\n            For more background information, refer to\n            [this MDN closure doc](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#Lexical_scoping).\n        "]))),
40         optionsDescription: Lint.Utils.dedent(templateObject_2 || (templateObject_2 = tslib_1.__makeTemplateObject(["\n            You can optionally pass an object to disable checking for certain kinds of declarations.\n            Possible keys are `\"class\"`, `\"enum\"`, `\"function\"`, `\"import\"`, `\"interface\"`, `\"namespace\"`, `\"typeAlias\"`\n            and `\"typeParameter\"`. You can also pass `\"underscore`\" to ignore variable names that begin with `_`.\n            Just set the value to `false` for the check you want to disable.\n            All checks default to `true`, i.e. are enabled by default.\n            Note that you cannot disable variables and parameters.\n\n            The option `\"temporalDeadZone\"` defaults to `true` which shows errors when shadowing block scoped declarations in their\n            temporal dead zone. When set to `false` parameters, classes, enums and variables declared\n            with `let` or `const` are not considered shadowed if the shadowing occurs within their\n            [temporal dead zone](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified).\n\n            The following example shows how the `\"temporalDeadZone\"` option changes the linting result:\n\n            ```ts\n            function fn(value) {\n                if (value) {\n                    const tmp = value; // no error on this line if \"temporalDeadZone\" is false\n                    return tmp;\n                }\n                let tmp = undefined;\n                if (!value) {\n                    const tmp = value; // this line always contains an error\n                    return tmp;\n                }\n            }\n            ```\n        "], ["\n            You can optionally pass an object to disable checking for certain kinds of declarations.\n            Possible keys are \\`\"class\"\\`, \\`\"enum\"\\`, \\`\"function\"\\`, \\`\"import\"\\`, \\`\"interface\"\\`, \\`\"namespace\"\\`, \\`\"typeAlias\"\\`\n            and \\`\"typeParameter\"\\`. You can also pass \\`\"underscore\\`\" to ignore variable names that begin with \\`_\\`.\n            Just set the value to \\`false\\` for the check you want to disable.\n            All checks default to \\`true\\`, i.e. are enabled by default.\n            Note that you cannot disable variables and parameters.\n\n            The option \\`\"temporalDeadZone\"\\` defaults to \\`true\\` which shows errors when shadowing block scoped declarations in their\n            temporal dead zone. When set to \\`false\\` parameters, classes, enums and variables declared\n            with \\`let\\` or \\`const\\` are not considered shadowed if the shadowing occurs within their\n            [temporal dead zone](http://jsrocks.org/2015/01/temporal-dead-zone-tdz-demystified).\n\n            The following example shows how the \\`\"temporalDeadZone\"\\` option changes the linting result:\n\n            \\`\\`\\`ts\n            function fn(value) {\n                if (value) {\n                    const tmp = value; // no error on this line if \"temporalDeadZone\" is false\n                    return tmp;\n                }\n                let tmp = undefined;\n                if (!value) {\n                    const tmp = value; // this line always contains an error\n                    return tmp;\n                }\n            }\n            \\`\\`\\`\n        "]))),
41         options: {
42             type: "object",
43             properties: {
44                 class: { type: "boolean" },
45                 enum: { type: "boolean" },
46                 function: { type: "boolean" },
47                 import: { type: "boolean" },
48                 interface: { type: "boolean" },
49                 namespace: { type: "boolean" },
50                 typeAlias: { type: "boolean" },
51                 typeParameter: { type: "boolean" },
52                 temporalDeadZone: { type: "boolean" },
53                 underscore: { type: "boolean" },
54             },
55         },
56         optionExamples: [
57             true,
58             [
59                 true,
60                 {
61                     class: true,
62                     enum: true,
63                     function: true,
64                     interface: false,
65                     namespace: true,
66                     typeAlias: false,
67                     typeParameter: false,
68                     underscore: false,
69                 },
70             ],
71         ],
72         type: "functionality",
73         typescriptOnly: false,
74     };
75     return Rule;
76 }(Lint.Rules.AbstractRule));
77 exports.Rule = Rule;
78 function parseOptions(option) {
79     return tslib_1.__assign({ class: true, enum: true, function: true, import: true, interface: true, namespace: true, temporalDeadZone: true, typeAlias: true, typeParameter: true, underscore: true }, option);
80 }
81 var Scope = /** @class */ (function () {
82     function Scope(functionScope) {
83         this.variables = new Map();
84         this.variablesSeen = new Map();
85         this.reassigned = new Set();
86         // if no functionScope is provided we are in the process of creating a new function scope, which for consistency links to itself
87         this.functionScope = functionScope !== undefined ? functionScope : this;
88     }
89     Scope.prototype.addVariable = function (identifier, blockScoped, tdz) {
90         if (blockScoped === void 0) { blockScoped = true; }
91         if (tdz === void 0) { tdz = false; }
92         // block scoped variables go to the block scope, function scoped variables to the containing function scope
93         var scope = blockScoped ? this : this.functionScope;
94         var list = scope.variables.get(identifier.text);
95         var variableInfo = {
96             identifier: identifier,
97             tdz: tdz,
98         };
99         if (list === undefined) {
100             scope.variables.set(identifier.text, [variableInfo]);
101         }
102         else {
103             list.push(variableInfo);
104         }
105     };
106     return Scope;
107 }());
108 var NoShadowedVariableWalker = /** @class */ (function (_super) {
109     tslib_1.__extends(NoShadowedVariableWalker, _super);
110     function NoShadowedVariableWalker() {
111         var _this = _super !== null && _super.apply(this, arguments) || this;
112         _this.scope = new Scope();
113         return _this;
114     }
115     NoShadowedVariableWalker.prototype.walk = function (sourceFile) {
116         var _this = this;
117         if (sourceFile.isDeclarationFile) {
118             return;
119         }
120         this.scope = new Scope();
121         var cb = function (node) {
122             var parentScope = _this.scope;
123             if (((_this.options.function && tsutils_1.isFunctionExpression(node)) ||
124                 (_this.options.class && tsutils_1.isClassExpression(node))) &&
125                 node.name !== undefined) {
126                 /* special handling for named function and class expressions:
127                    technically the name of the function is only visible inside of it,
128                    but variables with the same name declared inside don't cause compiler errors.
129                    Therefore we add an additional function scope only for the function name to avoid merging with other declarations */
130                 var functionScope = new Scope();
131                 functionScope.addVariable(node.name, false);
132                 _this.scope = new Scope();
133                 if (tsutils_1.isClassExpression(node)) {
134                     _this.visitClassLikeDeclaration(node, functionScope, cb);
135                 }
136                 else {
137                     ts.forEachChild(node, cb);
138                 }
139                 _this.onScopeEnd(functionScope);
140                 _this.scope = functionScope;
141                 _this.onScopeEnd(parentScope);
142                 _this.scope = parentScope;
143                 return;
144             }
145             /* Visit decorators before entering a function scope.
146                In the AST decorators are children of the declaration they decorate, but we don't want to warn for the following code:
147                @decorator((param) => param)
148                function foo(param) {}
149             */
150             if (node.decorators !== undefined) {
151                 for (var _i = 0, _a = node.decorators; _i < _a.length; _i++) {
152                     var decorator = _a[_i];
153                     ts.forEachChild(decorator, cb);
154                 }
155             }
156             var boundary = tsutils_1.isScopeBoundary(node);
157             if (boundary === 2 /* Block */) {
158                 _this.scope = new Scope(parentScope.functionScope);
159             }
160             else if (boundary === 1 /* Function */) {
161                 _this.scope = new Scope();
162             }
163             switch (node.kind) {
164                 case ts.SyntaxKind.Decorator:
165                     return; // handled above
166                 case ts.SyntaxKind.VariableDeclarationList:
167                     _this.handleVariableDeclarationList(node);
168                     break;
169                 case ts.SyntaxKind.TypeParameter:
170                     if (_this.options.typeParameter) {
171                         _this.scope.addVariable(node.name);
172                     }
173                     break;
174                 case ts.SyntaxKind.FunctionDeclaration:
175                     if (_this.options.function &&
176                         node.name !== undefined) {
177                         parentScope.addVariable(node.name, false);
178                     }
179                     break;
180                 case ts.SyntaxKind.ClassDeclaration:
181                     if (_this.options.class && node.name !== undefined) {
182                         parentScope.addVariable(node.name, true, true);
183                     }
184                 // falls through
185                 case ts.SyntaxKind.ClassExpression:
186                     _this.visitClassLikeDeclaration(node, parentScope, cb);
187                     _this.onScopeEnd(parentScope);
188                     _this.scope = parentScope;
189                     return;
190                 case ts.SyntaxKind.TypeAliasDeclaration:
191                     if (_this.options.typeAlias) {
192                         parentScope.addVariable(node.name);
193                     }
194                     break;
195                 case ts.SyntaxKind.EnumDeclaration:
196                     if (_this.options.enum) {
197                         parentScope.addVariable(node.name, true, true);
198                     }
199                     break;
200                 case ts.SyntaxKind.InterfaceDeclaration:
201                     if (_this.options.interface) {
202                         parentScope.addVariable(node.name);
203                     }
204                     break;
205                 case ts.SyntaxKind.Parameter:
206                     if (node.parent.kind !== ts.SyntaxKind.IndexSignature &&
207                         !tsutils_1.isThisParameter(node) &&
208                         tsutils_1.isFunctionWithBody(node.parent)) {
209                         _this.handleBindingName(node.name, false, true);
210                     }
211                     break;
212                 case ts.SyntaxKind.ModuleDeclaration:
213                     if (_this.options.namespace &&
214                         node.parent.kind !== ts.SyntaxKind.ModuleDeclaration &&
215                         node.name.kind === ts.SyntaxKind.Identifier &&
216                         !tsutils_1.isNodeFlagSet(node, ts.NodeFlags.GlobalAugmentation)) {
217                         parentScope.addVariable(node.name, false);
218                     }
219                     if (tsutils_1.hasModifier(node.modifiers, ts.SyntaxKind.DeclareKeyword)) {
220                         _this.onScopeEnd(parentScope);
221                         _this.scope = parentScope;
222                         return; // don't check any ambient declaration blocks
223                     }
224                     break;
225                 case ts.SyntaxKind.ImportClause:
226                     if (_this.options.import && node.name !== undefined) {
227                         _this.scope.addVariable(node.name, false);
228                     }
229                     break;
230                 case ts.SyntaxKind.NamespaceImport:
231                 case ts.SyntaxKind.ImportSpecifier:
232                 case ts.SyntaxKind.ImportEqualsDeclaration:
233                     if (_this.options.import) {
234                         _this.scope.addVariable(node.name, false);
235                     }
236             }
237             if (boundary !== 0 /* None */) {
238                 ts.forEachChild(node, cb);
239                 _this.onScopeEnd(parentScope);
240                 _this.scope = parentScope;
241             }
242             else {
243                 return ts.forEachChild(node, cb);
244             }
245         };
246         ts.forEachChild(sourceFile, cb);
247         this.onScopeEnd();
248     };
249     NoShadowedVariableWalker.prototype.visitClassLikeDeclaration = function (declaration, parentScope, cb) {
250         var _this = this;
251         var currentScope = this.scope;
252         ts.forEachChild(declaration, function (node) {
253             if (!tsutils_1.hasModifier(node.modifiers, ts.SyntaxKind.StaticKeyword)) {
254                 return cb(node);
255             }
256             /* Don't treat static members as children of the class' scope. That avoid shadowed type parameter warnings on static members.
257                class C<T> {
258                    static method<T>() {}
259                }
260             */
261             _this.scope = parentScope;
262             cb(node);
263             _this.scope = currentScope;
264         });
265     };
266     NoShadowedVariableWalker.prototype.handleVariableDeclarationList = function (node) {
267         var blockScoped = tsutils_1.isBlockScopedVariableDeclarationList(node);
268         for (var _i = 0, _a = node.declarations; _i < _a.length; _i++) {
269             var variable = _a[_i];
270             this.handleBindingName(variable.name, blockScoped);
271         }
272     };
273     NoShadowedVariableWalker.prototype.handleBindingName = function (node, blockScoped, tdz) {
274         if (tdz === void 0) { tdz = blockScoped; }
275         if (node.kind === ts.SyntaxKind.Identifier) {
276             this.scope.addVariable(node, blockScoped, tdz);
277         }
278         else {
279             for (var _i = 0, _a = node.elements; _i < _a.length; _i++) {
280                 var element = _a[_i];
281                 if (element.kind !== ts.SyntaxKind.OmittedExpression) {
282                     this.handleBindingName(element.name, blockScoped, tdz);
283                 }
284             }
285         }
286     };
287     NoShadowedVariableWalker.prototype.onScopeEnd = function (parent) {
288         var _this = this;
289         var _a = this.scope, variables = _a.variables, variablesSeen = _a.variablesSeen;
290         variablesSeen.forEach(function (identifiers, name) {
291             var declarationsInScope = variables.get(name);
292             var _loop_1 = function (identifier) {
293                 if (declarationsInScope !== undefined &&
294                     (_this.options.temporalDeadZone ||
295                         // check if any of the declaration either has no temporal dead zone or is declared before the identifier
296                         declarationsInScope.some(function (declaration) {
297                             return !declaration.tdz || declaration.identifier.pos < identifier.pos;
298                         })) &&
299                     (_this.options.underscore || !identifier.getText().startsWith("_"))) {
300                     _this.addFailureAtNode(identifier, Rule.FAILURE_STRING_FACTORY(name));
301                 }
302                 else if (parent !== undefined) {
303                     addOneToList(parent.variablesSeen, name, identifier);
304                 }
305             };
306             for (var _i = 0, identifiers_1 = identifiers; _i < identifiers_1.length; _i++) {
307                 var identifier = identifiers_1[_i];
308                 _loop_1(identifier);
309             }
310         });
311         if (parent !== undefined) {
312             variables.forEach(function (identifiers, name) {
313                 addToList(parent.variablesSeen, name, identifiers);
314             });
315         }
316     };
317     return NoShadowedVariableWalker;
318 }(Lint.AbstractWalker));
319 function addToList(map, name, variables) {
320     var list = map.get(name);
321     if (list === undefined) {
322         list = [];
323         map.set(name, list);
324     }
325     for (var _i = 0, variables_1 = variables; _i < variables_1.length; _i++) {
326         var variable = variables_1[_i];
327         list.push(variable.identifier);
328     }
329 }
330 function addOneToList(map, name, identifier) {
331     var list = map.get(name);
332     if (list === undefined) {
333         map.set(name, [identifier]);
334     }
335     else {
336         list.push(identifier);
337     }
338 }
339 var templateObject_1, templateObject_2;