Skip to content

Commit

Permalink
Add 'no-redundant-jsdoc' rule (palantir#2754)
Browse files Browse the repository at this point in the history
  • Loading branch information
andy-hanson authored and HyphnKnight committed Apr 9, 2018
1 parent b7da9ed commit b231d60
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/configs/all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ export const rules = {
"no-boolean-literal-compare": true,
"no-consecutive-blank-lines": true,
"no-parameter-properties": true,
"no-redundant-jsdoc": true,
"no-reference-import": true,
"no-unnecessary-callback-wrapper": true,
"no-unnecessary-initializer": true,
Expand Down
4 changes: 2 additions & 2 deletions src/language/formatter/formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ export interface FormatterConstructor {
export interface IFormatter {
/**
* Formats linter results
* @param {RuleFailure[]} failures Linter failures that were not fixed
* @param {RuleFailure[]} fixes Fixed linter failures. Available when the `--fix` argument is used on the command line
* @param failures Linter failures that were not fixed
* @param fixes Fixed linter failures. Available when the `--fix` argument is used on the command line
*/
format(failures: RuleFailure[], fixes?: RuleFailure[]): string;
}
132 changes: 132 additions & 0 deletions src/rules/noRedundantJsdocRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/**
* @license
* Copyright 2017 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.
*/

import { getJsDoc } from "tsutils";
import * as ts from "typescript";

import * as Lint from "../index";

export class Rule extends Lint.Rules.AbstractRule {
/* tslint:disable:object-literal-sort-keys */
public static metadata: Lint.IRuleMetadata = {
ruleName: "no-redundant-jsdoc",
description: "Forbids JSDoc which duplicates TypeScript functionality.",
optionsDescription: "Not configurable.",
options: null,
optionExamples: [true],
type: "style",
typescriptOnly: true,
};
/* tslint:enable:object-literal-sort-keys */

public static FAILURE_STRING_REDUNDANT_TYPE =
"Type annotation in JSDoc is redundant in TypeScript code.";
public static FAILURE_STRING_REDUNDANT_TAG(tagName: string): string {
return `JSDoc tag '@${tagName}' is redundant in TypeScript code.`;
}
public static FAILURE_STRING_NO_COMMENT(tagName: string): string {
return `'@${tagName}' is redundant in TypeScript code if it has no description.`;
}

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
return this.applyWithFunction(sourceFile, walk);
}
}

function walk(ctx: Lint.WalkContext<void>): void {
const { sourceFile } = ctx;
ts.forEachChild(sourceFile, function cb(node) {
for (const { tags } of getJsDoc(node, sourceFile)) {
if (tags !== undefined) {
for (const tag of tags) {
checkTag(tag);
}
}
}
ts.forEachChild(node, cb);
});

function checkTag(tag: ts.JSDocTag): void {
switch (tag.kind) {
case ts.SyntaxKind.JSDocTag:
if (redundantTags.has(tag.tagName.text)) {
ctx.addFailureAtNode(tag.tagName, Rule.FAILURE_STRING_REDUNDANT_TAG(tag.tagName.text));
}
break;

case ts.SyntaxKind.JSDocAugmentsTag:
// OK
break;

case ts.SyntaxKind.JSDocTemplateTag:
case ts.SyntaxKind.JSDocTypeTag:
case ts.SyntaxKind.JSDocTypedefTag:
case ts.SyntaxKind.JSDocPropertyTag:
// Always redundant
ctx.addFailureAtNode(tag.tagName, Rule.FAILURE_STRING_REDUNDANT_TAG(tag.tagName.text));
break;

case ts.SyntaxKind.JSDocReturnTag:
case ts.SyntaxKind.JSDocParameterTag: {
const { typeExpression, comment } = tag as ts.JSDocReturnTag | ts.JSDocParameterTag;
if (typeExpression !== undefined) {
ctx.addFailureAtNode(typeExpression, Rule.FAILURE_STRING_REDUNDANT_TYPE);
}
if (comment === "") {
// Redundant if no documentation
ctx.addFailureAtNode(tag.tagName, Rule.FAILURE_STRING_NO_COMMENT(tag.tagName.text));
}
break;
}

default:
throw new Error(`Unexpected tag kind: ${ts.SyntaxKind[tag.kind]}`);
}
}
}

const redundantTags = new Set([
"abstract",
"access",
"class",
"constant",
"constructs",
"default",
"enum",
"exports",
"function",
"global",
"implements",
"interface",
"instance",
"member",
"memberof",
"mixes",
"mixin",
"module",
"name",
"namespace",
"override",
"private",
"property",
"protected",
"public",
"readonly",
"requires",
"static",
"this",
]);
35 changes: 35 additions & 0 deletions test/rules/no-redundant-jsdoc/test.ts.lint
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/** @typedef {number} T */
~~~~~~~ [tag % ('typedef')]

/** @function */
~~~~~~~~ [tag % ('function')]
function f() {}

/** @type number */
~~~~ [tag % ('type')]
const x = 0;

/**
* @param {number} x Is a number
~~~~~~~~ [type]
* @param y
~~~~~ [param]
* @param {number} z
~~~~~ [param]
~~~~~~~~ [type]
* @returns {number}
~~~~~~~ [returns]
~~~~~~~~ [type]
*/
declare function g(x: number, y: number, z: number): number;

/**
* @param x Useful comment
* @returns Useful comment
*/
declare function h(x: number): number;

[tag]: JSDoc tag '@%s' is redundant in TypeScript code.
[type]: Type annotation in JSDoc is redundant in TypeScript code.
[param]: '@param' is redundant in TypeScript code if it has no description.
[returns]: '@returns' is redundant in TypeScript code if it has no description.
5 changes: 5 additions & 0 deletions test/rules/no-redundant-jsdoc/tslint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rules": {
"no-redundant-jsdoc": true
}
}
4 changes: 2 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1591,8 +1591,8 @@ tsutils@^2.12.1:
tslib "^1.7.1"

tsutils@^2.8.1:
version "2.8.1"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.8.1.tgz#3771404e7ca9f0bedf5d919a47a4b1890a68efff"
version "2.10.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.10.0.tgz#ae94511df2656eb06e4424056fba5c388887040c"
dependencies:
tslib "^1.7.1"

Expand Down

0 comments on commit b231d60

Please sign in to comment.