noUnusedVariableRule.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. "use strict";
  2. var __extends = (this && this.__extends) || function (d, b) {
  3. for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
  4. function __() { this.constructor = d; }
  5. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  6. };
  7. var ts = require("typescript");
  8. var Lint = require("../lint");
  9. var OPTION_REACT = "react";
  10. var OPTION_CHECK_PARAMETERS = "check-parameters";
  11. var REACT_MODULES = ["react", "react/addons"];
  12. var REACT_NAMESPACE_IMPORT_NAME = "React";
  13. var MODULE_SPECIFIER_MATCH = /^["'](.+)['"]$/;
  14. var Rule = (function (_super) {
  15. __extends(Rule, _super);
  16. function Rule() {
  17. _super.apply(this, arguments);
  18. }
  19. Rule.prototype.apply = function (sourceFile) {
  20. var languageService = Lint.createLanguageService(sourceFile.fileName, sourceFile.getFullText());
  21. return this.applyWithWalker(new NoUnusedVariablesWalker(sourceFile, this.getOptions(), languageService));
  22. };
  23. Rule.FAILURE_STRING = "unused variable: ";
  24. return Rule;
  25. }(Lint.Rules.AbstractRule));
  26. exports.Rule = Rule;
  27. var NoUnusedVariablesWalker = (function (_super) {
  28. __extends(NoUnusedVariablesWalker, _super);
  29. function NoUnusedVariablesWalker(sourceFile, options, languageService) {
  30. _super.call(this, sourceFile, options);
  31. this.languageService = languageService;
  32. this.skipVariableDeclaration = false;
  33. this.skipParameterDeclaration = false;
  34. this.hasSeenJsxElement = false;
  35. this.isReactUsed = false;
  36. }
  37. NoUnusedVariablesWalker.prototype.visitSourceFile = function (node) {
  38. _super.prototype.visitSourceFile.call(this, node);
  39. if (this.hasOption(OPTION_REACT)
  40. && this.reactImport != null
  41. && !this.isReactUsed
  42. && !this.hasSeenJsxElement) {
  43. var nameText = this.reactImport.name.getText();
  44. this.addFailure(this.createFailure(this.reactImport.name.getStart(), nameText.length, Rule.FAILURE_STRING + "'" + nameText + "'"));
  45. }
  46. };
  47. NoUnusedVariablesWalker.prototype.visitBindingElement = function (node) {
  48. var isSingleVariable = node.name.kind === ts.SyntaxKind.Identifier;
  49. if (isSingleVariable && !this.skipBindingElement) {
  50. var variableIdentifier = node.name;
  51. this.validateReferencesForVariable(variableIdentifier.text, variableIdentifier.getStart());
  52. }
  53. _super.prototype.visitBindingElement.call(this, node);
  54. };
  55. NoUnusedVariablesWalker.prototype.visitCatchClause = function (node) {
  56. this.visitBlock(node.block);
  57. };
  58. NoUnusedVariablesWalker.prototype.visitFunctionDeclaration = function (node) {
  59. if (!Lint.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword, ts.SyntaxKind.DeclareKeyword)) {
  60. var variableName = node.name.text;
  61. this.validateReferencesForVariable(variableName, node.name.getStart());
  62. }
  63. _super.prototype.visitFunctionDeclaration.call(this, node);
  64. };
  65. NoUnusedVariablesWalker.prototype.visitFunctionType = function (node) {
  66. this.skipParameterDeclaration = true;
  67. _super.prototype.visitFunctionType.call(this, node);
  68. this.skipParameterDeclaration = false;
  69. };
  70. NoUnusedVariablesWalker.prototype.visitImportDeclaration = function (node) {
  71. if (!Lint.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword)) {
  72. var importClause = node.importClause;
  73. if (importClause != null && importClause.name != null) {
  74. var variableIdentifier = importClause.name;
  75. this.validateReferencesForVariable(variableIdentifier.text, variableIdentifier.getStart());
  76. }
  77. }
  78. _super.prototype.visitImportDeclaration.call(this, node);
  79. };
  80. NoUnusedVariablesWalker.prototype.visitImportEqualsDeclaration = function (node) {
  81. if (!Lint.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword)) {
  82. var name_1 = node.name;
  83. this.validateReferencesForVariable(name_1.text, name_1.getStart());
  84. }
  85. _super.prototype.visitImportEqualsDeclaration.call(this, node);
  86. };
  87. NoUnusedVariablesWalker.prototype.visitIndexSignatureDeclaration = function (node) {
  88. this.skipParameterDeclaration = true;
  89. _super.prototype.visitIndexSignatureDeclaration.call(this, node);
  90. this.skipParameterDeclaration = false;
  91. };
  92. NoUnusedVariablesWalker.prototype.visitInterfaceDeclaration = function (node) {
  93. this.skipParameterDeclaration = true;
  94. _super.prototype.visitInterfaceDeclaration.call(this, node);
  95. this.skipParameterDeclaration = false;
  96. };
  97. NoUnusedVariablesWalker.prototype.visitJsxElement = function (node) {
  98. this.hasSeenJsxElement = true;
  99. _super.prototype.visitJsxElement.call(this, node);
  100. };
  101. NoUnusedVariablesWalker.prototype.visitJsxSelfClosingElement = function (node) {
  102. this.hasSeenJsxElement = true;
  103. _super.prototype.visitJsxSelfClosingElement.call(this, node);
  104. };
  105. NoUnusedVariablesWalker.prototype.visitMethodDeclaration = function (node) {
  106. if (node.name != null && node.name.kind === ts.SyntaxKind.Identifier) {
  107. var modifiers = node.modifiers;
  108. var variableName = node.name.text;
  109. if (Lint.hasModifier(modifiers, ts.SyntaxKind.PrivateKeyword)) {
  110. this.validateReferencesForVariable(variableName, node.name.getStart());
  111. }
  112. }
  113. if (Lint.hasModifier(node.modifiers, ts.SyntaxKind.AbstractKeyword)) {
  114. this.skipParameterDeclaration = true;
  115. }
  116. _super.prototype.visitMethodDeclaration.call(this, node);
  117. this.skipParameterDeclaration = false;
  118. };
  119. NoUnusedVariablesWalker.prototype.visitNamedImports = function (node) {
  120. for (var _i = 0, _a = node.elements; _i < _a.length; _i++) {
  121. var namedImport = _a[_i];
  122. this.validateReferencesForVariable(namedImport.name.text, namedImport.name.getStart());
  123. }
  124. _super.prototype.visitNamedImports.call(this, node);
  125. };
  126. NoUnusedVariablesWalker.prototype.visitNamespaceImport = function (node) {
  127. var importDeclaration = node.parent.parent;
  128. var moduleSpecifier = importDeclaration.moduleSpecifier.getText();
  129. var moduleNameMatch = moduleSpecifier.match(MODULE_SPECIFIER_MATCH);
  130. var isReactImport = (moduleNameMatch != null) && (REACT_MODULES.indexOf(moduleNameMatch[1]) !== -1);
  131. if (this.hasOption(OPTION_REACT) && isReactImport && node.name.text === REACT_NAMESPACE_IMPORT_NAME) {
  132. this.reactImport = node;
  133. var fileName = this.getSourceFile().fileName;
  134. var position = node.name.getStart();
  135. var highlights = this.languageService.getDocumentHighlights(fileName, position, [fileName]);
  136. if (highlights != null && highlights[0].highlightSpans.length > 1) {
  137. this.isReactUsed = true;
  138. }
  139. }
  140. else {
  141. this.validateReferencesForVariable(node.name.text, node.name.getStart());
  142. }
  143. _super.prototype.visitNamespaceImport.call(this, node);
  144. };
  145. NoUnusedVariablesWalker.prototype.visitParameterDeclaration = function (node) {
  146. var isSingleVariable = node.name.kind === ts.SyntaxKind.Identifier;
  147. var isPropertyParameter = Lint.hasModifier(node.modifiers, ts.SyntaxKind.PublicKeyword, ts.SyntaxKind.PrivateKeyword, ts.SyntaxKind.ProtectedKeyword);
  148. if (!isSingleVariable && isPropertyParameter) {
  149. this.skipBindingElement = true;
  150. }
  151. if (this.hasOption(OPTION_CHECK_PARAMETERS)
  152. && isSingleVariable
  153. && !this.skipParameterDeclaration
  154. && !Lint.hasModifier(node.modifiers, ts.SyntaxKind.PublicKeyword)) {
  155. var nameNode = node.name;
  156. this.validateReferencesForVariable(nameNode.text, node.name.getStart());
  157. }
  158. _super.prototype.visitParameterDeclaration.call(this, node);
  159. this.skipBindingElement = false;
  160. };
  161. NoUnusedVariablesWalker.prototype.visitPropertyDeclaration = function (node) {
  162. if (node.name != null && node.name.kind === ts.SyntaxKind.Identifier) {
  163. var modifiers = node.modifiers;
  164. var variableName = node.name.text;
  165. if (Lint.hasModifier(modifiers, ts.SyntaxKind.PrivateKeyword)) {
  166. this.validateReferencesForVariable(variableName, node.name.getStart());
  167. }
  168. }
  169. _super.prototype.visitPropertyDeclaration.call(this, node);
  170. };
  171. NoUnusedVariablesWalker.prototype.visitVariableDeclaration = function (node) {
  172. var isSingleVariable = node.name.kind === ts.SyntaxKind.Identifier;
  173. if (isSingleVariable && !this.skipVariableDeclaration) {
  174. var variableIdentifier = node.name;
  175. this.validateReferencesForVariable(variableIdentifier.text, variableIdentifier.getStart());
  176. }
  177. _super.prototype.visitVariableDeclaration.call(this, node);
  178. };
  179. NoUnusedVariablesWalker.prototype.visitVariableStatement = function (node) {
  180. if (Lint.hasModifier(node.modifiers, ts.SyntaxKind.ExportKeyword, ts.SyntaxKind.DeclareKeyword)) {
  181. this.skipBindingElement = true;
  182. this.skipVariableDeclaration = true;
  183. }
  184. _super.prototype.visitVariableStatement.call(this, node);
  185. this.skipBindingElement = false;
  186. this.skipVariableDeclaration = false;
  187. };
  188. NoUnusedVariablesWalker.prototype.validateReferencesForVariable = function (name, position) {
  189. var fileName = this.getSourceFile().fileName;
  190. var highlights = this.languageService.getDocumentHighlights(fileName, position, [fileName]);
  191. if (highlights == null || highlights[0].highlightSpans.length <= 1) {
  192. this.addFailure(this.createFailure(position, name.length, Rule.FAILURE_STRING + "'" + name + "'"));
  193. }
  194. };
  195. return NoUnusedVariablesWalker;
  196. }(Lint.RuleWalker));