deprecationRule.js 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. "use strict";
  2. /**
  3. * @license
  4. * Copyright 2016 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 = function (name, message) {
  30. return name + " is deprecated" + (message === "" ? "." : ": " + message.trim());
  31. };
  32. Rule.prototype.applyWithProgram = function (sourceFile, program) {
  33. return this.applyWithFunction(sourceFile, walk, undefined, program.getTypeChecker());
  34. };
  35. /* tslint:disable:object-literal-sort-keys */
  36. Rule.metadata = {
  37. ruleName: "deprecation",
  38. description: "Warns when deprecated APIs are used.",
  39. descriptionDetails: Lint.Utils.dedent(templateObject_1 || (templateObject_1 = tslib_1.__makeTemplateObject(["Any usage of an identifier\n with the @deprecated JSDoc annotation will trigger a warning.\n See http://usejsdoc.org/tags-deprecated.html"], ["Any usage of an identifier\n with the @deprecated JSDoc annotation will trigger a warning.\n See http://usejsdoc.org/tags-deprecated.html"]))),
  40. rationale: "Deprecated APIs should be avoided, and usage updated.",
  41. optionsDescription: "",
  42. options: null,
  43. optionExamples: [true],
  44. type: "maintainability",
  45. typescriptOnly: false,
  46. requiresTypeInfo: true,
  47. };
  48. return Rule;
  49. }(Lint.Rules.TypedRule));
  50. exports.Rule = Rule;
  51. function walk(ctx, tc) {
  52. return ts.forEachChild(ctx.sourceFile, function cb(node) {
  53. if (tsutils_1.isIdentifier(node)) {
  54. if (!isDeclaration(node)) {
  55. var deprecation = getDeprecation(node, tc);
  56. if (deprecation !== undefined) {
  57. ctx.addFailureAtNode(node, Rule.FAILURE_STRING(node.text, deprecation));
  58. }
  59. }
  60. }
  61. else {
  62. switch (node.kind) {
  63. case ts.SyntaxKind.ImportDeclaration:
  64. case ts.SyntaxKind.ImportEqualsDeclaration:
  65. case ts.SyntaxKind.ExportDeclaration:
  66. case ts.SyntaxKind.ExportAssignment:
  67. return;
  68. }
  69. return ts.forEachChild(node, cb);
  70. }
  71. });
  72. }
  73. function isDeclaration(identifier) {
  74. var parent = identifier.parent;
  75. switch (parent.kind) {
  76. case ts.SyntaxKind.ClassDeclaration:
  77. case ts.SyntaxKind.ClassExpression:
  78. case ts.SyntaxKind.InterfaceDeclaration:
  79. case ts.SyntaxKind.TypeParameter:
  80. case ts.SyntaxKind.FunctionExpression:
  81. case ts.SyntaxKind.FunctionDeclaration:
  82. case ts.SyntaxKind.LabeledStatement:
  83. case ts.SyntaxKind.JsxAttribute:
  84. case ts.SyntaxKind.MethodDeclaration:
  85. case ts.SyntaxKind.MethodSignature:
  86. case ts.SyntaxKind.PropertySignature:
  87. case ts.SyntaxKind.TypeAliasDeclaration:
  88. case ts.SyntaxKind.GetAccessor:
  89. case ts.SyntaxKind.SetAccessor:
  90. case ts.SyntaxKind.EnumDeclaration:
  91. case ts.SyntaxKind.ModuleDeclaration:
  92. return true;
  93. case ts.SyntaxKind.VariableDeclaration:
  94. case ts.SyntaxKind.Parameter:
  95. case ts.SyntaxKind.PropertyDeclaration:
  96. case ts.SyntaxKind.EnumMember:
  97. case ts.SyntaxKind.ImportEqualsDeclaration:
  98. return parent.name === identifier;
  99. case ts.SyntaxKind.PropertyAssignment:
  100. return parent.name === identifier &&
  101. !tsutils_1.isReassignmentTarget(identifier.parent.parent);
  102. case ts.SyntaxKind.BindingElement:
  103. // return true for `b` in `const {a: b} = obj"`
  104. return parent.name === identifier &&
  105. parent.propertyName !== undefined;
  106. default:
  107. return false;
  108. }
  109. }
  110. function getCallExpresion(node) {
  111. var parent = node.parent;
  112. if (tsutils_1.isPropertyAccessExpression(parent) && parent.name === node) {
  113. node = parent;
  114. parent = node.parent;
  115. }
  116. return tsutils_1.isTaggedTemplateExpression(parent) || (tsutils_1.isCallExpression(parent) || tsutils_1.isNewExpression(parent)) && parent.expression === node
  117. ? parent
  118. : undefined;
  119. }
  120. function getDeprecation(node, tc) {
  121. var callExpression = getCallExpresion(node);
  122. if (callExpression !== undefined) {
  123. var result = getSignatureDeprecation(tc.getResolvedSignature(callExpression));
  124. if (result !== undefined) {
  125. return result;
  126. }
  127. }
  128. var symbol;
  129. var parent = node.parent;
  130. if (parent.kind === ts.SyntaxKind.BindingElement) {
  131. symbol = tc.getTypeAtLocation(parent.parent).getProperty(node.text);
  132. }
  133. else if (tsutils_1.isPropertyAssignment(parent) && parent.name === node ||
  134. tsutils_1.isShorthandPropertyAssignment(parent) && parent.name === node && tsutils_1.isReassignmentTarget(node)) {
  135. symbol = tc.getPropertySymbolOfDestructuringAssignment(node);
  136. }
  137. else {
  138. symbol = tc.getSymbolAtLocation(node);
  139. }
  140. if (symbol !== undefined && tsutils_1.isSymbolFlagSet(symbol, ts.SymbolFlags.Alias)) {
  141. symbol = tc.getAliasedSymbol(symbol);
  142. }
  143. if (symbol === undefined ||
  144. // if this is a CallExpression and the declaration is a function or method,
  145. // stop here to avoid collecting JsDoc of all overload signatures
  146. callExpression !== undefined && isFunctionOrMethod(symbol.declarations)) {
  147. return undefined;
  148. }
  149. return getSymbolDeprecation(symbol);
  150. }
  151. function findDeprecationTag(tags) {
  152. for (var _i = 0, tags_1 = tags; _i < tags_1.length; _i++) {
  153. var tag = tags_1[_i];
  154. if (tag.name === "deprecated") {
  155. return tag.text === undefined ? "" : tag.text;
  156. }
  157. }
  158. return undefined;
  159. }
  160. function getSymbolDeprecation(symbol) {
  161. if (symbol.getJsDocTags !== undefined) {
  162. return findDeprecationTag(symbol.getJsDocTags());
  163. }
  164. // for compatibility with typescript@<2.3.0
  165. return getDeprecationFromDeclarations(symbol.declarations);
  166. }
  167. function getSignatureDeprecation(signature) {
  168. if (signature === undefined) {
  169. return undefined;
  170. }
  171. if (signature.getJsDocTags !== undefined) {
  172. return findDeprecationTag(signature.getJsDocTags());
  173. }
  174. // for compatibility with typescript@<2.3.0
  175. return signature.declaration === undefined ? undefined : getDeprecationFromDeclaration(signature.declaration);
  176. }
  177. function getDeprecationFromDeclarations(declarations) {
  178. if (declarations === undefined) {
  179. return undefined;
  180. }
  181. var declaration;
  182. for (var _i = 0, declarations_1 = declarations; _i < declarations_1.length; _i++) {
  183. declaration = declarations_1[_i];
  184. if (tsutils_1.isBindingElement(declaration)) {
  185. declaration = tsutils_1.getDeclarationOfBindingElement(declaration);
  186. }
  187. if (tsutils_1.isVariableDeclaration(declaration)) {
  188. declaration = declaration.parent;
  189. }
  190. if (tsutils_1.isVariableDeclarationList(declaration)) {
  191. declaration = declaration.parent;
  192. }
  193. var result = getDeprecationFromDeclaration(declaration);
  194. if (result !== undefined) {
  195. return result;
  196. }
  197. }
  198. return undefined;
  199. }
  200. function getDeprecationFromDeclaration(declaration) {
  201. for (var _i = 0, _a = tsutils_1.getJsDoc(declaration); _i < _a.length; _i++) {
  202. var comment = _a[_i];
  203. if (comment.tags === undefined) {
  204. continue;
  205. }
  206. for (var _b = 0, _c = comment.tags; _b < _c.length; _b++) {
  207. var tag = _c[_b];
  208. if (tag.tagName.text === "deprecated") {
  209. return tag.comment === undefined ? "" : tag.comment;
  210. }
  211. }
  212. }
  213. return undefined;
  214. }
  215. function isFunctionOrMethod(declarations) {
  216. if (declarations === undefined || declarations.length === 0) {
  217. return false;
  218. }
  219. switch (declarations[0].kind) {
  220. case ts.SyntaxKind.MethodDeclaration:
  221. case ts.SyntaxKind.FunctionDeclaration:
  222. case ts.SyntaxKind.FunctionExpression:
  223. case ts.SyntaxKind.MethodSignature:
  224. return true;
  225. default:
  226. return false;
  227. }
  228. }
  229. var templateObject_1;