4 * Copyright 2018 Palantir Technologies, Inc.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
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);
26 return _super !== null && _super.apply(this, arguments) || this;
28 /* tslint:enable:object-literal-sort-keys */
29 Rule.FAILURE_STRING = function (name, message) {
30 return name + " is deprecated" + (message === "" ? "." : ": " + message.trim());
32 Rule.prototype.applyWithProgram = function (sourceFile, program) {
33 return this.applyWithFunction(sourceFile, walk, undefined, program.getTypeChecker());
35 /* tslint:disable:object-literal-sort-keys */
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: "",
43 optionExamples: [true],
44 type: "maintainability",
45 typescriptOnly: false,
46 requiresTypeInfo: true,
49 }(Lint.Rules.TypedRule));
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));
63 case ts.SyntaxKind.ImportDeclaration:
64 case ts.SyntaxKind.ImportEqualsDeclaration:
65 case ts.SyntaxKind.ExportDeclaration:
66 case ts.SyntaxKind.ExportAssignment:
69 return ts.forEachChild(node, cb);
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:
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);
110 function getCallExpresion(node) {
111 var parent = node.parent;
112 if (tsutils_1.isPropertyAccessExpression(parent) && parent.name === node) {
114 parent = node.parent;
116 return tsutils_1.isTaggedTemplateExpression(parent) ||
117 ((tsutils_1.isCallExpression(parent) || tsutils_1.isNewExpression(parent)) && parent.expression === node)
121 function getDeprecation(node, tc) {
122 var callExpression = getCallExpresion(node);
123 if (callExpression !== undefined) {
124 var result = getSignatureDeprecation(tc.getResolvedSignature(callExpression));
125 if (result !== undefined) {
130 var parent = node.parent;
131 if (parent.kind === ts.SyntaxKind.BindingElement) {
132 symbol = tc.getTypeAtLocation(parent.parent).getProperty(node.text);
134 else if ((tsutils_1.isPropertyAssignment(parent) && parent.name === node) ||
135 (tsutils_1.isShorthandPropertyAssignment(parent) &&
136 parent.name === node &&
137 tsutils_1.isReassignmentTarget(node))) {
138 symbol = tc.getPropertySymbolOfDestructuringAssignment(node);
141 symbol = tc.getSymbolAtLocation(node);
143 if (symbol !== undefined && tsutils_1.isSymbolFlagSet(symbol, ts.SymbolFlags.Alias)) {
144 symbol = tc.getAliasedSymbol(symbol);
146 if (symbol === undefined ||
147 // if this is a CallExpression and the declaration is a function or method,
148 // stop here to avoid collecting JsDoc of all overload signatures
149 (callExpression !== undefined && isFunctionOrMethod(symbol.declarations))) {
152 return getSymbolDeprecation(symbol);
154 function findDeprecationTag(tags) {
155 for (var _i = 0, tags_1 = tags; _i < tags_1.length; _i++) {
156 var tag = tags_1[_i];
157 if (tag.name === "deprecated") {
158 return tag.text === undefined ? "" : tag.text;
163 function getSymbolDeprecation(symbol) {
164 if (symbol.getJsDocTags !== undefined) {
165 return findDeprecationTag(symbol.getJsDocTags());
167 // for compatibility with typescript@<2.3.0
168 return getDeprecationFromDeclarations(symbol.declarations);
170 function getSignatureDeprecation(signature) {
171 if (signature === undefined) {
174 if (signature.getJsDocTags !== undefined) {
175 return findDeprecationTag(signature.getJsDocTags());
177 // for compatibility with typescript@<2.3.0
178 return signature.declaration === undefined
180 : getDeprecationFromDeclaration(signature.declaration);
182 function getDeprecationFromDeclarations(declarations) {
183 if (declarations === undefined) {
187 for (var _i = 0, declarations_1 = declarations; _i < declarations_1.length; _i++) {
188 declaration = declarations_1[_i];
189 if (tsutils_1.isBindingElement(declaration)) {
190 declaration = tsutils_1.getDeclarationOfBindingElement(declaration);
192 if (tsutils_1.isVariableDeclaration(declaration)) {
193 declaration = declaration.parent;
195 if (tsutils_1.isVariableDeclarationList(declaration)) {
196 declaration = declaration.parent;
198 var result = getDeprecationFromDeclaration(declaration);
199 if (result !== undefined) {
205 function getDeprecationFromDeclaration(declaration) {
206 for (var _i = 0, _a = tsutils_1.getJsDoc(declaration); _i < _a.length; _i++) {
207 var comment = _a[_i];
208 if (comment.tags === undefined) {
211 for (var _b = 0, _c = comment.tags; _b < _c.length; _b++) {
213 if (tag.tagName.text === "deprecated") {
214 return tag.comment === undefined ? "" : tag.comment;
220 function isFunctionOrMethod(declarations) {
221 if (declarations === undefined || declarations.length === 0) {
224 switch (declarations[0].kind) {
225 case ts.SyntaxKind.MethodDeclaration:
226 case ts.SyntaxKind.FunctionDeclaration:
227 case ts.SyntaxKind.FunctionExpression:
228 case ts.SyntaxKind.MethodSignature:
234 var templateObject_1;