diff --git a/source/rules/no-deprecated.ts b/source/rules/no-deprecated.ts index 4cc9397..2c0ac33 100644 --- a/source/rules/no-deprecated.ts +++ b/source/rules/no-deprecated.ts @@ -7,7 +7,7 @@ import { TSESTree as es } from "@typescript-eslint/experimental-utils"; import { getParent, getParserServices } from "eslint-etc"; import * as ts from "typescript"; import { findTaggedNames } from "../tag"; -import { getTag, isDeclaration } from "../tslint-tag"; +import { getTags, isDeclaration } from "../tslint-tag"; import { ruleCreator } from "../utils"; const deprecatedNamesByProgram = new WeakMap>(); @@ -92,16 +92,18 @@ const rule = ruleCreator({ ) { return; } - const tag = getTag("deprecated", identifier, typeChecker); - if (tag !== undefined) { - context.report({ - data: { - comment: tag.trim().replace(/[\n\r\s\t]+/g, " "), - name: identifier.text, - }, - messageId: "forbidden", - node, - }); + const tags = getTags("deprecated", identifier, typeChecker); + if (tags.length > 0) { + for (const tag of tags) { + context.report({ + data: { + comment: tag.trim().replace(/[\n\r\s\t]+/g, " "), + name: identifier.text, + }, + messageId: "forbidden", + node, + }); + } } }, }; diff --git a/source/rules/no-internal.ts b/source/rules/no-internal.ts index d029407..26f30ab 100644 --- a/source/rules/no-internal.ts +++ b/source/rules/no-internal.ts @@ -7,7 +7,7 @@ import { TSESTree as es } from "@typescript-eslint/experimental-utils"; import { getParent, getParserServices } from "eslint-etc"; import * as ts from "typescript"; import { findTaggedNames } from "../tag"; -import { getTag, isDeclaration } from "../tslint-tag"; +import { getTags, isDeclaration } from "../tslint-tag"; import { ruleCreator } from "../utils"; // https://api-extractor.com/pages/tsdoc/tag_internal/ @@ -94,13 +94,18 @@ const rule = ruleCreator({ ) { return; } - const comment = getTag("internal", identifier, typeChecker); - if (comment !== undefined) { - context.report({ - data: { comment, name: identifier.text }, - messageId: "forbidden", - node, - }); + const tags = getTags("internal", identifier, typeChecker); + if (tags.length > 0) { + for (const tag of tags) { + context.report({ + data: { + comment: tag.trim().replace(/[\n\r\s\t]+/g, " "), + name: identifier.text, + }, + messageId: "forbidden", + node, + }); + } } }, }; diff --git a/source/tslint-tag.ts b/source/tslint-tag.ts index 63a06c2..84d27c8 100644 --- a/source/tslint-tag.ts +++ b/source/tslint-tag.ts @@ -77,18 +77,18 @@ function getCallExpresion( : undefined; } -export function getTag( +export function getTags( tagName: string, node: ts.Identifier, tc: ts.TypeChecker -): string | undefined { +): string[] { const callExpression = getCallExpresion(node); if (callExpression !== undefined) { - const result = getSignatureTag( + const result = getSignatureTags( tagName, tc.getResolvedSignature(callExpression) ); - if (result !== undefined) { + if (result.length > 0) { return result; } } @@ -119,51 +119,49 @@ export function getTag( // stop here to avoid collecting JsDoc of all overload signatures (callExpression !== undefined && isFunctionOrMethod(symbol.declarations)) ) { - return undefined; + return []; } - return getSymbolTag(tagName, symbol); + return getSymbolTags(tagName, symbol); } -function findTag(tagName: string, tags: ts.JSDocTagInfo[]): string | undefined { +function findTags(tagName: string, tags: ts.JSDocTagInfo[]): string[] { + const result: string[] = []; for (const tag of tags) { if (tag.name === tagName) { - return tag.text === undefined ? "" : tag.text; + result.push(tag.text === undefined ? "" : tag.text); } } - return undefined; + return result; } -function getSymbolTag(tagName: string, symbol: ts.Symbol): string | undefined { +function getSymbolTags(tagName: string, symbol: ts.Symbol): string[] { if (symbol.getJsDocTags !== undefined) { - return findTag(tagName, symbol.getJsDocTags()); + return findTags(tagName, symbol.getJsDocTags()); } // for compatibility with typescript@<2.3.0 - return getDeprecationFromDeclarations(tagName, symbol.declarations); + return getDeprecationsFromDeclarations(tagName, symbol.declarations); } -function getSignatureTag( - tagName: string, - signature?: ts.Signature -): string | undefined { +function getSignatureTags(tagName: string, signature?: ts.Signature): string[] { if (signature === undefined) { - return undefined; + return []; } if (signature.getJsDocTags !== undefined) { - return findTag(tagName, signature.getJsDocTags()); + return findTags(tagName, signature.getJsDocTags()); } // for compatibility with typescript@<2.3.0 return signature.declaration === undefined - ? undefined - : getDeprecationFromDeclaration(tagName, signature.declaration); + ? [] + : getDeprecationsFromDeclaration(tagName, signature.declaration); } -function getDeprecationFromDeclarations( +function getDeprecationsFromDeclarations( tagName: string, declarations?: ts.Declaration[] -): string | undefined { +): string[] { if (declarations === undefined) { - return undefined; + return []; } let declaration: ts.Node; for (declaration of declarations) { @@ -176,29 +174,31 @@ function getDeprecationFromDeclarations( if (tsutils.isVariableDeclarationList(declaration)) { declaration = declaration.parent; } - const result = getDeprecationFromDeclaration(tagName, declaration); - if (result !== undefined) { + const result = getDeprecationsFromDeclaration(tagName, declaration); + if (result.length > 0) { return result; } } - return undefined; + return []; } -function getDeprecationFromDeclaration( +function getDeprecationsFromDeclaration( tagName: string, declaration: ts.Node -): string | undefined { +): string[] { + const result: string[] = []; for (const comment of tsutils.getJsDoc(declaration)) { if (comment.tags === undefined) { continue; } + console.log(comment.tags); for (const tag of comment.tags) { if (tag.tagName.text === tagName) { - return tag.comment === undefined ? "" : tag.comment; + result.push(tag.comment === undefined ? "" : tag.comment); } } } - return undefined; + return result; } function isFunctionOrMethod(declarations?: ts.Declaration[]) { diff --git a/tests/rules/no-deprecated.ts b/tests/rules/no-deprecated.ts index e9f1328..903dfdb 100644 --- a/tests/rules/no-deprecated.ts +++ b/tests/rules/no-deprecated.ts @@ -349,5 +349,18 @@ ruleTester({ comments: true, types: true }).run("no-deprecated", rule, { ~~~~ [forbidden { "comment": "Don't use this function", "name": "func" }] ` ), + fromFixture( + stripIndent` + // Multiple deprecated tags + /** + * @deprecated This function is slow + * @deprecated This function is buggy + */ + declare function func(): void; + func(); + ~~~~ [forbidden { "comment": "This function is slow", "name": "func" }] + ~~~~ [forbidden { "comment": "This function is buggy", "name": "func" }] + ` + ), ], }); diff --git a/tests/rules/no-internal.ts b/tests/rules/no-internal.ts index 3b04f9a..abaf5b9 100644 --- a/tests/rules/no-internal.ts +++ b/tests/rules/no-internal.ts @@ -325,5 +325,18 @@ ruleTester({ comments: true, types: true }).run("no-internal", rule, { ], } ), + fromFixture( + stripIndent` + // Multiple internal tags + /** + * @internal This function is internal + * @internal This function is experimental + */ + declare function func(): void; + func(); + ~~~~ [forbidden { "comment": "This function is internal", "name": "func" }] + ~~~~ [forbidden { "comment": "This function is experimental", "name": "func" }] + ` + ), ], });