diff options
author | Florian Dold <florian.dold@gmail.com> | 2017-05-28 00:38:50 +0200 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2017-05-28 00:40:43 +0200 |
commit | 7fff4499fd915bcea3fa93b1aa8b35f4fe7a6027 (patch) | |
tree | 6de9a1aebd150a23b7f8c273ec657a5d0a18fe3e /node_modules/tslint/lib/rules/preferConstRule.js | |
parent | 963b7a41feb29cc4be090a2446bdfe0c1f1bcd81 (diff) |
add linting (and some initial fixes)
Diffstat (limited to 'node_modules/tslint/lib/rules/preferConstRule.js')
-rw-r--r-- | node_modules/tslint/lib/rules/preferConstRule.js | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/node_modules/tslint/lib/rules/preferConstRule.js b/node_modules/tslint/lib/rules/preferConstRule.js new file mode 100644 index 000000000..674a44755 --- /dev/null +++ b/node_modules/tslint/lib/rules/preferConstRule.js @@ -0,0 +1,310 @@ +"use strict"; +/** + * @license + * Copyright 2013 Palantir Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +var tslib_1 = require("tslib"); +var ts = require("typescript"); +var Lint = require("../index"); +var utils = require("tsutils"); +var OPTION_DESTRUCTURING_ALL = "all"; +var OPTION_DESTRUCTURING_ANY = "any"; +var Rule = (function (_super) { + tslib_1.__extends(Rule, _super); + function Rule() { + return _super !== null && _super.apply(this, arguments) || this; + } + /* tslint:enable:object-literal-sort-keys */ + Rule.FAILURE_STRING_FACTORY = function (identifier, blockScoped) { + return "Identifier '" + identifier + "' is never reassigned; use 'const' instead of '" + (blockScoped ? "let" : "var") + "'."; + }; + Rule.prototype.apply = function (sourceFile) { + var options = { + destructuringAll: this.ruleArguments.length !== 0 && + this.ruleArguments[0].destructuring === OPTION_DESTRUCTURING_ALL, + }; + var preferConstWalker = new PreferConstWalker(sourceFile, this.ruleName, options); + return this.applyWithWalker(preferConstWalker); + }; + return Rule; +}(Lint.Rules.AbstractRule)); +/* tslint:disable:object-literal-sort-keys */ +Rule.metadata = { + ruleName: "prefer-const", + description: "Requires that variable declarations use `const` instead of `let` and `var` if possible.", + descriptionDetails: (_a = ["\n If a variable is only assigned to once when it is declared, it should be declared using 'const'"], _a.raw = ["\n If a variable is only assigned to once when it is declared, it should be declared using 'const'"], Lint.Utils.dedent(_a)), + hasFix: true, + optionsDescription: (_b = ["\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."], _b.raw = ["\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."], Lint.Utils.dedent(_b, OPTION_DESTRUCTURING_ANY, OPTION_DESTRUCTURING_ALL)), + options: { + type: "object", + properties: { + destructuring: { + type: "string", + enum: [OPTION_DESTRUCTURING_ALL, OPTION_DESTRUCTURING_ANY], + }, + }, + }, + optionExamples: [ + true, + [true, { destructuring: OPTION_DESTRUCTURING_ALL }], + ], + type: "maintainability", + typescriptOnly: false, +}; +exports.Rule = Rule; +var Scope = (function () { + function Scope(functionScope) { + this.variables = new Map(); + this.reassigned = new Set(); + // if no functionScope is provided we are in the process of creating a new function scope, which for consistency links to itself + this.functionScope = functionScope === undefined ? this : functionScope; + } + Scope.prototype.addVariable = function (identifier, declarationInfo, destructuringInfo) { + // block scoped variables go to the block scope, function scoped variables to the containing function scope + var scope = declarationInfo.isBlockScoped ? this : this.functionScope; + scope.variables.set(identifier.text, { + declarationInfo: declarationInfo, + destructuringInfo: destructuringInfo, + identifier: identifier, + reassigned: false, + }); + }; + return Scope; +}()); +var PreferConstWalker = (function (_super) { + tslib_1.__extends(PreferConstWalker, _super); + function PreferConstWalker() { + return _super !== null && _super.apply(this, arguments) || this; + } + PreferConstWalker.prototype.walk = function (sourceFile) { + var _this = this; + // don't check anything on declaration files + if (sourceFile.isDeclarationFile) { + return; + } + this.scope = new Scope(); + var cb = function (node) { + var savedScope = _this.scope; + var boundary = utils.isScopeBoundary(node); + if (boundary !== 0 /* None */) { + if (boundary === 1 /* Function */) { + if (node.kind === ts.SyntaxKind.ModuleDeclaration && utils.hasModifier(node.modifiers, ts.SyntaxKind.DeclareKeyword)) { + // don't check ambient namespaces + return; + } + _this.scope = new Scope(); + if (utils.isFunctionDeclaration(node) || + utils.isMethodDeclaration(node) || + utils.isFunctionExpression(node) || + utils.isArrowFunction(node) || + utils.isConstructorDeclaration(node)) { + // special handling for function parameters + // each parameter initializer can only reassign preceding parameters of variables of the containing scope + if (node.body !== undefined) { + for (var _i = 0, _a = node.parameters; _i < _a.length; _i++) { + var param = _a[_i]; + cb(param); + _this.settle(savedScope); + } + cb(node.body); + _this.onScopeEnd(savedScope); + } + _this.scope = savedScope; + return; + } + } + else { + _this.scope = new Scope(_this.scope.functionScope); + if ((utils.isForInStatement(node) || utils.isForOfStatement(node)) && + node.initializer.kind !== ts.SyntaxKind.VariableDeclarationList) { + _this.handleExpression(node.initializer); + } + } + } + if (node.kind === ts.SyntaxKind.VariableDeclarationList) { + _this.handleVariableDeclaration(node); + } + else if (node.kind === ts.SyntaxKind.CatchClause) { + _this.handleBindingName(node.variableDeclaration.name, { + canBeConst: false, + isBlockScoped: true, + }); + } + else if (node.kind === ts.SyntaxKind.Parameter) { + _this.handleBindingName(node.name, { + canBeConst: false, + isBlockScoped: true, + }); + } + else if (utils.isPostfixUnaryExpression(node) || + utils.isPrefixUnaryExpression(node) && + (node.operator === ts.SyntaxKind.PlusPlusToken || node.operator === ts.SyntaxKind.MinusMinusToken)) { + if (utils.isIdentifier(node.operand)) { + _this.scope.reassigned.add(node.operand.text); + } + } + else if (utils.isBinaryExpression(node) && utils.isAssignmentKind(node.operatorToken.kind)) { + _this.handleExpression(node.left); + } + if (boundary !== 0 /* None */) { + ts.forEachChild(node, cb); + _this.onScopeEnd(savedScope); + _this.scope = savedScope; + } + else { + return ts.forEachChild(node, cb); + } + }; + if (ts.isExternalModule(sourceFile)) { + ts.forEachChild(sourceFile, cb); + this.onScopeEnd(); + } + else { + return ts.forEachChild(sourceFile, cb); + } + }; + PreferConstWalker.prototype.handleExpression = function (node) { + switch (node.kind) { + case ts.SyntaxKind.Identifier: + this.scope.reassigned.add(node.text); + break; + case ts.SyntaxKind.ParenthesizedExpression: + this.handleExpression(node.expression); + break; + case ts.SyntaxKind.ArrayLiteralExpression: + for (var _i = 0, _a = node.elements; _i < _a.length; _i++) { + var element = _a[_i]; + if (element.kind === ts.SyntaxKind.SpreadElement) { + this.handleExpression(element.expression); + } + else { + this.handleExpression(element); + } + } + break; + case ts.SyntaxKind.ObjectLiteralExpression: + for (var _b = 0, _c = node.properties; _b < _c.length; _b++) { + var property = _c[_b]; + switch (property.kind) { + case ts.SyntaxKind.ShorthandPropertyAssignment: + this.scope.reassigned.add(property.name.text); + break; + case ts.SyntaxKind.SpreadAssignment: + if (property.name !== undefined) { + this.scope.reassigned.add(property.name.text); + } + else { + // handle `...(variable)` + this.handleExpression(property.expression); + } + break; + default: + this.handleExpression(property.initializer); + } + } + break; + } + }; + PreferConstWalker.prototype.handleBindingName = function (name, declarationInfo) { + var _this = this; + if (name.kind === ts.SyntaxKind.Identifier) { + this.scope.addVariable(name, declarationInfo); + } + else { + var destructuringInfo_1 = { + reassignedSiblings: false, + }; + utils.forEachDestructuringIdentifier(name, function (declaration) { return _this.scope.addVariable(declaration.name, declarationInfo, destructuringInfo_1); }); + } + }; + PreferConstWalker.prototype.handleVariableDeclaration = function (declarationList) { + var declarationInfo; + var kind = utils.getVariableDeclarationKind(declarationList); + if (kind === 2 /* Const */ || + utils.hasModifier(declarationList.parent.modifiers, ts.SyntaxKind.ExportKeyword, ts.SyntaxKind.DeclareKeyword)) { + declarationInfo = { + canBeConst: false, + isBlockScoped: kind !== 0 /* Var */, + }; + } + else { + declarationInfo = { + allInitialized: declarationList.parent.kind === ts.SyntaxKind.ForOfStatement || + declarationList.parent.kind === ts.SyntaxKind.ForInStatement || + declarationList.declarations.every(function (declaration) { return declaration.initializer !== undefined; }), + canBeConst: true, + declarationList: declarationList, + isBlockScoped: kind === 1 /* Let */, + isForLoop: declarationList.parent.kind === ts.SyntaxKind.ForStatement, + reassignedSiblings: false, + }; + } + for (var _i = 0, _a = declarationList.declarations; _i < _a.length; _i++) { + var declaration = _a[_i]; + this.handleBindingName(declaration.name, declarationInfo); + } + }; + PreferConstWalker.prototype.settle = function (parent) { + var _a = this.scope, variables = _a.variables, reassigned = _a.reassigned; + reassigned.forEach(function (name) { + var variableInfo = variables.get(name); + if (variableInfo !== undefined) { + if (variableInfo.declarationInfo.canBeConst) { + variableInfo.reassigned = true; + variableInfo.declarationInfo.reassignedSiblings = true; + if (variableInfo.destructuringInfo !== undefined) { + variableInfo.destructuringInfo.reassignedSiblings = true; + } + } + } + else if (parent !== undefined) { + // if the reassigned variable was not declared in this scope we defer to the parent scope + parent.reassigned.add(name); + } + }); + reassigned.clear(); + }; + PreferConstWalker.prototype.onScopeEnd = function (parent) { + var _this = this; + this.settle(parent); + var appliedFixes = new Set(); + this.scope.variables.forEach(function (info, name) { + if (info.declarationInfo.canBeConst && + !info.reassigned && + // don't add failures for reassigned variables in for loop initializer + !(info.declarationInfo.reassignedSiblings && info.declarationInfo.isForLoop) && + // if {destructuring: "all"} is set, only add a failure if all variables in a destructuring assignment can be const + (!_this.options.destructuringAll || + info.destructuringInfo === undefined || + !info.destructuringInfo.reassignedSiblings)) { + var fix = void 0; + // only apply fixes if the VariableDeclarationList has no reassigned variables + // and the variable is block scoped aka `let` and initialized + if (info.declarationInfo.allInitialized && + !info.declarationInfo.reassignedSiblings && + info.declarationInfo.isBlockScoped && + !appliedFixes.has(info.declarationInfo.declarationList)) { + fix = new Lint.Replacement(info.declarationInfo.declarationList.getStart(_this.sourceFile), 3, "const"); + // add only one fixer per VariableDeclarationList + appliedFixes.add(info.declarationInfo.declarationList); + } + _this.addFailureAtNode(info.identifier, Rule.FAILURE_STRING_FACTORY(name, info.declarationInfo.isBlockScoped), fix); + } + }); + }; + return PreferConstWalker; +}(Lint.AbstractWalker)); +var _a, _b; |